权限声明与最小权限原则

聊到第三方 SDK 的权限问题,我脑子里立刻蹦出几年前的一个项目。当时我们集成了一家地图 SDK,结果发现 App 一启动就弹「读取通讯录」的授权框——用户直接差评刷屏。后来一查,SDK 里躺着一行没人注意的权限声明。这事让我彻底明白,权限这玩意儿,你想着「反正声明了也没用」,用户可不这么想。

Android 与 iOS 权限模型差异

说白了,两个系统对权限的态度完全不同。Android 走的是「先声明、后申请」的路子,你在 AndroidManifest.xml 里列了哪些权限,安装时或运行时系统才允许你申请。iOS 则更霸道——不允许「静默声明」,任何权限必须在调用系统 API 时实时弹出对话框,而且用户随时可以去设置里关掉。

核心区别一句话:Android 的权限是「授权后一直有效直到撤销」,iOS 的权限是「每次使用都可能被拒绝」。

对比维度 Android iOS
权限声明方式 Manifest 静态声明 + 运行时请求 Info.plist 描述 + 运行时实时弹窗
权限类型 普通 / 危险 / 签名 / 系统 NS* 前缀,每个权限独立描述
用户可撤销性 Android 6.0+ 可单独关闭 设置中随时关闭,且系统会重置
第三方 SDK 行为 SDK 可直接声明权限(需审计) SDK 不能自动声明,宿主 App 必须主动添加 NSCameraUsageDescription 等键值
最小权限原则 需手动检查 SDK 额外权限 审核更严,但也是人工审查

Android 权限模型细节

我习惯把 Android 权限分成三层:

  1. Normal Permissions——系统自动授予,比如 INTERNET。SDK 声明了也不弹窗,但容易被滥用。
  2. Dangerous Permissions——比如 ACCESS_FINE_LOCATION、CAMERA。必须运行时请求,用户能拒绝。
  3. Signature / System——系统级权限,第三方 SDK 通常拿不到。

你看,问题出在「普通权限」上。很多 SDK 偷偷加上 READ_EXTERNAL_STORAGE(危险权限)还写在 Manifest 里,实际上根本用不到。我在审计时发现过一个社交分享 SDK,居然声明了 RECORD_AUDIO——就问一个分享按钮为什么需要录音?

审计小技巧:用 aapt dump permissions your.apk 列出所有声明的权限,然后一行行核对 SDK 功能。别信文档,信二进制。

iOS 权限模型细节

iOS 这边的关键点在 Info.plist。每个权限必须写一个「使用说明」字符串,例如 NSCameraUsageDescription 的值是「此应用需要相机权限以拍摄头像」。用户弹窗时能看到这段话。

但坑也在这里——很多开发者觉得「随便写一句就行」。我曾经见过一个购物 App 的相机权限描述写的是「为了更好的体验」——用户根本不知道你什么时候会偷拍。更严重的是,有些 SDK 会要求宿主 App 在 plist 里添加某些 key,但宿主自己不知道,结果审核被拒。

注意:iOS 14.5 之后,App 追踪透明度(ATT)权限也被纳入隐私框架。如果你集成广告类 SDK,必须在 plist 里声明 NSUserTrackingUsageDescription,否则直接无法获取 IDFA。

权限滥用的典型案例

我把项目中踩过的坑整理成几类,你想想看是不是很眼熟:

类型 具体表现 真实案例
过度声明 SDK 声明了与核心功能无关的权限 某推送 SDK 声明了 READ_CONTACTS,官方说「用于优化消息送达」,实际没任何代码用到
隐蔽授权 SDK 在后台静默申请权限,不弹窗解释 某统计 SDK 在 Android 6.0 以下版本偷偷读取设备标识
拒绝降级 用户拒绝权限后,SDK 功能直接崩溃或无限弹窗 某视频 SDK 拒绝相机权限后,每次启动都弹窗「请授权」,无法关闭
数据关联 将获取的权限数据与用户 ID 关联后外传 某广告 SDK 获取位置后,连同 IMEI 一起发送到第三方服务器

为什么这些案例频发?说白了,SDK 开发者总想「多拿点数据,反正不影响用户」。但合规审计就是要把这些「顺手牵羊」的行为揪出来。

最小权限原则落地

我个人认为,最小权限原则不是一句口号,而是可以量化的标准。我每次审计都按三步走:

  1. 列出所有权限——通过反编译或 API 日志,抓出 SDK 实际申请的所有权限。
  2. 匹配功能点——把每个权限对应到 SDK 的某个具体功能。对不上的就是可疑项。
  3. 测试拒绝场景——模拟用户拒绝该权限,看 SDK 是否正常降级。如果崩溃或报错,说明强依赖不该有的权限。

举个例子,一个图片加载库(比如 Glide 或 SDWebImage)只需要 INTERNET 和文件存储权限。如果它在 AndroidManifest 里加上 CAMERA,那就直接亮红灯。

黄金标准:SDK 声明的权限数量 ≤ 其核心功能所需的最小权限数。多一个都不行。

知识体系总览

下面这张图把整个权限审计的逻辑串起来了。你跟着箭头走一遍,基本上就能形成自己的审计框架。

第三方SDK权限审计核心逻辑 Android 权限模型 Manifest 静态声明 + 运行时请求 Normal / Dangerous / Signature 用户可撤销(6.0+) iOS 权限模型 Info.plist 描述 + 实时弹窗 NSCameraUsageDescription 等 用户设置中随时关闭 权限滥用典型案例 过度声明 | 隐蔽授权 | 拒绝降级 | 数据关联 (审计重点:找出与功能无关的权限) 最小权限原则实施步骤 Step1: 列出所有权限 → Step2: 匹配功能点 → Step3: 测试拒绝场景 Android 审计要点 aapt dump | 反编译 | 运行时权限检查 iOS 审计要点 plist 检查 | 描述文案 | 隐私框架适配 💡 核心原则:权限数量 = 功能所需最小集,多一个都不行

避坑指南与实战心得

我最后分享几条亲自踩过的坑,希望能帮你省掉不少排查时间。

  • [Android] 别信 merge 后的 manifest——有时候 SDK 通过 tools:replace 覆盖宿主的权限声明。一定要看最终的 merged manifest 文件,位置在 build/intermediates/merged_manifest/ 下。
  • [iOS] 注意 Privacy Info 的完整路径——iOS 16 之后,Apple 要求所有隐私相关权限都要在 PrivacyInfo.xcprivacy 文件中声明,否则审核不通过。SDK 文档如果不提这个,你就得主动追问。
  • [通用] 测试用户拒绝权限后的表现——不要只测授权场景。我曾见过一个支付 SDK,用户拒绝位置权限后直接闪退,导致线上支付功能无法使用。正确的做法是降级为无位置服务,而不是强制要求。
  • [一句话总结] 如果 SDK 的文档里没有「权限声明列表」和「最小权限说明」,这个 SDK 的合规性就要打问号。

紧急提醒:2024 年 Google Play 和 App Store 都加强了对权限的审核。一旦发现 SDK 超范围申请权限,不仅 App 会被拒,开发者的账号也可能被标记。对于历史遗留的 SDK,建议尽快升级到最新版本,并重新审计权限清单。

好了,权限这个话题说深了能写一本书,但掌握以上几条,应付日常审计完全够用。下一件事就是动手把项目里的权限清单拉出来,对照着看一遍——你会发现,问题比你想象的要多。不信?试试看。