文章目录

  • 背景
  • 技术目标
  • 技术方案
  • 技术实践
    • 技术流程
    • 自定义 lint 规则
  • 总结

背景

辛辛苦苦迭代完当前版本,准备推送 App 到应用市场上架,却收到拒审通知:App隐私合规上架护航版检测报告

报告内容:

场景2:APP以隐私政策弹窗的形式向用户明示收集使用规则,未经用户同意,存在收集设备MAC地址、IMEI等信息的行为。
检测结果: 存在问题
改进建议: (1)在APP首次运行或用户注册时以弹窗、突出链接等明显方式主动提示用户阅读隐私政策; (2)在用户点击同意隐私政策之前,不应提前收集IMEI、设备MAC地址和软件安装列表等信息,以及不应提前向用户申请手机、通讯、短信等敏感权限。

这真是晴天霹雳!!!此时,老板又让你半天时间解决。那么,该如何去排查这个问题呢?

遇到上面这种问题,第一时间,可能想到解决思路是: 查看 git 日志,找到启动模块的更改。如果是项目本身的更改,那很好办,直接更改代码逻辑即可。如果不是,是引入或升级三方库导致的,那么只能根据获取 IMEI、设备MAC地址和软件安装列表等信息的 API 进行方法搜索,然而在 Android Studio 里面搜索的结果却是:

这信息对问题排除起不到任何帮助。

技术目标

我们期望有个工具,能扫描出启动模块中自身模块代码以及三方依赖库中所有使用 API 获取 获取 IMEI、设备MAC地址和软件安装列表等信息的地方,然后做版本对比,就可以知道新增代码或依赖库哪里有调用隐私方法。类似下面这张结果报告:

技术方案

根据之前一篇文章:Android 静态代码检查。知道 lint 可以自定义规则检查,而且 lint 中有提供 .class 文件的检查,这样就可以对自身项目代码以及三方库代码进行目标类方法调用者检查,并把这个规则集成到 lint 中,与 项目静态代码检查 一起工作。

关于 .class 文件的检查,lint 中也是使用了 asm ,所以这个和字节码插桩实现是同样的效果。单集成在 lint 中,技术成本更低。

目标类方法调用者检查:根据配置文件中要检查的类方法(达到动态配置功能,按需检查),检查后找到所有调用该类方法的地方,并输出 Json 和 Html 文件报告,并且还可以输出版本 diff 后的报告。

技术实践

技术流程

在自定义 lint 中 定义一个 Detector,用于接收 项目和三方库 class 文件扫描。在 Detector 执行过程中,将 class 和 class method 信息收集起来,等执行完成,将收集到的类方法信息与配置文件中的要检查的类方法信息进行匹配,匹配完成后输出 Json 和 Html 格式文件报告,如果有上一个执行结果,将与之 diff 后再输出结果。

下面为流程图:

自定义 lint 规则

google 在 github 上提供了一个自定义 lint 规则的 demo:https://github.com/googlesamples/android-custom-lint-rules。

这里,新建立一个 MethodCollectorDetector,并让它实现 Detector.ClassScanner 接口,主要告诉 lint ,需要的是 class 文件的检查。在 Issue 的 Implementation 中的作用域,需要注意的是:Scope.CLASS_FILE_SCOPEScope.ALL_CLASSES_AND_LIBRARIES 的区别,前者作用域只包含项目内的 class 文件,后一个作用域才会包含三方库中的 class 文件。

下面为伪代码:

class MethodCollectorDetector : Detector(), Detector.ClassScanner {override fun getApplicableAsmNodeTypes(): IntArray {//需要的是方法return intArrayOf(AbstractInsnNode.METHOD_INSN)}override fun checkInstruction(context: ClassContext,classNode: ClassNode,method: MethodNode,instruction: AbstractInsnNode) {super.checkInstruction(context, classNode, method, instruction)//目标所属类名称:instruction.owner//目标所属类方法名称:instruction.name//调用者所属类名称:classNode.name//调用者所属类方法名称:method.name//调用者所属类方法行数:ClassContext.findLineNumber(method)//上面信息与配置文件中的类方法信息进行匹配,匹配成功,就添加到结果中(instruction as? MethodInsnNode)?.let {if (match(instruction.owner,instruction.name,classNode.name,method.name)) {add( instruction.owner,instruction.name,classNode.name,method.name)context.report(ISSUE, context.getLocation(instruction),msg)}}}override fun beforeCheckRootProject(context: Context) {super.beforeCheckRootProject(context)//在检查根项目之前,读取配置文件中的类方法信息}override fun afterCheckRootProject(context: Context) {super.afterCheckRootProject(context)//将收集到的信息分析并生成 json 和 html 报告}companion object {private const val BUILD_NAME = "build"private const val BUILD_REPORTS_NAME = "reports"private const val METHOD_COLLECTOR_NAME = "method-collector"val ISSUE = Issue.create("MethodCollector",  //唯一 ID"在目录${BUILD_NAME}/${BUILD_REPORTS_NAME}/${METHOD_COLLECTOR_NAME}下查看相关方法调用者信息",  //简单描述"根据配置文件中类方法,找到调用它的地方,包括项目和三方库",  //详细描述Category.CORRECTNESS,  //问题种类(正确性、安全性等)6, Severity.WARNING,  //问题严重程度(忽略、警告、错误)Implementation( //实现,包括处理实例和作用域MethodCollectorDetector::class.java,Scope.ALL_CLASSES_AND_LIBRARIES))}
}

下面是类方法配置 .json 文件示例:

{"methods": [{"owner": "android/location/LocationManager","name": "getLastKnownLocation","message": "大佬,麻烦请用项目xxx库中xxx类的xxx方法获取","excludes": [{"caller": "androidx/appcompat/app/TwilightManager","name": "getLastKnownLocationForProvider"}]},{"owner": "android/net/wifi/WifiInfo","name": "getBSSID","message": "大佬,麻烦请用项目xxx库中xxx类的xxx方法获取"},{"owner": "android/net/wifi/WifiInfo","name": "getSSID","message": "大佬,麻烦请用项目xxx库中xxx类的xxx方法获取","excludes": [{"caller": "org/chromium/net/AndroidNetworkLibrary","name": "getWifiSSID"},{"caller": "org/chromium/net/NetworkChangeNotifierAutoDetect$WifiManagerDelegate","name": "getWifiSsid"}]},{"owner": "android/net/wifi/WifiInfo","name": "getMacAddress","message": "大佬,麻烦请用项目xxx库中xxx类的xxx方法获取"},{"owner": "android/telephony/TelephonyManager","name": "getImei","message": "大佬,麻烦请用项目xxx库中xxx类的xxx方法获取"},{"owner": "android/telephony/TelephonyManager","name": "getDeviceId","message": "大佬,麻烦请用项目xxx库中xxx类的xxx方法获取"},{"owner": "android/content/Context","name": "getExternalFilesDir","message": "大佬,麻烦请用项目xxx库中xxx类的xxx方法获取"},{"owner": "android/content/Context","name": "getExternalFilesDir","message": "大佬,麻烦请用项目xxx库中xxx类的xxx方法获取"}],"output": {"type": "single"}
}

总结

在 App 上架的时候,如果隐私不合规,可以通过上面这种:查看隐私权限方法调用者来快速定位。这种方法的原理,可以通过自定义 lint 规则来做,也可以通过 asm 字节码插桩来做。它们的核心都是通过扫描项目和三方库的 class 文件,然后再检查类文件中的类方法。

其实,上面这个工具,还可以满足需求,例如:

  • 在项目中,代码收敛,比如将所有使用 getExternalFilesDir 方法的地方都替换为一个 工具类方法;
  • 在项目中,某个库方法有更改,找到所有使用的地方包括其它 aar 库;

Demo Github 地址:https://github.com/WJRye/lint_mthod_collector

Android 查看隐私权限方法调用者集合相关推荐

  1. Android 判断摄像头权限方法

    由于项目需要,我们需要在启动摄像头前,预先判断一下我们的应用是否有摄像头权限(包括系统设置以及第三方安全软件是否禁止了摄像头打开权限). 目前主要用到了一下两个方法结合起来判断. 1.通过系统的检查权 ...

  2. Android APP隐私权限整改

    一.背景简介 前段时间,国内对于安卓APP隐私问题做了一波整改,我们的APP也做了一些整改,现在分块抽空整理出来吧 二.整改项目 1.隐私权限整改 主要是针对现在市场上APP各种乱申请权限,获取用户隐 ...

  3. android查看应用权限管理,通过adb列出Android应用程序的权限

    我只是想将Jason和Juuso的答案结合在一起,并注意到前者列出了授予的权限,而后者列出了请求的权限(包括被授予的权限). 要查看仅授予的权限(但忽略被请求但未被授予的权限),请使用 adb she ...

  4. android 应用宝上应用隐私权限声明的处理

    android 应用宝上应用隐私权限声明的处理 场景说明 最近运维同学反馈,在应用宝上传应用审核的时候被打回,原因是用户隐私权限的处理,通知内容如下 然后查看了一下市面上淘宝等其他应用的样式,发现效果 ...

  5. Android 5.x 权限问题解决方法

    Android 5.x 权限问题解决方法               一.  android 5.x开始,引入了非常严格的selinux权限管理机制,我们经常会遇到因为selinux权限问题造成的各种 ...

  6. android危险权限分组,Android 6.0权限请求相关及权限分组方法

    Android M(6.0)API 23后加入了权限请求设置,APP需要使用某些权限需要主动申请. 权限分为3类,一组是Normal权限,无需申请,另一组是Dangerous,需申请,然后是特殊权限, ...

  7. Android Studio查看SQLite数据库方法大全

    本文目录 方法1:Stetho Android Studio 中添加代码 Chrome浏览器中调试 方法2:SQLite Expert Professional 第一步:导出模拟器数据库文件 第二步: ...

  8. android 隐私泄露 路径,一种Android应用隐私泄露漏洞检测方法与流程

    本发明涉及Android查漏的技术领域,尤其涉及到一种Android应用隐私泄露漏洞检测方法. 背景技术: 在目前的Android隐私泄露漏洞检测方法中,静态污点分析是最常用且最有效的方法.首先对an ...

  9. AndroidQ(九)Android Q隐私权:权限变更

    Android Q隐私权:权限变更 本文档介绍了权限模型的一些变更.这些变更有助于增强用户隐私. 其中一些变更会影响在Android Q上运行的所有应用,而其他变更仅会影响以Android Q为目标平 ...

最新文章

  1. mysql象限和投影_PostGIS空间数据库SRID背景知识 - 地理坐标系(球面坐标系)和投影坐标系(平面坐标系) - GIS开发者...
  2. [转]计算机存储 cache介绍
  3. 【快乐水题】997. 找到小镇的法官
  4. linux查看逻辑卷命令,Linux命令--逻辑卷管理
  5. 鸿蒙硬件HI3861-OLED扫雷版本1
  6. linux显示指定目录容量,linux 查看指定目录的容量大小,系统目录容量大小
  7. 修改浏览器的默认最小字号限制(以chrome为例)
  8. 机房计算机配置思维导图,运用思维导图培养高中学生信息技术学科核心素养
  9. 如何设置透明FLASH
  10. Sklearn聚类算法之meanshift
  11. 6,JESD204B接口简介
  12. Centos7下安装Relion
  13. SPI通讯协议详解 基于STM32
  14. CRC (Cyclic redundancy check) java 实现
  15. Unity中的Object和object的区别
  16. IDEA修改编辑与控制台字体大小
  17. 爱乐馆-无损古典之Various Artist 《飞利浦原封套系列55CD》(PHILIPS ORIGINAL JACKETS COLLECTION)[FLAC]...
  18. Visual Studio 2017 卸载 以及 Visual Studio 2010 安装
  19. 新建android项目
  20. RJ45型配线架的端接后安装

热门文章

  1. MATLAB-如何生成随机数
  2. HCSA-01 Hillstone防火墙功能、StoneOS系统框架、接口与安全域
  3. 五方面提高销售流程管理的CRM系统
  4. Kubespray v2.22.1 在线部署 kubernetes v1.26.5 集群
  5. 一个自制的简单词云的制作模板(根据Python语言)
  6. 【PE/makefile】编译标记EXTRA_CFLAGS介绍和使用方法
  7. 多伦多大学计算机科学专业学费,多伦多大学留学一年学费是多少
  8. 多肽、instanceof
  9. 自控原理知识点小结(填空简答)
  10. 个人形象设计之衣橱管理