Обнаружение или предупреждение, если пользователь использует поддельное местоположение

Я заблокирую пользователя от использования моего приложения, если оно подделает местоположение. Поэтому я использую isFromMockProvider чтобы проверить, является ли местоположение фальшивым (см. Здесь ). Но isFromMockProvider() в некоторых случаях может возвращать false для поддельных мест.

 public void onLocationChanged(Location location) { textView.append("long:"+location.getLatitude()+" - lat:"+location.getLongitude()+" - isMock :"+location.isFromMockProvider() + "\n"); } 

Мое дело : я использую приложение Fake GPS location для подделки для местоположения, тогда я отключу фальшивое местоположение и перейду в свое приложение. Затем onLocationChanged возвращает фальшивое местоположение с isFromMockProvider() = false

Видеомагнитофон : https://www.youtube.com/watch?v=rWVvjOCaZiI (в этом видео мое текущее местоположение – 16,06, 108,21, подделка – 36,26,138,28). В последнем видео вы можете увидеть место 36,26, 138.28, но isFromMockProvider = false)

Есть ли способ определить, использует ли пользователь фальшивое местоположение в этом случае? Любая помощь или предложение были бы очень оценены.
Проект DEMO

Solutions Collecting From Web of "Обнаружение или предупреждение, если пользователь использует поддельное местоположение"

Ответы на этот вопрос SO и в меньшей степени ответы на этот вопрос SO, похоже, указывают на то, что вы страдаете от неудачной проблемы кэширования в FusedLocationApi, вызванной вызовом onLocationChanged с устаревшей меткой времени (таким образом игнорируя результат, поскольку он думает там Уже более новые данные).

Чтобы процитировать ответ Рено :

Если вы не изменились … чтобы новые точки доступа были обнаружены, я боюсь, вы получите только кэшированные местоположения. Если вы хотите, чтобы новые места использовали провайдер GPS.

Решение будет состоять в том, чтобы вместо этого позвонить из провайдера GPS следующим образом:

 LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); LocationListener locationListener = new MyLocationListener(); locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 10, locationListener); 

(Приведенный выше код приведен из более длинного примера здесь )

Рискуя реалистичным ответом

Я хотел бы дать ответ, который поможет разработчику понять аспект дизайна отношений с общественностью, рискуя критиковать. Честно говоря, нельзя писать большие приложения в вакууме компьютерной науки. Удовлетворение потребностей пользователей и их балансирование с безопасностью – одна из основных проблем в программном интерфейсе и поведенческом дизайне сегодня, особенно в мобильном пространстве.

С этой точки зрения, ваш вопрос: «Есть ли способ определить, использует ли пользователь фальшивое местоположение в этом случае?» Не может быть самым актуальным вопросом, с которым вы сталкиваетесь. Я не уклончива, задав этот другой вопрос, который может помочь вам больше, и я могу ответить хорошо: «Есть ли способ безопасно получить данные из геокоординатной прошивки устройства пользователя, чтобы его нельзя было подделать?»

Ответ на этот вопрос: «Нет».

Контракт клиента HTTP для Android

Он не является частью контракта клиент-сервер Android или его конкурентов, чтобы гарантировать информацию о местоположении устройства пользователя.

Практическая причина

На самом деле существует рыночная сила, которая, вероятно, будет настаивать на такой гарантии на неопределенный срок. Многие владельцы устройств (и ваши пользователи) хотят получить контроль над тем, знают ли люди свое истинное местоположение для конфиденциальности, а также из соображений безопасности дома и семьи.

Решение

Следующий вопрос, который вы можете задать себе как разработчик своего программного обеспечения, – «Как приложение или библиотека могут работать и обеспечивать потребности, которые я хочу заполнить определенным процентом сообщества пользователей, используя сегодняшнее (или завтрашнее) программное обеспечение для спуфинга местоположений? "

Если вы пишете программное обеспечение бизнес-аналитики или в вашей системе есть какой-то другой статистический аспект, вам нужен программный эквивалент баров ошибок. Если вы показываете статистику, то бары ошибок будут подходящей функцией графического отображения. Оценка процентной доли помехоустойчивости от населения пользователей потребует дальнейшего изучения.

Я использую этот метод в своих проектах, и он отлично работает до сих пор:

Для api <18

 //returns true if mock location enabled, false if not enabled. public static boolean isMockLocationOn(Context context) { if (Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION).equals("0")) return false; else return true; } 

Для api> = 18 вам следует использовать

 location.isFromMockProvider(); 

Дело в том, что location.isFromMockProvider неисправен, и иногда он будет показывать насмешливое местоположение, как его ОК! Существует обходное решение в этой ссылке с полной детализацией. Местоположение на Android: Stop Mocking Me!

Подход:

  • Помните самое последнее место, обозначенное как макет

  • Если новое «не-фальшивое» чтение находится в пределах 1 км от последнего макета, отклоните его.

  • Очистите последнее последнее место после 20 последовательных «несовременных» показаний.

Я использую два способа идентификации поддельных мест.

Во-первых, я проверяю местоположение макета, как и в другом коде здесь.

 public static boolean isMockLocationOn(Location location, Context context) { if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { return location.isFromMockProvider(); } else { String mockLocation = "0"; try { mockLocation = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION); } catch (Exception e) { e.printStackTrace(); } return !mockLocation.equals("0"); } } 

Во-вторых, я проверяю запуск приложений и служб, которым требуется разрешение на доступ к локальному местоположению. И это работает хорошо.

 public static List<String> getListOfFakeLocationApps(Context context) { List<String> runningApps = getRunningApps(context, false); for (int i = runningApps.size() - 1; i >= 0; i--) { String app = runningApps.get(i); if(!hasAppPermission(context, app, "android.permission.ACCESS_MOCK_LOCATION")){ runningApps.remove(i); } } return runningApps; } public static List<String> getRunningApps(Context context, boolean includeSystem) { ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); List<String> runningApps = new ArrayList<>(); List<ActivityManager.RunningAppProcessInfo> runAppsList = activityManager.getRunningAppProcesses(); for (ActivityManager.RunningAppProcessInfo processInfo : runAppsList) { for (String pkg : processInfo.pkgList) { runningApps.add(pkg); } } try { //can throw securityException at api<18 (maybe need "android.permission.GET_TASKS") List<ActivityManager.RunningTaskInfo> runningTasks = activityManager.getRunningTasks(1000); for (ActivityManager.RunningTaskInfo taskInfo : runningTasks) { runningApps.add(taskInfo.topActivity.getPackageName()); } } catch (Exception ex) { ex.printStackTrace(); } List<ActivityManager.RunningServiceInfo> runningServices = activityManager.getRunningServices(1000); for (ActivityManager.RunningServiceInfo serviceInfo : runningServices) { runningApps.add(serviceInfo.service.getPackageName()); } runningApps = new ArrayList<>(new HashSet<>(runningApps)); if(!includeSystem){ for (int i = runningApps.size() - 1; i >= 0; i--) { String app = runningApps.get(i); if(isSystemPackage(context, app)){ runningApps.remove(i); } } } return runningApps; } public static boolean isSystemPackage(Context context, String app){ PackageManager packageManager = context.getPackageManager(); try { PackageInfo pkgInfo = packageManager.getPackageInfo(app, 0); return (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } return false; } public static boolean hasAppPermission(Context context, String app, String permission){ PackageManager packageManager = context.getPackageManager(); PackageInfo packageInfo; try { packageInfo = packageManager.getPackageInfo(app, PackageManager.GET_PERMISSIONS); if(packageInfo.requestedPermissions!= null){ for (String requestedPermission : packageInfo.requestedPermissions) { if (requestedPermission.equals(permission)) { return true; } } } } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } return false; }