隐私合规神器:从此告别隐私违规下架

你是否像我一样,有过这样的经历?因为三方SDK过度索取用户信息而造成APP被应用市场强制下架?当遇到这种问题的时候,你会怎么办呢?我想大部分用户可能会去找对应SDK的技术客服寻求解决办法,这可能是目前我们所能想到的最好的解决办法,或者是去掉那些不重要的SDK。

概述 


你是否像我一样,有过这样的经历?因为三方SDK过度索取用户信息而造成APP被应用市场强制下架?当遇到这种问题的时候,你会怎么办呢?我想大部分用户可能会去找对应SDK的技术客服寻求解决办法,这可能是目前我们所能想到的最好的解决办法,或者是去掉那些不重要的SDK。


然而,三方SDK的维护速度可能会让你崩溃,他们可能会排期处理,但是往往得好几天,甚至几十天,那么有没有一种方便、有效的办法去解决这个问题呢?

他号称可规避应用市场上架合规检测的大部分问题,我也在项目中采用了,目前来说,没有发现什么太大的问题,需要注意的一点是,你的项目AGP需要保持在8.0以下,如果不能的话,可能无法使用这个工具


一、如何使用 


    1. 在根目录的build.gralde下添加
	allprojects {
		repositories {
			...
			maven { url 'https://jitpack.io' }
		}
	}
	
	buildscript {
	     dependencies {
	         // 添加插件依赖
	         classpath 'com.github.allenymt.PrivacySentry:plugin-sentry:1.3.4.2'
	     }
	}
	
	allprojects {
        repositories {
            maven { url 'https://jitpack.io' }
        }
    }
    2. 在项目中的build.gralde下添加
        // 在主项目里添加插件依赖
        apply plugin: 'privacy-sentry-plugin'
        
        dependencies {
            // aar依赖
            def privacyVersion = "1.3.4.2"
            implementation "com.github.allenymt.PrivacySentry:hook-sentry:$privacyVersion"
            implementation "com.github.allenymt.PrivacySentry:privacy-annotation:$privacyVersion"

             // 代理类的库,如果自己没有代理类,那么必须引用这个aar!!
             // 如果不想使用库中本身的代理方法,可以不引入这个aar,但是自己必须实现代理类!!
             // 引入privacy-proxy,也可以自定义类代理方法,优先以业务方定义的为准
            implementation "com.github.allenymt.PrivacySentry:privacy-proxy:$privacyVersion"
            // 1.2.3 新增类替换,主要是为了hook构造函数的参数,按业务方需求自己决定
            implementation "com.github.allenymt.PrivacySentry:privacy-replace:$privacyVersion"
        }
        
        // 黑名单配置,可以设置这部分包名不会被修改字节码
        // 项目里如果有引入高德地图,先加黑 blackList = ["com.loc","com.amap.api"], asm的版本有冲突
        // 如果需要生成静态扫描文件, 默认名是replace.json
       privacy {
               // 设置免hook的名单
                blackList = []
                // 开关PrivacySentry插件功能,核心功能开关,默认为true
                enablePrivacy = true
            
                // 开启hook反射的方法,默认为false,按需打开
                hookReflex = false
                //  配置反射拦截 反射获取小米系统的oaid、aaid、vaid,例如极光、个推、穿山甲等SDK都有获取
                reflexMap = ["com.android.id.impl.IdProviderImpl":["getOAID","getAAID","getVAID"]]
            
                // 默认为false,按需打开
                hookConstructor = false
                // 默认为false,按需打开
                hookField = false
            
            
                //*************以下是分割线,主要是对Service的自启动优化处理,默认为false,按需打开****************
                // 处理Manifest文件,主要是处理Service的Priority , 关闭Service的Export
                enableProcessManifest = false
                // hook Service的部分代码,修复在MIUI上的自启动问题
                // 部分Service把自己的Priority设置为1000,这里开启代理功能,可以代理成0
                enableReplacePriority = false
                replacePriority = 1
            
                // 支持关闭Service的Export功能,默认为false,注意部分厂商通道之类的push(xiaomi、vivo、huawei等厂商的pushService),不能关闭
                enableCloseServiceExport = false
                // Export白名单Service
                serviceExportPkgWhiteList = ["white"]
                enableHookServiceStartCommand = false
        }
    初始化方法最好在attachBaseContext中第一个调用!!!(1.3.1开始不需要了,可以晚点初始化,不影响检测结果)
    完成功能的初始化
    PrivacySentryBuilder builder = new PrivacySentryBuilder()
                        // 自定义文件结果的输出名
                        .configResultFileName("buyer_privacy")
	`		//  debug打开,可以看到logcat的堆栈日志
			.syncDebug(true)
                        // 配置写入文件日志 , 线上包这个开关不要打开!!!!,true打开文件输入,false关闭文件输入
                        .enableFileResult(true)
                        // 持续写入文件30分钟
                        .configWatchTime(30 * 60 * 1000)
                        // 文件输出后的回调
                        .configResultCallBack(new PrivacyResultCallBack() {

                            @Override
                            public void onResultCallBack(@NonNull String s) {

                            }
                        });
    // 添加默认结果输出,包含log输出和文件输出
    PrivacySentry.Privacy.INSTANCE.init(application, builder);
    如果在日志中发现check!!! 还未展示隐私协议,Illegal print,说明此时还未同意隐私协议,调用了敏感或者违规的api
    所以在隐私协议确认的时候调用,这一步非常重要!,一定要加,这一步是告知SDK,APP已经同意隐私协议了
    kotlin:PrivacySentry.Privacy.updatePrivacyShow()
    java:PrivacySentry.Privacy.INSTANCE.updatePrivacyShow();
    支持自定义配置hook函数
    /**
 * @author yulun
 * @since 2022-01-13 17:57
 * 主要是两个注解PrivacyClassProxy和PrivacyMethodProxy,PrivacyClassProxy代表要解析的类,PrivacyMethodProxy代表要hook的方法配置
 */
@Keep
open class PrivacyProxyResolver {
     
    // kotlin里实际解析的是这个PrivacyProxyCall$Proxy 内部类
    @PrivacyClassProxy
    @Keep
    object Proxy {
 
        // 查询
        @SuppressLint("MissingPermission")
        @PrivacyMethodProxy(
            originalClass = ContentResolver::class,   // hook的方法所在的类名
            originalMethod = "query",   // hook的方法名
            originalOpcode = MethodInvokeOpcode.INVOKEVIRTUAL //hook的方法调用,一般是静态调用和实例调用
        )
        @JvmStatic
        fun query(
            contentResolver: ContentResolver?, //实例调用的方法需要把声明调用对象,我们默认把对象参数放在第一位
            uri: Uri,
            projection: Array<String?>?, selection: String?,
            selectionArgs: Array<String?>?, sortOrder: String?
        ): Cursor? {
            doFilePrinter("query", "查询服务: ${uriToLog(uri)}") // 输入日志到文件
            return contentResolver?.query(uri, projection, selection, selectionArgs, sortOrder)
        }
  
        @RequiresApi(Build.VERSION_CODES.O)
        @PrivacyMethodProxy(
            originalClass = android.os.Build::class,
            originalMethod = "getSerial",
            originalOpcode = MethodInvokeOpcode.INVOKESTATIC //静态调用
        )
        @JvmStatic
        fun getSerial(): String? {
            var result = ""
            try {
                doFilePrinter("getSerial", "读取Serial")
                if (PrivacySentry.Privacy.getBuilder()?.isVisitorModel() == true) {
                return ""
                }
            result = Build.getSerial()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        return result
        }
    }
}
    如何配置替换一个类
    可以参考源码中PrivacyFile的配置,使用PrivacyClassReplace注解,originClass代表你要替换的类,注意要继承originClass的所有构造函数
    可以配置 hookConstructor = false关闭这个功能
/**
 * @author yulun
 * @since 2022-11-18 15:01
 * 代理File的构造方法,如果是自定义的file类,需要业务方单独配置自行处理
 */
@PrivacyClassReplace(originClass = File.class)
public class PrivacyFile extends File {

    public PrivacyFile(@NonNull String pathname) {
        super(pathname);
        record(pathname);
    }

    public PrivacyFile(@Nullable String parent, @NonNull String child) {
        super(parent, child);
        record(parent + child);
    }

    public PrivacyFile(@Nullable File parent, @NonNull String child) {
        super(parent, child);
        record(parent.getPath() + child);
    }

    public PrivacyFile(@NonNull URI uri) {
        super(uri);
        record(uri.toString());
    }

    private void record(String path) {
        PrivacyProxyUtil.Util.INSTANCE.doFilePrinter("PrivacyFile", "访问文件", "path is " + path, PrivacySentry.Privacy.INSTANCE.getBuilder().isVisitorModel(), false);
    }
}

二、基本原理 

  • 编译期注解+hook方案,第一个transform收集需要拦截的敏感函数,第二个transform替换敏感函数,运行期收集日志
  • 为什么不用xposed等框架? 因为想做本地自动化定期排查,第三方hook框架外部依赖性太大
  • 为什么不搞基于lint的排查方式? 工信部对于运行期 敏感函数的调用时机和次数都有限制,代码扫描解决不了这些问题

三、支持的hook函数列表 

支持hook以下功能函数:

  • 支持敏感字段缓存(磁盘缓存、带有时间限制的磁盘缓存、内存缓存)

  • hook替换类 (构造函数)

  • 当前运行进程和任务

  • 系统剪贴板服务

  • 读取设备应用列表

  • 读取 Android SN(Serial,包括方法和变量),系统设备号

  • 读写联系人、日历、本机号码

  • 获取定位、基站信息、wifi信息

  • Mac 地址、IP 地址

  • 读取 IMEI(DeviceId)、MEID、IMSI、ADID(AndroidID)

  • 手机可用传感器,传感器注册,传感器列表

  • 权限请求

四、常见的合规字段整理 

IMEI、MAC地址、MEID、IMSI、SN、ICCID等设备唯一标识符,Android ID、WiFi(WiFi名称、WiFi MAC地址以及设备扫描到的所有WiFi信息),SIM卡信息(IMSI、SIM卡序列号ICCID、手机号、运营商信息),应用安装列表(设备所有已安装应用的包名和应用名),传感器(传感器列表、加速度传感器、温度传感器等),蓝牙信息(设备蓝牙地址和设备扫描到的蓝牙设备信息),基站定位、GPS(用户地理位置信息),账户(各类应用注册的不同账号信息)、剪切板、IP地址、硬件序列号、SDCard信息(公有目录)

五、总结 

这么简单?没错,就是这么简单,要不然怎么说他是神器呢?项目的地址在下面,感兴趣的可以在项目中尝试一下

希望大家能多多点赞,关注一下,不定期分享优秀的开源工具

项目地址:https://github.com/allenymt/PrivacySentry

往期内容 

商务合作:dxmcpjl

APP、小程序、官网、软件开发

扫码进群

来源: 互联网
本文观点不代表码客-全球程序员交流社区立场,不承担法律责任,文章及观点也不构成任何投资意见。

赞 ()

相关推荐

发表回复

评论列表

点击查看更多

    联系我们

    在线咨询: QQ交谈

    微信:dxmcpjl

    邮件:1529097251#qq.com

    工作时间:周一至周五,9:30-18:30,节假日休息

    微信