Отключить / проверить на ложное местоположение (предотвратить спуфинг GPS) - PullRequest
80 голосов
/ 30 июля 2011

В поисках лучшего способа предотвращения / обнаружения спуфинга GPS на Android.Любые предложения о том, как это сделать, и что можно сделать, чтобы остановить это?Я предполагаю, что пользователь должен включить фиктивные местоположения, чтобы подделать GPS, если это будет сделано, то они могут подделать GPS?

Полагаю, мне нужно было бы просто определить, включены ли Mock Locations?Любые другие предложения?

Ответы [ 8 ]

114 голосов
/ 27 мая 2013

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

Сначала мы можем проверить, включена ли опция 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 (Location Spoofing Apps)

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

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

Теперь спуфинга можно избежать, используя API-интерфейс Location Manager.

Мы можем удалить провайдера тестов, прежде чем запрашивать обновления местоположения у обоих провайдеров (сети и 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);

Я видел, что removeTestProvider (~) очень хорошо работает над Jelly Bean и более поздними версиями. Этот API оказался ненадежным до Ice Cream Sandwich.

35 голосов
/ 11 января 2016

Начиная с API 18, объект Местоположение имеет метод .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");
}
35 голосов
/ 14 сентября 2011

Кажется, что единственный способ сделать это - предотвратить подмену местоположения, предотвращая MockLocations.С другой стороны, есть некоторые пользователи, которые используют Bluetooth 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;
23 голосов
/ 05 июня 2016

Наткнулся на эту ветку пару лет спустя. В 2016 году большинство устройств Android будут иметь уровень API> = 18 и, следовательно, должны полагаться на Location.isFromMockProvider () , на что указывает Фернандо .

Я много экспериментировал с поддельными / фиктивными местоположениями на разных устройствах Android и дистрибутивах. К сожалению, .isFromMockProvider () не является надежным на 100%. Время от времени поддельное местоположение не будет помечено как фиктивное . Похоже, это связано с ошибочной внутренней логикой слияния в Google Location API.

Я написал подробное сообщение в блоге об этом , если вы хотите узнать больше. Подводя итог, если вы подписываетесь на обновления местоположения из Location API, затем включаете поддельное приложение GPS и печатаете результат каждого Location.toString () на консоль, вы увидите что-то вроде этого:

enter image description here

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

Чтобы устранить эту проблему, я написал служебный класс, который будет надежно подавлять местоположения макетов во всех современных версиях Android (уровень API 15 и выше):

LocationAssistant - Беспроблемные обновления местоположения на Android

По сути, он "не доверяет" немодальным местоположениям, которые находятся в пределах 1 км от последнего известного местоположения макета, а также маркирует их как макет. Это происходит до тех пор, пока не появится значительное количество не фиктивных мест. 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) это в основном так.

Конечно, с рутованной ОС вы все еще можете найти способы подмены информации о местоположении, которые невозможно обнаружить обычным приложениям.

6 голосов
/ 02 июля 2012

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

Например, если ваше приложение разблокирует функции, только если пользователь находится в определенном месте (например, в вашем магазине), вы можете проверить gps, а также вышки сотовой связи. В настоящее время ни одно приложение gps-спуфинга также не подделывает вышки сотовой связи, поэтому вы можете увидеть, просто ли кто-то по всей стране пытается подделать ваши специальные функции (например, я имею в виду приложение Disney Mobile Magic).

Вот как приложение Llama по умолчанию управляет местоположением, поскольку проверка идентификаторов вышек сотовой связи требует гораздо меньше заряда батареи, чем GPS. Это бесполезно для очень специфических мест, но если дом и работа находятся на расстоянии нескольких миль, он может очень легко отличить два основных места.

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

3 голосов
/ 10 марта 2018

попробуйте этот код, он очень прост и полезен

  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;
    }
2 голосов
/ 07 июня 2017

Этот скрипт работает для всех версий Android, и я нахожу его после многих поиска

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
    }
1 голос
/ 21 февраля 2018

Вы можете добавить дополнительную проверку на основе триангуляции вышек сотовой связи или информации о точках доступа Wi-Fi, используя API геолокации Карт Google

Самый простой способ получить информацию о 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();

Вы можете сравнить свои результаты с сайтом

Чтобы получить информацию о точках доступа 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();
}
...