禁用/检查模拟位置(防止GPS欺骗)
寻找在Android上防止/检测GPS欺骗的最佳方法。 有关如何完成的任何build议,以及可以做些什么来阻止它? 我猜测用户必须打开模拟位置来欺骗GPS,如果这样做,那么他们可以欺骗GPS?
我想我只需要检测是否启用了模拟位置? 还有其他build议吗?
我已经做了一些调查,并在这里分享我的结果,这可能对其他人有用。
首先,我们可以检查MockSetting选项是否打开
public static boolean isMockSettingsON(Context context) { // returns true if mock location enabled, false if not enabled. if (Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION).equals("0")) return false; else return true; }
其次,我们可以检查设备中是否有其他应用程序,这些应用程序正在使用android.permission.ACCESS_MOCK_LOCATION
(位置欺骗应用程序)
public static boolean areThereMockPermissionApps(Context context) { int count = 0; PackageManager pm = context.getPackageManager(); List<ApplicationInfo> packages = pm.getInstalledApplications(PackageManager.GET_META_DATA); for (ApplicationInfo applicationInfo : packages) { try { PackageInfo packageInfo = pm.getPackageInfo(applicationInfo.packageName, PackageManager.GET_PERMISSIONS); // Get Permissions String[] requestedPermissions = packageInfo.requestedPermissions; if (requestedPermissions != null) { for (int i = 0; i < requestedPermissions.length; i++) { if (requestedPermissions[i] .equals("android.permission.ACCESS_MOCK_LOCATION") && !applicationInfo.packageName.equals(context.getPackageName())) { count++; } } } } catch (NameNotFoundException e) { Log.e("Got exception " , e.getMessage()); } } if (count > 0) return true; return false; }
如果上述两种方法都是正确的,那么位置可能被欺骗或伪造的可能性很大。
现在,可以通过使用位置pipe理器的API来避免欺骗。
在请求提供者(networking和GPS)的位置更新之前,我们可以移除testing提供者,
LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE); try { Log.d(TAG ,"Removing Test providers") lm.removeTestProvider(LocationManager.GPS_PROVIDER); } catch (IllegalArgumentException error) { Log.d(TAG,"Got exception in removing test provider"); } lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, locationListener);
我已经看到,removeTestProvider(〜)比Jelly Bean和以后的版本工作得很好。 这个API似乎是不可靠的,直到冰淇淋三明治。
似乎唯一的方法是防止位置欺骗防止MockLocations。 不利的一面是有些用户使用蓝牙GPS设备获得更好的信号,他们将无法使用应用程序,因为他们需要使用模拟位置。
为此,我做了以下工作:
// returns true if mock location enabled, false if not enabled. if (Settings.Secure.getString(getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION).equals("0")) return false; else return true;
从API 18开始,对象Location具有.isFromMockProvider()方法,因此您可以过滤掉伪造的位置。
如果你想支持18之前的版本,可以使用这样的东西:
boolean isMock = false; if (android.os.Build.VERSION.SDK_INT >= 18) { isMock = location.isFromMockProvider(); } else { isMock = !Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION).equals("0"); }
几年后,偶然发现了这个问题。 在2016年,大多数Android设备的API级别大于等于18,因此应该像Fernando指出的那样依赖Location.isFromMockProvider() 。
我在不同的Android设备和发行版上广泛地尝试了假冒/模拟地点。 不幸的是.isFromMockProvider()不是100%可靠的。 每过一段时间, 一个虚假的位置就不会被标记为模拟 。 这似乎是由于Google Location API中一些错误的内部融合逻辑。
我写了一篇详细的博客文章 ,如果你想了解更多。 总而言之,如果您从Location API订阅位置更新,那么打开一个假的GPS应用程序并将每个Location.toString()的结果打印到控制台,您将看到如下所示的内容:
assets/content/stop_mocking_me_05.png
请注意,在位置更新stream中,一个位置与其他位置具有相同的坐标,但未被标记为模拟,并且定位精度较差。
为了解决这个问题,我写了一个实用工具类, 可以在所有现代Android版本(API级别15以上)中可靠地抑制模拟位置:
LocationAssistant – 在Android上无障碍位置更新
基本上,它是“不信任”在距离最近已知的模拟位置1km内的非模拟位置,并且将它们标记为模拟。 它会这样做,直到大量的非模拟地点到达。 LocationAssistant不仅可以拒绝模拟位置,还可以避免设置和订阅位置更新的麻烦。
要只接收真正的位置更新(即抑制模拟),请按如下所示使用它:
public class MyActivity extends Activity implements LocationAssistant.Listener { private LocationAssistant assistant; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... // You can specify a different accuracy and interval here. // The last parameter (allowMockLocations) must be 'false' to suppress mock locations. assistant = new LocationAssistant(this, this, LocationAssistant.Accuracy.HIGH, 5000, false); } @Override protected void onResume() { super.onResume(); assistant.start(); } @Override protected void onPause() { assistant.stop(); super.onPause(); } @Override public void onNewLocationAvailable(Location location) { // No mock locations arriving here } ... }
onNewLocationAvailable()
现在只会被调用真实的位置信息。 还有一些你需要实现的监听器方法,但在你的问题(如何防止GPS欺骗)的背景下,这基本上就是这样。
当然,使用根目录的操作系统,您仍然可以find欺骗性的位置信息的方法,而普通的应用程序无法检测到这些位置信息。
如果您碰巧知道手机信号塔的大致位置,则可以检查当前手机信号塔是否与给定的位置相匹配(在大于10英里的大的误差范围内)。
例如,如果您的应用仅在用户位于特定位置(例如您的商店)时解锁function,则可以检查gps以及手机信号塔。 目前,没有GPS欺骗应用程序也欺骗手机塔,所以你可以看到,如果全国有人只是试图欺骗他们的方式进入你的特殊function(例如,我想迪斯尼手机魔术应用程序,例如)。
这是默认情况下Llama应用程序pipe理位置的方式,因为检查手机信号塔ID比电池密度低得多。 这对于非常具体的地点是没有用的,但是如果家和工作距离几英里远,它可以非常容易地区分两个大的地点。
当然,这要求用户有一个单元信号。 而且,您必须知道该地区的所有networking基站(所有networking提供商),否则您将面临漏报的风险。
这个脚本是适用于所有版本的Android,我发现它后,许多search
LocationManager locMan; String[] mockProviders = {LocationManager.GPS_PROVIDER, LocationManager.NETWORK_PROVIDER}; try { locMan = (LocationManager) getSystemService(Context.LOCATION_SERVICE); for (String p : mockProviders) { if (p.contentEquals(LocationManager.GPS_PROVIDER)) locMan.addTestProvider(p, false, false, false, false, true, true, true, 1, android.hardware.SensorManager.SENSOR_STATUS_ACCURACY_HIGH); else locMan.addTestProvider(p, false, false, false, false, true, true, true, 1, android.hardware.SensorManager.SENSOR_STATUS_ACCURACY_LOW); locMan.setTestProviderEnabled(p, true); locMan.setTestProviderStatus(p, android.location.LocationProvider.AVAILABLE, Bundle.EMPTY, java.lang.System.currentTimeMillis()); } } catch (Exception ignored) { // here you should show dialog which is mean the mock location is not enable }