AndroidでGPSスプーフィングを防止/検出するための最良の方法を探しています。これがどのように達成されるか、そしてそれを止めるために何ができるかについての提案はありますか?GPSをスプーフィングするには、ユーザーがモックロケーションをオンにする必要があると思います。これを行うと、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;
}
上記の両方の方法(1番目と2番目)が当てはまる場合、その場所がなりすましまたは偽物である可能性が高くなります。
これで、Location Managerの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(〜)は、JellyBean以降のバージョンで非常にうまく機能することを確認しました。このAPIは、Ice CreamSandwichまで信頼できないようでした。
android.permission.ACCESS_MOCK_LOCATION
権限が必要ですremoveTestProvider
。これが最大の欠点だと思います。
isMockSettingsON()
、Location.isFromMockProvider()
そしてareThereMockPermissionApps()
アプリケーションのブラックリストを持ちます。ACCESS_MOCK_LOCATION
HTCやSamsungデバイスなど、許可を得たプリインストールされたシステムアプリがたくさんあります。すべての正当なアプリのホワイトリストの方が良いでしょうが、私の場合、最も人気のあるロケーションスプーフィングアプリのブラックリストがうまく機能しました。また、デバイスがルート化されているかどうかも確認しました。
API 18以降、オブジェクトLocationにはメソッド.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");
}
isMock = !Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION).equals("0");
これを行う唯一の方法は、ロケーションスプーフィングが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;
return !x
代わりに使用できますif(x) return false; else return true
。
数年後、このスレッドに出くわしました。2016年には、ほとんどのAndroidデバイスのAPIレベルが18以上になるため、Fernandoが指摘しているようにLocation.isFromMockProvider()に依存する必要があります。
私はさまざまなAndroidデバイスとディストリビューションで偽の/モックの場所を広範囲に実験しました。残念ながら、.isFromMockProvider()は100%信頼できるわけではありません。たまに、偽の場所がモックとしてラベル付けされないことがあります。これは、Google LocationAPIの誤った内部融合ロジックが原因のようです。
詳細を知りたい場合は、これについて詳細なブログ投稿を書きました。要約すると、Location APIから位置情報の更新をサブスクライブし、偽のGPSアプリをオンにして、各Location.toString()の結果をコンソールに出力すると、次のように表示されます。
場所の更新のストリームで、1つの場所が他の場所と同じ座標を持っているが、モックとしてフラグが付けられておらず、場所の精度がはるかに低いことに注意してください。
この問題を解決するには、私は、ユーティリティクラスを書いただろう確実にすべての現代のAndroidのバージョン(APIレベル15以上)を越えモック場所を抑制します:
LocationAssistant-Androidでの手間のかからない位置更新
基本的に、最後に認識されたモックロケーションから1 km以内にある非モックロケーションを「不信」にし、モックとしてラベル付けします。これは、モックではない場所がかなりの数到着するまで行われます。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アプリを考えています)。
これは、セルタワーIDのチェックがgpsよりもはるかにバッテリー消費が少ないため、Llamaアプリがデフォルトで場所を管理する方法です。非常に特定の場所には役立ちませんが、自宅と職場が数マイル離れている場合は、2つの一般的な場所を非常に簡単に区別できます。
もちろん、これにはユーザーがセル信号を持っている必要があります。また、エリア内のすべてのセルタワー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
}
セルタワーの三角測量またはWifiアクセスポイントの情報に基づいて、次のコマンドを使用してチェックを追加できます。 Google Maps Geolocation APIます
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();
あなたはあなたの結果をと比較することができます サイト
Wifiアクセスポイントに関する情報を取得するには
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();
}