目录介绍
- 前言
- 合规检查
- 检测隐私API方案
- 合规整改
- 合规解决方案-ASM插桩
- 什么是ASM
- ASM 插桩可以做什么?
- 最终效果
前言
从2020年开始,全球各大应用程序商店对应用程序安全隐私问题监管变的越来越严格,这说明应用的隐私合规安全问题愈加被重视,对 Android 平台的管控程度也要比 IOS 平台严格很多,很多不合规的应用也先后被下架要求整改。笔者就曾遇到过加班整改隐私合规的问题,隐私合规问题主要针对两个方面:
- 在用户同意隐私协议之前不能收集用户隐私数据,例如 IMEI、AndroidId、MAC 等
- 在用户同意隐私协议之后,收集用户数据行为在对应场景不能超频,比如一分钟不能超过 3 次获取 IMEI
那么从技术角度思考,有没有一劳永逸的办法,杜绝隐私调用不合规问题呢?
当然有!下面从合规检查,合规整改,合规解决方案ASM两方面来介绍来拆分隐私合规问题。
合规检查
检查这个操作主要针对于App发布和技术同学,App发布之前肯定需要系统性检查用户同意隐私协议之前有没有收集用户隐私数据的操作。
通过检查收集项目中(自有代码 + 三方 sdk)使用隐私合规相关 api 的相关代码。
目前市面已经有很多方案检测隐私API,下面介绍几种常见方案:
检测隐私API方案
- 方案1:Xposed
如果你对Xposed比较熟悉,并且手头有个root的设备安装了Xposed框架,那么直接开发一个Xposed模块来hook指定方法就可以了,缺点是需要root权限。
- 方案2:VirtualXposed
VirtualXposed 是基于VirtualApp 和 epic 在非ROOT环境下运行Xposed模块的实现(支持5.0~10.0)。
VirtualXposed其实就是一个支持Xposed的虚拟机,我们把开发好的Xposed模块和对应需要hook的App安装上去就能实现hook功能。 - 方案3:epic
如果不想折腾 Xposed 或者 VirtualXposed,只要在应用内接入epic,就可以实现应用内Xposed hook功能,满足运行hook需求。
epic 存在兼容性问题,例如Android 11 只支持64位App,所以建议只在debug环境使用。
当然我们推荐方案3,它可以拦截本进程内部几乎任意的 Java 方法调用,可用于实现 AOP 编程、运行时插桩、性能分析、安全审计等。
使用起来也非常简单:提前设置需要 hook 哪个 java 方,比如,我要 hook TelephonyManager 的 getDeviceId 方法:
//核心方法 DexposedBridge.findAndHookMethod(TelephonyManager.class, "getDeviceId", new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); String className = param.method.getDeclaringClass().getName(); String methodName = param.method.getName(); Log.i(PrivacyHelper.TAG, "检测到风险函数被调用: " + className + "#" + methodName); Log.d(PrivacyHelper.TAG, StackTraceUtils.getMethodStack()); } @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); Log.d(PrivacyHelper.TAG, "afterHookedMethod getDeviceId"); } });
在代码中如果有地方调用 TelephonyManager.getDeviceId 的,都会被 epic 的 beforeHookedMethod 给拦截到,只需要在 beforeHookedMethod 打印出堆栈即可看到是谁调用的。
既然我们知道了哪里有非法API调用,那么接下来看看如何整改。
合规整改
做过隐私合规的同学,想必都知道一些常见的合规操作:
- 用户在点击隐私政策协议“同意”按钮前,APP和SDK不能调用系统的敏感权限接口,特别是能获取IMEI、IMSI、MAC、IP、Android、已安装应用列表、硬件序列表、手机号码、位置等等信息的系统接口。
- 集成的第三方SDK建议升级到最新版本,用户在点击隐私政策协议“同意”按钮后,SDK再进行初始化。
- 在“同意”按钮上加入判定函数,当用户点击“同意”后,APP和SDK再执行调用系统接口的相关函数行为。
- 统一管理敏感信息采集入口,缓存敏感信息数据,可以设定缓存过期时间(建议设置超过5分钟)。获取android_id,缓存下来,下次调用先拿缓存,避免超频调用系统api。
但是特殊场景怎么办?那么我们有哪些特殊场景呢?
- 三方SDK断更了没法升级了,但是这个库又很重要,一时半会儿找不到好的合规库替代
- 三方SDK很重要,应用一启动等不了用户同意隐私政策就必须调用
- 三方SDK在调用某个敏感API,本地代码也调用同一个,这时候虽然本地代码做了缓存,尽可能的避免超频调用,但是三方SDK并不会读缓存,这样就有可能导致三方SDK本身没超频,本地代码本身也没有超频,但是两个都调用了而超频
很显然常见的合规操作并不足以解决特殊场景下的隐私合规。下面就要用到今天的主角ASM插桩。
合规解决方案-ASM插桩
什么是ASM
ASM 是一款通用的JAVA 平台字节码修改和分析框架。ASM 能够被用于直接在二进制层面修改现有的或生成新的class 文件。
ASM 插桩可以做什么?
- 编译阶段扫描修改代码,注意这里不管是本地代码还是三方SDK代码都可以修改,通过ASM插桩
可以达到在调用敏感API之前插入代码,记录运行时的方法调用链和当前时间。 - hook敏感API,替换字节码指令将调用链指向工具类从而统一管理敏感数据。这样既可以在未同意隐私协议之前,不调用相关API,又可以控制调用频率
最终效果
- 本地敏感调用
触发本地敏感调用
image.png
查看Logcat打印
image.png
查看编译后源码
image.png
- 模拟三方SDK敏感调用
原aar库敏感调用
image.png
触发三方SDK敏感调用
image.png
查看Logcat打印
image.png
查看编译后源码
可以看到不管是本地还是三方SDK敏感API调用,都在编译阶段被修改替换成了hook函数。
这样常见场景的隐私合规,特殊场景的隐私合规是不是都简单了?