[android] 모의 위치 비활성화 / 확인 (gps 스푸핑 방지)

Android에서 GPS 스푸핑을 방지 / 감지하는 가장 좋은 방법을 찾고 있습니다. 이 작업을 수행하는 방법에 대한 제안 사항과이를 중지하기 위해 무엇을 할 수 있습니까? 사용자가 GPS를 스푸핑하기 위해 모의 위치를 ​​켜야한다고 생각하는데, 이것이 완료되면 GPS를 스푸핑 할 수 있습니까?

모의 위치가 활성화되어 있는지 감지해야할까요? 다른 제안이 있습니까?



답변

여기에서 조사를하고 결과를 공유했습니다. 이것은 다른 사람들에게 유용 할 수 있습니다.

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

위의 방법 (첫 번째와 두 번째 방법)이 모두 사실이면 위치가 스푸핑되거나 가짜 일 가능성이 높습니다.

이제 위치 관리자의 API를 사용하여 스푸핑을 방지 할 수 있습니다.

공급자 (네트워크 및 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까지 신뢰할 수없는 것처럼 보였습니다.


답변

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


답변

이를 수행하는 유일한 방법은 위치 스푸핑이 MockLocation을 방지하는 것을 방지하는 것 같습니다. 단점은 더 나은 신호를 얻기 위해 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;


답변

몇 년 후이 스레드를 우연히 발견했습니다. 2016 년에 대부분의 Android 기기는 API 레벨이 18 보다 크므로 Fernando가 지적한대로 Location.isFromMockProvider () 에 의존해야합니다 .

다양한 Android 기기 및 배포판에서 가짜 / 모의 위치를 ​​광범위하게 실험했습니다. 불행히도 .isFromMockProvider () 는 100 % 신뢰할 수 없습니다. 가끔 가짜 위치는 mock로 표시되지 않습니다 . 이는 Google Location API의 잘못된 내부 융합 논리 때문인 것 같습니다.

자세한 내용 을 알고 싶다면 이에 대한 자세한 블로그 게시물을 작성했습니다 . 요약하면 Location API에서 위치 업데이트를 구독 한 다음 가짜 GPS 앱을 켜고 각 Location.toString () 의 결과를 콘솔에 인쇄하면 다음과 같은 내용이 표시됩니다.

여기에 이미지 설명 입력

위치 업데이트 스트림에서 한 위치가 다른 위치와 동일한 좌표를 가지지 만 모의로 플래그가 지정되지 않고 위치 정확도가 훨씬 떨어지는 것을 확인하십시오.

이 문제를 해결하기 위해, 나는 유틸리티 클래스를 쓴 것이다 현대 안드로이드 버전 (최대 API 레벨 15)에 걸쳐 안정적으로 억제 모의 위치 :

LocationAssistant-Android에서 번거 로움없는 위치 업데이트

기본적으로 마지막으로 알려진 모의 위치에서 1km 이내에있는 모의가 아닌 위치를 “불신”하고이를 모의로 표시합니다. 모의가 아닌 많은 위치가 도착할 때까지이를 수행합니다. LocationAssistant은 모의 위치를 거부 할뿐만 아니라, 설정 및 위치 업데이트에 가입의 번거 로움의 대부분에서 당신을 unburdens 수 있습니다뿐만 아니라.

실제 위치 업데이트 만 수신하려면 (예 : 모의 억제) 다음과 같이 사용하십시오.

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 스푸핑을 방지하는 방법) 기본적으로 이것이 있습니다.

물론, 루팅 된 OS를 사용하면 일반 앱에서 감지 할 수없는 위치 정보를 스푸핑하는 방법을 찾을 수 있습니다.


답변

기지국의 일반적인 위치를 알게 된 경우 현재 기지국이 주어진 위치와 일치하는지 확인할 수 있습니다 (10 마일 이상과 같은 큰 오차 범위 내에서).

예를 들어 사용자가 특정 위치 (예 : 상점)에있는 경우에만 앱에서 기능을 잠금 해제하는 경우 GPS와 기지국을 확인할 수 있습니다. 현재는 GPS 스푸핑 앱이 기지국을 스푸핑하지 않으므로 전국의 누군가가 귀하의 특수 기능에 스푸핑을 시도하고 있는지 확인할 수 있습니다 (예를 들어 Disney Mobile Magic 앱을 생각하고 있습니다).

이것은 Llama 앱이 기본적으로 위치를 관리하는 방법입니다. 기지국 ID를 확인하는 것이 GPS보다 배터리 집약적이지 않기 때문입니다. 특정 위치에는 유용하지 않지만 집과 직장이 몇 마일 떨어져 있으면 두 일반 위치를 매우 쉽게 구분할 수 있습니다.

물론 이것은 사용자가 셀 신호를 가지고 있어야합니다. 그리고 모든 네트워크 제공 업체에서 해당 지역의 모든 셀 타워 ID를 알아야합니다. 그렇지 않으면 거짓 음성의 위험이 있습니다.


답변

이 코드는 매우 간단하고 유용합니다.

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


답변

이 스크립트는 모든 버전의 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
    }