Android 安全开发之 exported 组件安全

2024-06-08 05:28

本文主要是介绍Android 安全开发之 exported 组件安全,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Android系统中的组件是应用的基本构建块,用于实现应用的功能和展现界面。组件可以被其他应用调用或访问,这可以通过设置组件的android:exported属性来控制。然而,如果exported属性设置不当,可能会导致严重的安全漏洞,例如数据泄露、隐私侵犯甚至恶意代码执行。

Android 安全开发之 exported 组件安全

  • 一、安全渗透案例
  • 二、解决方案
    • 2.1 设置组件 exported false
    • 2.1 设置组件 exported true
  • 三、 exported 组件的安全最佳实践

一、安全渗透案例

应用多个 exported 组件可绕过私密保险箱密码,直接读取私有目录下的私密文件。

1)DocViewActivity读取私密保险箱密码文件

adb shell am start -n com.xxx.filemanager/com.xxx.safe.view.preview.DocViewActivity --es android.intent.extra.TITLE test_title --es safe_file_path /data/data/com.xxx.filemanager/shared_prefs/safe_record.xml

2)DocViewActivity、VideoPlayActivity、AudioPlayActivity、ImageViewActivity 在设置隐私保险箱密码后,可绕过密码直接播放保险箱中的文件

可以播放私密保险箱中的视频

adb shell am start -n com.xxx.filemanager/com.xxx.safe.view.preview.VideoPlayActivity --es android.intent.extra.TITLE test_title --es safe_file_path /data/data/com.xxx.filemanager/app_private/4a992493f68406c22ae6a6af2e19be89

可以播放私密保险箱中的音频

adb shell am start -n com.xxx.filemanager/com.xxx.safe.view.preview.AudioPlayActivity --es android.intent.extra.TITLE test_title --es safe_file_path /data/data/com.xxx.filemanager/app_private/5e98efcd742f79aa4eb5928f12bab778

可以播放私密保险箱中的图片

adb shell am start -n com.xxx.filemanager/com.xxx.safe.view.preview.ImageViewActivity --es android.intent.extra.TITLE test_title --es safe_file_path /data/data/com.xxx.filemanager/app_private/e10dec177fc877e1ccb4b2b47d0596f8

修复方案:

  1. 需要确保私密保险箱秘密验证正确后,才能读app_private下的文件
  2. 限制应用沙箱文件的读取路径,只能读取/data/data/com.xxx.filemanager/app_private下的文件

二、解决方案

2.1 设置组件 exported false

如果此类预览文件 Activity 仅自己使用,可以将其设置exported="false",其他应用将无法访问。

 <activity android:name="com.xxx.safe.view.preview.AudioPlayActivity"android:exported="false"android:label="@string/audio_preview"android:theme="@style/AppTheme.Dialog"android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"><intent-filter><action android:name="com.xxx.intent.action.filemanager.VIEW" /><category android:name="android.intent.category.DEFAULT"/><data android:mimeType="audio/*" /></intent-filter></activity><activity android:name="com.xxx.safe.view.preview.VideoPlayActivity"android:exported="false"android:theme="@style/AppTheme.NoActionBar"android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"><intent-filter><action android:name="com.xxx.intent.action.filemanager.VIEW" /><category android:name="android.intent.category.DEFAULT"/><data android:mimeType="video/*" /></intent-filter></activity><activity android:name="com.xxx.safe.view.preview.ImageViewActivity"android:exported="false"android:theme="@style/AppTheme.NoActionBar"android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"><intent-filter><action android:name="com.xxx.intent.action.filemanager.VIEW" /><category android:name="android.intent.category.DEFAULT"/><data android:mimeType="image/*" /></intent-filter></activity><activity android:name="com.xxx.safe.view.preview.DocViewActivity"android:exported="false"android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"android:screenOrientation="portrait"><intent-filter><action android:name="com.xxx.intent.action.filemanager.VIEW" /><category android:name="android.intent.category.DEFAULT"/><data android:mimeType="text/*" /><data android:mimeType="text/html"/><data android:mimeType="text/plain"/><data android:mimeType="application/xhtml+xml"/><data android:mimeType="application/vnd.wap.xhtml+xml"/></intent-filter></activity>

由于设置exported="false",应用自身调用时候若使用隐式Intent也将无法跳转,需要指定包名PackageName或组件名ComponentName,才可以成功跳转。

private void openSelectedFile(EncryptionFileInfo info, String file) {String originalPath = info.getOriginalPath();String originName = SafeUtils.getOriginalFileName(originalPath);int mediaType = info.getMediaType();if (!mIsDoubleClick) {mIsDoubleClick = true;Intent intent = new Intent();intent.setAction(SafeConstants.ACTION_SAFE_FILE_VIEW);switch (mediaType) {case MediaFile.AUDIO_TYPE:intent.setType("audio/*");break;case MediaFile.VIDEO_TYPE:intent.setType("video/*");break;case MediaFile.IMAGE_TYPE:intent.setType("image/*");break;case MediaFile.DOC_TYPE:MediaFileType mediaFileType = MediaFile.getFileType(originalPath);intent.setType(mediaFileType == null ? "text/*" : mediaFileType.mimeType);break;default:break;}intent.putExtra(SafeConstants.SAFE_FILE_PATH, file);intent.putExtra(Intent.EXTRA_TITLE, originName);intent.setPackage(mActivity.getPackageName());try {startActivity(intent);} catch (ActivityNotFoundException e) {mIsDoubleClick = false;Toast.makeText(mActivity, R.string.open_fail, Toast.LENGTH_SHORT).show();}}
}

如果将组件设置属性exported="false",adb命令启动Activity则会抛出SecurityException异常,无法启动Activity预览文件。

server@dev-fj-srv:~/Desktop/$ adb shell am start -n com.xxx.filemanager/com.xxx.safe.view.preview.DocViewActivity --es android.intent.extra.TITLE test_title --es safe_file_path /data/data/com.xxx.filemanager/shared_prefs/safe_record.xml
Starting: Intent { cmp=com.xxx.filemanager/com.xxx.safe.view.preview.DocViewActivity (has extras) }
Exception: java.lang.SecurityException: Permission Denial: starting Intent { flg=0x10000000 cmp=com.xxx.filemanager/com.xxx.safe.view.preview.DocViewActivity (has extras) } from null (pid=15578, uid=2000) not exported from uid 10193
java.lang.SecurityException: Permission Denial: starting Intent { flg=0x10000000 cmp=com.xxx.filemanager/com.xxx.safe.view.preview.DocViewActivity (has extras) } from null (pid=15578, uid=2000) not exported from uid 10193at com.android.server.wm.ActivityTaskSupervisor.checkStartAnyActivityPermission(ActivityTaskSupervisor.java:1164)at com.android.server.wm.ActivityStarter.executeRequest(ActivityStarter.java:1194)at com.android.server.wm.ActivityStarter.execute(ActivityStarter.java:833)at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser(ActivityTaskManagerService.java:1371)at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser(ActivityTaskManagerService.java:1301)at com.android.server.am.ActivityManagerService.startActivityAsUserWithFeature(ActivityManagerService.java:3348)at com.android.server.am.ActivityManagerShellCommand.runStartActivity(ActivityManagerShellCommand.java:731)at com.android.server.am.ActivityManagerShellCommand.onCommand(ActivityManagerShellCommand.java:240)at com.android.server.am.UnisocActivityManagerShellCommand.onCommand(UnisocActivityManagerShellCommand.java:92)at com.android.modules.utils.BasicShellCommandHandler.exec(BasicShellCommandHandler.java:97)at android.os.ShellCommand.exec(ShellCommand.java:38)at com.android.server.am.UnisocActivityManagerServiceImpl.onShellCommand(UnisocActivityManagerServiceImpl.java:430)at android.os.Binder.shellCommand(Binder.java:1068)at android.os.Binder.onTransact(Binder.java:888)at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:5348)at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2812)at android.os.Binder.execTransactInternal(Binder.java:1344)at android.os.Binder.execTransact(Binder.java:1275)

2.1 设置组件 exported true

如果需要通过部分应用使用,组件必须可导出exported="true",可以添加鉴权校验或者包名过滤,以免数据泄漏。

@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 进行鉴权校验boolean isAuthorized = performAuthorizationCheck();if (isAuthorized) {// 鉴权通过,执行正常的处理逻辑setContentView(R.layout.activity_main);// ...} else {// 鉴权失败,执行相应的处理逻辑,比如显示错误提示或跳转到其他界面showAuthorizationFailedMessage();finish();}
}

在上述代码中,首先调用performAuthorizationCheck()方法进行鉴权校验。如果鉴权通过,就继续执行正常的处理逻辑,比如设置布局、初始化界面等。如果鉴权失败,你可以根据需求执行相应的处理逻辑,例如显示错误提示或跳转到其他界面,并在最后调用finish()方法关闭当前Activity。

private boolean performAuthorizationCheck() {// 自定义的鉴权逻辑if (customAuthorizationLogic()) {return true;} else {return false;}
}

在performAuthorizationCheck()方法中,你可以根据你的应用程序的需求和安全策略实现相应的鉴权逻辑。以下是一些常见的鉴权处理方式:

  1. 用户权限验证:检查当前用户是否具有执行该操作的权限。这可能涉及到用户身份验证、角色检查或权限列表的验证。
  2. 用户登录状态验证:检查用户是否已登录或会话是否有效。你可以根据你的应用逻辑,验证用户的登录状态和会话令牌的有效性。
  3. 设备标识验证:验证启动请求是否来自于一个受信任的设备。你可以使用设备标识信息(如IMEI、Android ID等)与预先存储的信任设备列表进行比对。

三、 exported 组件的安全最佳实践

为了降低exported组件的安全风险,开发者应该遵循以下最佳实践:

1.最小化exported组件:只将必要的组件设置为exported,尽量减少暴露在外部的组件数量。
2.严格控制权限:只授予exported组件所需的最小权限,避免授予不必要的权限。
3.输入验证:对所有输入数据进行严格的验证,防止恶意数据注入。
4.输出过滤:对所有输出数据进行过滤,防止敏感数据泄露。
5.加密敏感数据:对敏感数据进行加密存储,防止被窃取。
6.使用安全的编码实践:遵循安全的编码实践,避免编写易受攻击的代码。
7.定期进行安全测试:定期对exported组件进行安全测试,发现并修复潜在的安全漏洞。

相关参考:
[1] Google 官方文档:隐私权和安全性

这篇关于Android 安全开发之 exported 组件安全的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1041306

相关文章

浅析Rust多线程中如何安全的使用变量

《浅析Rust多线程中如何安全的使用变量》这篇文章主要为大家详细介绍了Rust如何在线程的闭包中安全的使用变量,包括共享变量和修改变量,文中的示例代码讲解详细,有需要的小伙伴可以参考下... 目录1. 向线程传递变量2. 多线程共享变量引用3. 多线程中修改变量4. 总结在Rust语言中,一个既引人入胜又可

四种Flutter子页面向父组件传递数据的方法介绍

《四种Flutter子页面向父组件传递数据的方法介绍》在Flutter中,如果父组件需要调用子组件的方法,可以通过常用的四种方式实现,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录方法 1:使用 GlobalKey 和 State 调用子组件方法方法 2:通过回调函数(Callb

Vue项目中Element UI组件未注册的问题原因及解决方法

《Vue项目中ElementUI组件未注册的问题原因及解决方法》在Vue项目中使用ElementUI组件库时,开发者可能会遇到一些常见问题,例如组件未正确注册导致的警告或错误,本文将详细探讨这些问题... 目录引言一、问题背景1.1 错误信息分析1.2 问题原因二、解决方法2.1 全局引入 Element

基于Python开发电脑定时关机工具

《基于Python开发电脑定时关机工具》这篇文章主要为大家详细介绍了如何基于Python开发一个电脑定时关机工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 简介2. 运行效果3. 相关源码1. 简介这个程序就像一个“忠实的管家”,帮你按时关掉电脑,而且全程不需要你多做

Java中的Opencv简介与开发环境部署方法

《Java中的Opencv简介与开发环境部署方法》OpenCV是一个开源的计算机视觉和图像处理库,提供了丰富的图像处理算法和工具,它支持多种图像处理和计算机视觉算法,可以用于物体识别与跟踪、图像分割与... 目录1.Opencv简介Opencv的应用2.Java使用OpenCV进行图像操作opencv安装j

vue解决子组件样式覆盖问题scoped deep

《vue解决子组件样式覆盖问题scopeddeep》文章主要介绍了在Vue项目中处理全局样式和局部样式的方法,包括使用scoped属性和深度选择器(/deep/)来覆盖子组件的样式,作者建议所有组件... 目录前言scoped分析deep分析使用总结所有组件必须加scoped父组件覆盖子组件使用deep前言

基于Qt Qml实现时间轴组件

《基于QtQml实现时间轴组件》时间轴组件是现代用户界面中常见的元素,用于按时间顺序展示事件,本文主要为大家详细介绍了如何使用Qml实现一个简单的时间轴组件,需要的可以参考下... 目录写在前面效果图组件概述实现细节1. 组件结构2. 属性定义3. 数据模型4. 事件项的添加和排序5. 事件项的渲染如何使用

基于Qt开发一个简单的OFD阅读器

《基于Qt开发一个简单的OFD阅读器》这篇文章主要为大家详细介绍了如何使用Qt框架开发一个功能强大且性能优异的OFD阅读器,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 目录摘要引言一、OFD文件格式解析二、文档结构解析三、页面渲染四、用户交互五、性能优化六、示例代码七、未来发展方向八、结论摘要

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

在 VSCode 中配置 C++ 开发环境的详细教程

《在VSCode中配置C++开发环境的详细教程》本文详细介绍了如何在VisualStudioCode(VSCode)中配置C++开发环境,包括安装必要的工具、配置编译器、设置调试环境等步骤,通... 目录如何在 VSCode 中配置 C++ 开发环境:详细教程1. 什么是 VSCode?2. 安装 VSCo