Detectar o impedir si el usuario utiliza una ubicación falsa

Bloquearé a un usuario de usar mi aplicación si falsifican la ubicación. Así que utilizo isFromMockProvider para comprobar si la ubicación es falsa (siga aquí ). Pero isFromMockProvider() puede devolver falso para ubicaciones falsas en algunos casos.

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

Mi caso es : Yo uso la aplicación Fake GPS para la ubicación falsa a una ubicación, a continuación, deshabilitar la ubicación falsa y vaya a mi aplicación. Entonces onLocationChanged devuelve la ubicación falsa con isFromMockProvider() = false

Video Recorder : https://www.youtube.com/watch?v=rWVvjOCaZiI (en este video, mi ubicación actual es 16.06, 108.21, la ubicación falsa es 36.26.138.28. Usted puede ver en el último video la ubicación es 36.26, 138.28 pero isFromMockProvider = false)

¿Hay alguna forma de detectar si un usuario utiliza una ubicación falsa en este caso? Cualquier ayuda o sugerencia sería muy apreciada.
Proyecto DEMO

Respuestas a esta pregunta SO y en menor medida las respuestas a esta pregunta SO parecen indicar que usted está sufriendo de un desafortunado problema de caché en el FusedLocationApi causado por onLocationChanged siendo llamado con una fecha de caducidad (ignorando así el resultado como piensa allí Es ya más reciente).

Para citar la respuesta de Reno :

A menos que no hayas cambiado … para que se descubran nuevos APs, me temo que solo tendrás ubicaciones en caché. Si desea ubicaciones nuevas, utilice el proveedor de GPS.

La solución será llamar a un lugar del proveedor de GPS de la siguiente manera:

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

(El código anterior proviene de un ejemplo más largo aquí )

Arriesgando una respuesta realista

Me gustaría proporcionar una respuesta que ayude al desarrollador a comprender el aspecto de relaciones públicas del diseño de productos, asumiendo el riesgo de ser criticado. Francamente, uno no puede escribir grandes aplicaciones en un vacío de la ciencia de la computación. Satisfacer las necesidades de los usuarios y equilibrarlos con la seguridad es uno de los principales problemas en la interfaz de software y el diseño de comportamiento hoy en día, especialmente en el espacio móvil.

Desde esta perspectiva, su pregunta, "¿Hay alguna forma de detectar si un usuario utiliza una ubicación falsa en este caso?" Puede no ser la pregunta más pertinente que usted enfrenta. No estoy siendo evasivo al hacer esta otra pregunta que puede ayudarte más y es algo que puedo responder bien: "¿Hay alguna forma de obtener de forma segura los datos del firmware geoordinado del dispositivo del usuario de manera que no pueda ser falsificado?"

La respuesta a esta pregunta es: "No."

Contrato de cliente HTTP de Android

No forma parte del contrato cliente-servidor de Android ni de sus competidores para garantizar la información de ubicación del dispositivo de usuario.

Razón práctica

En realidad, existe una fuerza de mercado que probablemente empujará indefinidamente esa garantía. Muchos propietarios de dispositivos (y sus usuarios) quieren controlar si las personas conocen su ubicación real por razones de privacidad y de seguridad doméstica y familiar.

Solución

La siguiente pregunta que puede hacerse a usted mismo como diseñador de su software es: "¿Cómo puede funcionar la aplicación o la biblioteca y satisfacer las necesidades que busco cubrir con un determinado porcentaje de la comunidad de usuarios utilizando el software de falsificación de ubicaciones de hoy (o mañana)? "

Si está escribiendo software de inteligencia de negocios o hay algún otro aspecto estadístico en su sistema, entonces necesita el equivalente de software de barras de error. Si muestra las estadísticas, las barras de error serían una característica gráfica apropiada. La estimación del porcentaje de spoofers de localización de una población de usuarios requeriría estudio adicional.

Yo uso este método en mis proyectos y funciona perfectamente hasta ahora:

Para 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; } 

Para api> = 18 debe usar

 location.isFromMockProvider(); 

El punto es location.isFromMockProvider es buggy y algunas veces se mostrará una ubicación de burla como su bien! Hay una solución en este enlace con todos los detalles Ubicación en Android: Stop Mocking Me!

El enfoque es:

  • Recuerde la ubicación más reciente etiquetada como un simulacro

  • Si una nueva lectura "no simulada" está dentro de 1km de la última burla, rechácela.

  • Solamente borre la última ubicación simulada después de 20 lecturas consecutivas "no simulada".

Utilizo dos maneras de identificar ubicaciones falsas.

Primero, compruebo la localización simulada, como en el otro código aquí.

 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"); } } 

En segundo lugar, compruebo las aplicaciones y servicios en ejecución, que necesitan permiso para acceder a la ubicación falsa. Y parece funcionar bien.

 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; } 
  • No ver Geofence Transitions en el tutorial de Google sobre Geofencing
  • Cómo publicar datos utilizando el método POST en Android
  • Problemas de permiso para la ubicación en android Marshmallow applicaton
  • Intervalo requestLocationUpdates en Android
  • Donde el archivo .apk se coloca en el teléfono después de la instalación
  • Cómo obtener la ubicación GPS de Android
  • Cómo animar un marcador a través de un ArrayList de LatLng puntos?
  • Buena forma de obtener la ubicación del usuario en Android
  • Recibir una notificación (vía BroadcastReceiver) cuando se inicia / detiene el GPS (o servicios de ubicación)
  • Creación de un objeto Ubicación en Android con valores de latitud y longitud
  • RequestLocationUpdates no se actualiza en intervalos en Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.