Szukam najlepszego sposobu zapobiegania fałszowaniu danych GPS na urządzeniach z Androidem / wykrywania takich przypadków. Jakieś sugestie, jak to osiągnąć i co można zrobić, aby temu zapobiec? Zgaduję, że użytkownik musi włączyć pozorowane lokalizacje, aby sfałszować GPS, jeśli tak się stanie, to może sfałszować GPS?
Myślę, że musiałbym po prostu wykryć, czy Mock Locations są włączone? Jakieś inne sugestie?
Odpowiedzi:
Przeprowadziłem pewne dochodzenie i udostępniłem tutaj swoje wyniki, może to być przydatne dla innych.
Najpierw możemy sprawdzić, czy opcja MockSetting jest włączona
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; }
Po drugie, możemy sprawdzić, czy na urządzeniu są inne aplikacje, które używają
android.permission.ACCESS_MOCK_LOCATION
(Aplikacje do fałszowania lokalizacji)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; }
Jeśli obie powyższe metody, pierwsza i druga, są prawdziwe, istnieje duże prawdopodobieństwo, że lokalizacja może być sfałszowana lub fałszywa.
Teraz można uniknąć podszywania się za pomocą interfejsu API Location Manager.
Możemy usunąć dostawcę testów przed zażądaniem aktualizacji lokalizacji od obu dostawców (sieć i GPS)
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);
Widziałem, że removeTestProvider (~) działa bardzo dobrze w stosunku do Jelly Bean i nowszych wersji. To API wydawało się niewiarygodne aż do Ice Cream Sandwich.
źródło
android.permission.ACCESS_MOCK_LOCATION
pozwolenie naremoveTestProvider
działanie, co moim zdaniem jest największą wadą.isMockSettingsON()
,Location.isFromMockProvider()
aareThereMockPermissionApps()
czarną listę aplikacji. Istnieje wiele preinstalowanych aplikacji systemowych zACCESS_MOCK_LOCATION
zezwoleniem, na przykład na urządzeniach HTC i Samsung. Biała lista wszystkich legalnych aplikacji byłaby lepsza, ale w moim przypadku dobrze działała czarna lista najpopularniejszych aplikacji do fałszowania lokalizacji. Sprawdziłem też, czy urządzenie jest zrootowane.Od API 18 obiekt Location ma metodę .isFromMockProvider (), dzięki czemu można odfiltrować fałszywe lokalizacje.
Jeśli chcesz wspierać wersje starsze niż 18, możesz użyć czegoś takiego:
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"); }
źródło
isMock = !Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION).equals("0");
Wygląda na to, że jedynym sposobem na to jest zapobieganie fałszowaniu lokalizacji przed MockLocations. Wadą jest to, że niektórzy użytkownicy używają urządzeń GPS Bluetooth, aby uzyskać lepszy sygnał, nie będą mogli korzystać z aplikacji, ponieważ są zobowiązani do korzystania z pozorowanych lokalizacji.
Aby to zrobić, wykonałem następujące czynności:
// 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;
źródło
return !x
zamiastif(x) return false; else return true
.Natknąłem się na ten wątek kilka lat później. W 2016 r. Większość urządzeń z Androidem będzie miała poziom API> = 18 i dlatego powinno polegać na Location.isFromMockProvider (), jak wskazał Fernando .
Intensywnie eksperymentowałem z fałszywymi / pozorowanymi lokalizacjami na różnych urządzeniach z Androidem i dystrybucjach. Niestety .isFromMockProvider () nie jest w 100% wiarygodne. Od czasu do czasu fałszywa lokalizacja nie będzie oznaczona jako pozorna . Wydaje się, że jest to spowodowane błędną wewnętrzną logiką fuzji w Google Location API.
Napisałem na ten temat szczegółowy post na blogu , jeśli chcesz dowiedzieć się więcej. Podsumowując, jeśli subskrybujesz aktualizacje lokalizacji z interfejsu API lokalizacji, a następnie włączasz fałszywą aplikację GPS i drukujesz wynik każdego Location.toString () na konsoli, zobaczysz coś takiego:
Zwróć uwagę, że w strumieniu aktualizacji lokalizacji jedna lokalizacja ma te same współrzędne co inne, ale nie jest oznaczona jako pozorna i ma znacznie gorszą dokładność lokalizacji.
Aby rozwiązać ten problem, napisałem klasę narzędzi, która niezawodnie blokuje lokalizacje Mock we wszystkich nowoczesnych wersjach Androida (poziom API 15 i nowsze):
LocationAssistant - Bezproblemowe aktualizacje lokalizacji na Androida
Zasadniczo „nie ufa” niezamierzonym lokalizacjom, które znajdują się w promieniu 1 km od ostatniej znanej pozorowanej lokalizacji, a także określa je jako pozorowane. Robi to, dopóki nie pojawi się znaczna liczba nieudanych lokalizacji. LocationAssistant można nie tylko odrzucić pozorowanie lokalizacji, ale także odciąża cię z większości kłopotów konfigurowania i subskrypcji aktualizacji lokalizacji.
Aby otrzymywać tylko prawdziwe aktualizacje lokalizacji (tj. Pomijać fałszywe informacje), użyj ich w następujący sposób:
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()
będą teraz wywoływane tylko z prawdziwymi informacjami o lokalizacji. Jest jeszcze kilka metod nasłuchujących, które musisz wdrożyć, ale w kontekście twojego pytania (jak zapobiegać fałszowaniu GPS) to w zasadzie wszystko.Oczywiście w przypadku zrootowanego systemu operacyjnego nadal można znaleźć sposoby fałszowania informacji o lokalizacji, których normalne aplikacje nie mogą wykryć.
źródło
Jeśli zdarzyło Ci się znać ogólną lokalizację wież komórkowych, możesz sprawdzić, czy bieżąca wieża komórkowa pasuje do podanej lokalizacji (z marginesem błędu czegoś dużego, na przykład 10 lub więcej mil).
Na przykład, jeśli Twoja aplikacja odblokowuje funkcje tylko wtedy, gdy użytkownik znajduje się w określonej lokalizacji (na przykład w Twoim sklepie), możesz sprawdzić GPS, a także wieże komórkowe. Obecnie żadna aplikacja do fałszowania GPS nie fałszuje również wież komórkowych, więc możesz zobaczyć, czy ktoś w całym kraju po prostu próbuje sfałszować swoje specjalne funkcje (mam na myśli aplikację Disney Mobile Magic, na przykład).
W ten sposób aplikacja Lama domyślnie zarządza lokalizacją, ponieważ sprawdzanie identyfikatorów wież komórkowych jest znacznie mniej energochłonne niż GPS. Nie jest to przydatne w przypadku bardzo konkretnych lokalizacji, ale jeśli dom i praca są oddalone o kilka mil, można bardzo łatwo rozróżnić te dwie główne lokalizacje.
Oczywiście wymagałoby to od użytkownika w ogóle posiadania sygnału komórkowego. I musiałbyś znać wszystkie identyfikatory wież komórkowych w okolicy - u wszystkich dostawców sieci - w przeciwnym razie ryzykowałbyś fałszywie ujemnym.
źródło
wypróbuj ten kod, jest bardzo prosty i przydatny
public boolean isMockLocationEnabled() { boolean isMockLocation = false; try { //if marshmallow if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { AppOpsManager opsManager = (AppOpsManager) getApplicationContext().getSystemService(Context.APP_OPS_SERVICE); isMockLocation = (opsManager.checkOp(AppOpsManager.OPSTR_MOCK_LOCATION, android.os.Process.myUid(), BuildConfig.APPLICATION_ID)== AppOpsManager.MODE_ALLOWED); } else { // in marshmallow this will always return true isMockLocation = !android.provider.Settings.Secure.getString(getApplicationContext().getContentResolver(), "mock_location").equals("0"); } } catch (Exception e) { return isMockLocation; } return isMockLocation; }
źródło
Ten skrypt działa dla wszystkich wersji Androida i znajduję go po wielu poszukiwaniach
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 }
źródło
Możesz dodać dodatkowe sprawdzenie w oparciu o triangulację wieży komórkowej lub informacje o punktach dostępu Wi-Fi za pomocą interfejsu API geolokalizacji Map Google
Najprostszy sposób na uzyskanie informacji o CellTowers
final TelephonyManager telephonyManager = (TelephonyManager) appContext.getSystemService(Context.TELEPHONY_SERVICE); String networkOperator = telephonyManager.getNetworkOperator(); int mcc = Integer.parseInt(networkOperator.substring(0, 3)); int mnc = Integer.parseInt(networkOperator.substring(3)); String operatorName = telephonyManager.getNetworkOperatorName(); final GsmCellLocation cellLocation = (GsmCellLocation) telephonyManager.getCellLocation(); int cid = cellLocation.getCid(); int lac = cellLocation.getLac();
Możesz porównać swoje wyniki z witryną
Aby uzyskać informacje o punktach dostępu Wi-Fi
final WifiManager mWifiManager = (WifiManager) appContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE); if (mWifiManager != null && mWifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED) { // register WiFi scan results receiver IntentFilter filter = new IntentFilter(); filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { List<ScanResult> results = mWifiManager.getScanResults();//<-result list } }; appContext.registerReceiver(broadcastReceiver, filter); // start WiFi Scan mWifiManager.startScan(); }
źródło