04_Broadcast安全与最佳实践_修订版
04 Broadcast 安全与跨应用通信最佳实践
基于原 PDF 修订、联网校对并补充缺失内容
1. Broadcast 安全模型的核心问题
Broadcast 的 action 命名空间是全局的,隐式广播可能被任何匹配的应用接收;导出的 receiver 也可能被其他应用伪造广播触发。因此,Broadcast 一定要同时考虑“谁能收到我发的广播”和“谁能给我发广播”。
| 风险 | 表现 | 防护 |
|---|---|---|
| 敏感信息泄漏 | 使用隐式广播发送 token、订单号、用户资料等 | 不要发敏感数据;必要时 setPackage/显式组件/权限保护。 |
| 伪造广播触发逻辑 | 导出 receiver 被恶意应用发送相同 action 激活 | android:exported=“false”;校验 permission、签名、来源与 extras。 |
| Action 冲突 | 多个应用使用同名自定义 action | 使用包名前缀命名 action。 |
| 后台滥用 | receiver 里执行长任务或拉起 Activity | 快速返回,转交 WorkManager/JobScheduler,用通知而不是直接启动页面。 |
2. 发送广播时如何限制接收方
- 优先显式化:intent.setPackage(packageName) 或 intent.setComponent(ComponentName(…))。
- 使用发送权限:sendBroadcast(intent, “com.example.permission.PRIVATE”)。
- 不要通过隐式广播发送敏感 extras。
- 对外协议要版本化,extras 使用稳定 key,并做好缺字段与类型错误处理。
// 只发给本应用包内匹配的 receiver
Intent intent = new Intent("com.example.app.ACTION_LOGOUT");
intent.setPackage(context.getPackageName());
context.sendBroadcast(intent);
// 使用权限保护接收方:只有持有该权限的 receiver 才能接收
context.sendBroadcast(intent, "com.example.permission.INTERNAL_BROADCAST");
3. 接收广播时如何限制发送方
<!-- Manifest receiver:默认不对外暴露 -->
<receiver
android:name=".InternalReceiver"
android:exported="false" />
<!-- 对外 receiver:用权限限制调用方 -->
<receiver
android:name=".PartnerReceiver"
android:exported="true"
android:permission="com.example.permission.PARTNER_BROADCAST">
<intent-filter>
<action android:name="com.example.partner.ACTION_PAY_RESULT" />
</intent-filter>
</receiver>
动态注册时,内部事件优先使用 RECEIVER_NOT_EXPORTED;确实要接收外部应用或某些特权系统应用广播时才使用 RECEIVER_EXPORTED,并按需要加 receiverPermission。
4. 内部事件不一定要用 Broadcast
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| ViewModel 通知 Activity/Fragment | LiveData、StateFlow、SharedFlow | 类型安全,生命周期友好。 |
| 模块间事件 | 接口回调、Flow、事件总线 | 不需要 Intent 序列化,也不依赖系统广播机制。 |
| 跨进程通信 | Binder/AIDL、Messenger、ContentProvider | 明确 IPC 边界,类型与权限更可控。 |
| 系统事件触发后台任务 | Manifest receiver + WorkManager/JobScheduler | 符合后台限制,可靠性更好。 |
| 通知用户打开页面 | Notification + PendingIntent | 不要从 receiver 直接启动 Activity。 |
5. 跨应用广播协议设计清单
- action 使用包名前缀:com.company.product.ACTION_XXX。
- 明确 exported:默认 false;对外才 true。
- 使用签名级 permission 或 receiverPermission 控制调用方。
- extras 做完整校验:null、类型、范围、版本号都要处理。
- 不要相信广播来源;需要强身份时用绑定服务、AIDL 或服务端校验。
- onReceive 只做轻量解析和任务分发,不做网络请求和大 IO。
6. Sticky Broadcast 安全补充
Sticky Broadcast 的缓存和重放机制会带来“任何人可访问、可发送、可修改”的风险。现代应用不应使用 sticky broadcast 传递业务状态。
参考资料
- Android Developers - Broadcasts overview: https://developer.android.com/develop/background-work/background-tasks/broadcasts
- Android Developers - Implicit broadcast exceptions: https://developer.android.com/develop/background-work/background-tasks/broadcasts/broadcast-exceptions
- Android Developers - BroadcastReceiver API reference: https://developer.android.com/reference/android/content/BroadcastReceiver
- Android Developers - LocalBroadcastManager release notes: https://developer.android.com/jetpack/androidx/releases/localbroadcastmanager
- Android Developers - Android 14 behavior changes: https://developer.android.com/about/versions/14/behavior-changes-14
- Android Developers - Android 12 behavior changes: https://developer.android.com/about/versions/12/behavior-changes-12
- Android Developers - ConnectivityManager API reference: https://developer.android.com/reference/android/net/ConnectivityManager
- Android Developers - Sticky broadcasts risk: https://developer.android.com/privacy-and-security/risks/sticky-broadcast