检测或阻止用户是否使用虚假位置

Pha*_*inh 15 gps android location google-api-client

如果用户伪造该位置,我将阻止用户使用我的应用.所以我isFromMockProvider用来检查位置是否是假的(按照这里).但isFromMockProvider()在某些情况下可能会为伪造的位置返回false.

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

我的情况是:我使用假冒伪劣GPS定位到一个位置然后我禁用虚假位置并转到我的应用程序.然后onLocationChanged返回假位置isFromMockProvider() = false

录像机:https://www.youtube.com/watch?v = rWVvjOCaZiI(在此视频中,我目前的位置是16.06,108.21,假位置是36.26,138.28.你可以在上一个视频中看到位置是36.26, 138.28但isFromMockProvider = false)

有没有办法检测用户在这种情况下是否使用虚假位置?任何帮助或建议将非常感谢.
DEMO项目

Fau*_*ian 13

冒着现实的答案

我想提供一个答案,帮助开发人员理解产品设计的公共关系方面,冒着批评的风险.坦率地说,人们无法在计算机科学真空中编写出色的应用程序.满足用户需求并使其与安全性保持平衡是当今软件界面和行为设计的主要问题之一,尤其是在移动领域.

从这个角度来看,您的问题是"在这种情况下,有没有办法检测用户是否使用假位置?" 可能不是你面临的最相关的问题.我不会回答这个问题可能会对你有所帮助,而且我可以很好地回答:"有没有办法安全地从用户设备的地理坐标固件中获取数据,这样就不会被欺骗?"

这个的答案是,"不."

Android HTTP客户端合同

它不是Android客户端 - 服务器合同的一部分,也不是其竞争对手的合同,以保证用户设备位置信息.

实际原因

事实上,市场力量可能会无限期地推动这种担保.许多设备所有者(以及您的用户)希望控制人们是否知道他们的真实位置是出于隐私以及家庭和家庭安全的原因.

您可以问自己作为软件设计者的下一个问题是,"应用程序或库如何工作并满足我使用当今(或明天)位置欺骗软件填充一定比例的用户社区的需求? "

如果您正在编写商业智能软件或您的系统还有其他一些统计方面,那么您需要相当于错误栏的软件.如果显示统计数据,则误差线将是适当的图形功能.估计用户群中位置欺骗者的百分比需要进一步研究.


Joh*_*ohn 13

我用两种方法来识别假位置.

首先,我检查模拟位置,就像这里的其他代码一样.

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

其次,我检查运行的应用程序和服务,它们需要访问模拟位置的权限.它似乎运作良好.

public static List<String> getListOfFakeLocationApps(Context context) {
    List<String> runningApps = getRunningApps(context);
    List<String> fakeApps = new ArrayList<>();
    for (String app : runningApps) {
        if(!isSystemPackage(context, app) && hasAppPermission(context, app, "android.permission.ACCESS_MOCK_LOCATION")){
            fakeApps.add(getApplicationName(context, app));
        }
    }
    return fakeApps;
}

public static List<String> getRunningApps(Context context, boolean includeSystem) {
    ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    HashSet<String> runningApps = new HashSet<>();
    try {
        List<ActivityManager.RunningAppProcessInfo> runAppsList = activityManager.getRunningAppProcesses();
        for (ActivityManager.RunningAppProcessInfo processInfo : runAppsList) {
            runningApps.addAll(Arrays.asList(processInfo.pkgList));
        }
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    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();
    }
    try {
        List<ActivityManager.RunningServiceInfo> runningServices = activityManager.getRunningServices(1000);
        for (ActivityManager.RunningServiceInfo serviceInfo : runningServices) {
            runningApps.add(serviceInfo.service.getPackageName());
        }
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return new ArrayList<>(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;
}

public static String getApplicationName(Context context, String packageName) {
    String appName = packageName;
    PackageManager packageManager = context.getPackageManager();
    try {
        appName = packageManager.getApplicationLabel(packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA)).toString();
    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
    }
    return appName;
}
Run Code Online (Sandbox Code Playgroud)


Nic*_*oso 5

关于这个 SO 问题的答案以及在较小程度上这个 SO 问题的答案似乎表明您在 FusedLocationApi 中遇到了不幸的缓存问题,原因是 onLocationChanged 被调用时带有过时的时间戳(因此忽略了它认为的结果)已经是较新的数据)。

引用Reno 的回答

除非你没有改变......以便可以发现新的AP,恐怕你只会得到缓存的位置。如果您想要新的位置,请使用 GPS 提供商。

解决方案是改为从GPS 提供商调用位置,如下所示:

LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
LocationListener locationListener = new MyLocationListener();
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 10, locationListener);
Run Code Online (Sandbox Code Playgroud)

(上面的代码来自这里的一个更长的例子)


归档时间:

查看次数:

28741 次

最近记录:

6 年 前