理解 Android 上的安全性
利用沙箱、应用程序签名和权限增强应用程序安全性
转:http://www.ibm.com/developerworks/cn/xml/x-androidsecurity/
概念上讲,沙箱可以表示为 图 1 所示。
用户 ID:Linux 与 Android
Android 应用程序运行在它们自己的 Linux 进程上,并被分配一个惟一的用户 ID。默认情况下,运行在基本沙箱进程中的应用程序没有被分配权限,因而防止了此类应用程序访问系统或资源。但是 Android 应用程序可以通过应用程序的 manifest 文件请求权限。
通过做到以下两点,Android 应用程序可以允许其他应用程序访问它们的资源:
- 声明适当的 manifest 权限
- 与其他受信任的应用程序运行在同一进程中,从而共享对其数据和代码的访问
后者演示在 图 2 中。
不同的应用程序可以运行在相同的进程中。对于此方法,首先必须使用相同的私钥签署这些应用程序,然后必须使用 manifest 文件给它们分配相同的 Linux 用户 ID,这通过用相同的值/名定义 manifest 属性 android:sharedUserId
来做到。
图 3 演示了很多在开发 Android 应用程序时会发现的与安全性相关的用例。
- 应用程序或代码签名是这样一个过程,即生成私有、公共密钥和公共密钥证书,签署和优化应用程序。
- 权限是 Android 平台的一种安全机制,以允许或限制应用程序访问受限的 API 和资源。默认情况下,Android 应用程序没有被授予任何权限,不允许它们访问设备上受保护的 API 或资源,从而保证了它们的安全。权限必须被请求,定义了定制的权限,文件和内容提供者就可以受到保护。确保在运行时检查、执行、授予和撤销权限。
接下来,更加详细地来看一下每个安全领域。
所有 Android 应用程序都必须被签名。应用程序或代码签名是一个这样的过程,即使用私有密钥数字地签署一个给定的应用程序,以便:
- 识别代码的作者
- 检测应用程序是否发生了改变
- 在应用程序之间建立信任
基于这一信任关系,应用程序可以安全地共享代码和数据。
使用相同数字签名签署的两个应用程序可以相互授予权限来访问基于签名的 API,如果它们共享用户 ID,那么也可以运行在同一进程中,从而允许访问对方的代码和数据。
应用程序签名首先是生成一个私有、公共密钥对和一个相关公共密钥证书,简称为公共密钥证书。
构建 Android 应用程序时可以采用调试模式和发布模式:
- 使用 Android 构建工具(命令行和 Eclipse ADT)构建的应用程序是用一个调试私有密钥自动签名的;这些应用程序被称为调试模式应用程序。调试模式应用程序用于测试,不能够发布。注意,未签名的或者使用调试私有密钥签名的应用程序不能够通过 Android Market 发布。
- 您准备发布自己的应用程序时,必须构建一个发布模式的版本,这意味着用私有密钥签署应用程序。
Android 中的代码签名采用一种比其他移动平台中要简单得多的方式。在 Android 上,证书可以是自签名的,这就是说,无需证书授权。这种方法简化了发布过程和相关的成本。
接下来,介绍如何从命令行以及通过使用 Eclipse ADT 手动签署 Android 应用程序。本文中不介绍第三种方法,即使用 Ant。
回想一下,调试模式应用程序是使用调试密钥/证书由构建工具自动签名的。要签署一个发布模式的应用程序,首先必须生成私有、公共密钥对和公共密钥证书。可以手动地或者通过使用 Eclipse ADT 签署应用程序。两种方法中都使用了 Java Developer Kit (JDK) keytool 密钥和证书管理实用工具。
要手动生成私有、公共密钥信息,可以从命令行使用 keytool
,如 清单 1 所示。
清单 1. 使用 keytool
生成私有/公共密钥和证书
keytool -genkey -v -alias <alias_name> -keystore <keystore.name> -keyalg RSA -keysize 2048 -validity <number of days>
注意:清单 1 假设 JDK 已安装在您的计算机上,并且 JAVA_HOME
路径被正确定义为指向您的 JDK 目录(参见 参考资料,获得下载和设置信息)。
在 清单 1 中,-genkey
表示一个公共、私有密钥对项,以及一个 X.509 v1 自签署的单个元素证书链,其中包含生成的公共密钥。-v
表示冗长模式。-alias
是用于 keystore 项的别名,keystore 存储生成的私有密钥和证书。-keystore
表示使用的密钥仓库的名称。-keyalg
是用来生成密钥对的算法。-keysize
是生成的密钥大小,其中默认大小是 1024,但是推荐大小是 2048。-validity
是有效天数;推荐采用大于 1000 的值。
注意:生成密钥之后,一定要保证密钥的安全。不要共享私有密钥,也不要在命令行或脚本中指定密钥;注意,keytool 和 jarsigner 会提示输入密码。关于这一技巧和其他技巧,请参考 Android Developers 网站的 “Securing Your Private Key”(参见 参考资料 中的链接)。
Keytool
提示您输入名和姓、公司、城市、州、国家,从这些信息生成一个 X.500 Distinguished Name(更多信息请参见 参考资料),还要输入保护私有密钥和密钥仓库本身的密码。
对于有效期,请确保使用超出应用程序本身和相关应用程序预期生命期的时期。如果您是在 Android Market 上发布应用程序,那么有效期必须晚于 2033 年 10 月 22 日结束;否则不能上载。此外,拥有长寿命的证书让升级应用程序更为容易。幸运的是,Android Market 强制采用长寿命的证书,以帮助您避免此类问题。
手动签署应用程序
接下来,使用 jarsigner
工具(它是 JDK 的一部分)签署未签名的应用程序:
jarsigner -verbose -keystore <keystore.name> <my_application.apk> <alias_name>
在上述代码中,-verbose
表示冗长模式,-keystore
表示使用的密钥仓库的名称。接下来是应用程序的名称 (.apk),最后是用于私有密钥的别名。
Jarsigner
提示您输入使用密钥仓库和私有密钥时的密码。
应用程序可以使用不同的密钥进行多次签名,用相同私有密钥签名的应用程序之间可以建立一种信任关系,并且可以运行在同一进程中,共享代码和数据。
手动优化应用程序
签署过程的最后一步是优化应用程序,以便数据边界与文件的开始是内存对齐的,这种技术有助于改善运行时性能和内存利用率。要签署应用程序,可以使用 zipalign
:
zipalign -v 4 your_project_name-unaligned.apk your_project_name.apk
在前面的代码中,-v
表示冗长输出。数字 4 表示使用四字节对齐(总是使用四字节)。下一个参数是输入已签署应用程序的文件名 (.apk),它必须用您的私有密钥签署。最后一个参数是输出文件名;如果覆盖现有应用程序,则添加一个 -f
。
手动验证应用程序已经签署
要验证应用程序已经签署,可以使用 Jarsigner
,这次传递 -verify
标志:
jarsigner -verify -verbose -certs my_application.apk
在前面的代码中,-verify
表示验证应用程序;-verbose
表示冗长模式;-certs
表示展示创建密钥的 CN 字段,最后一个参数是要验证的 Android 应用程序包的名称。
注意:如果 CN 读入 "Android Debug",那么意味着应用程序是用调试密钥签署的,这表明不能发布;如果您计划在 Android Market 上发布您的应用程序,一定要记得使用私有密钥。
刚才学习了如何手动创建私有、公共密钥,以及签署和优化应用程序。接下来,了解如何使用 Eclipse ADT 自动创建私有、公共密钥,以及签署和优化应用程序。
使用 Eclipse ADT 创建密钥和证书,以及签署和优化应用程序
要使用 Eclipse ADT 生成密钥,必须导出应用程序。有两种方法从 Eclipse 导出应用程序:
- 导出您必须手动签署的应用程序的未签署 版本
- 导出应用程序的已签署 版本,其中所有步骤都由 ADT 为您代劳
导出未签署的应用程序
您可以导出您必须手动签署的应用程序的未签署版本。就是说,您需要手动运行 keytool(如前所述,是为了生成密钥)和 Jarsigner(为了签署应用程序),并使用 zipalign 工具优化应用程序,跟前面解释的那样。
要使用 ADT 导出应用程序的未签署版本,可以右键单击项目并选择 Android Tools>Export Unsigned Application Package(参见 图 4)。
图 4. 导出未签署的应用程序
选中之后,ADT 提示您选择将未签署应用程序导出到的目录。记住,一旦应用程序被导出,您就必须手动签署和优化应用程序,跟前面介绍的那样。
导出已签署的应用程序
利用 Eclipse ADT,您可以导出应用程序的已签署版本。使用这种方法,ADT 提示您输入以下内容:
- 使用现有 KeyStore 或者创建新的受保护 KeyStore 所需的信息
- 创建受保护私有密钥所需的信息
- 生成公共密钥证书所需的信息
要导出已签署的应用程序,可以右键单击项目,但是这一次选择菜单项 Android Tools->Export Signed Application Package,如 图 5 所示。
图 5. 导出已签署的应用程序
此时,Export Wizard 执行,如 图 6 所示。
图 6. Export Wizard
在 图 7 中,选择一个现有的密钥仓库(或者创建一个新的)和证书。
图 7. Export Wizard:密钥仓库选择
在 图 8 中,输入信息以创建私有密钥和数字证书。
图 8. Export Wizard:创建私有密钥和数字证书
在 图 9 中,输入目标文件的路径和名称,并验证有效期间。
图 9. 输入目标文件的路径和名称
完成时,您就有了一个发布模式的已签署和已优化的应用程序,您可以发布它。
另外,您也可以使用 Android Manifest 工具调用 Export Wizard,如 图 10 所示。
图 10. 使用 Android Manifest 工具调用 Export Wizard
应用程序签署之后,下一步由您在 manifest 中定义应用程序需要的权限。接下来将描述这一过程。
注意,Android Developer 网站有非常好的关于应用程序签署的文档,当有 Android 平台的新版本可用时,这些文档都会更新(参见 参考资料,了解更多信息)。
使用权限
权限是一种 Android 平台安全机制,旨在允许或限制应用程序访问受限的 API 和资源。默认情况下,Android 应用程序没有被授予权限,这通过不允许它们访问设备上的受保护 API 或资源,确保了它们的安全。权限在安装期间通过 manifest 文件由应用程序请求,由用户授予或不授予。
Android 定义长长的一系列 manifest 权限,以保护系统或其他应用程序的各个方面。要请求权限,可以在 manifest 文件中声明一个 <user-permission>
属性:
<uses-permission android:name="string" />
其中 android:name
指定权限的名称。
要得到所有 Android 定义的 manifest 权限的列表,请参见 Manifest.permisson 页面。清单 2 是一个 manifest 文件的例子,它请求使用 Internet 的权限和写到外部存储器的权限:
清单 2. 声明(请求)权限
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.cenriqueortiz.tutorials.datastore" android:installLocation="auto"> <application : : : </application> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> </manifest>
应用程序可以定义它们自己的定制权限,以保护应用程序资源。其他应用程序想要访问一个应用程序的受保护资源,就必须通过它们自己的 manifest 文件请求适当的权限。清单 3 展示了一个如何定义权限的例子。
清单 3. 声明定制权限
<permission xmlns:android="http://schemas.android.com/apk/res/android" android:name="com.cenriqueortiz.android.ACCESS_FRIENDS_LIST" android:description="@string/permission_description" android:label="@string/permission_label" android:protectionLevel="normal" > </permission>
在 清单 3 中,通过指定最少的属性,即 name
、description
、label
和 protectionLevel
,定义了一个定制权限。也可以定义其他属性,但是这里没做介绍。
特别有趣的是 android:protectionLevel
属性,它表示系统向一个请求权限的应用程序授予(或不授予)给定的权限时应该遵循的方法。保护级别有普通 和危险。前者自动授予权限(尽管用户在安装之前总是可以重审),基于签名授予权限(就是说,如果请求权限的应用程序是用同一证书签署的);后者表示权限给予私有数据的访问权,或者具有另一个潜在的负面影响。有关 <permission>
manifest 属性的更多信息,请参见 <permission> 页面(参见 参考资料)。
应用程序可以限制对应用程序及其使用的系统组件(比如 Activity、Service、Content Provider 和 Broadcast Receiver)的访问。通过像 清单 4 中那样定义 android:permission
属性,很容易实现这种限制。这种级别的保护让应用程序允许或限制其他应用程序访问系统资源。
清单 4. 定义一个活动的权限
<activity android:name=".FriendsListActivity" android:label="Friends List"> android:permission="com.cenriqueortiz.android.ACCESS_FRIENDS_LIST" <intent-filter> : : </intent-filter> </activity>
内容提供者和文件权限
内容提供者暴露一个公共 URI,用于惟一地识别它们的数据(参见 参考资料)。要保护此内容提供者,当开始时或者从活动返回结果时,调用者可以设置 Intent.FLAG_GRANT_READ_URI_PERMISSION
和 Intent.FLAG_GRANT_WRITE_URI_PERMISSION
,以便授予接收活动权限,以访问特定的数据 URI。
应用程序文件默认是受保护的。文件基于用户 ID 受保护,因而只对所有者应用程序是可访问的(此应用程序具有相同的用户 ID)。正如前面介绍的,共享相同用户 ID(并使用相同数字证书签署)的应用程序运行在相同进程上,因而共享对它们的应用程序的访问。
应用程序可以允许其他应用程序或进程访问它们的文件。这种允许是通过指定适当的 MODE_WORLD_READABLE
和 MODE_WORLD_WRITEABLE
操作模式(以便允许对文件的读或写访问)或 MODE_PRIVATE
(以便以私有模式打开文件)而做到的。您可以在创建或打开文件时利用以下方法指定操作模式:
-
getSharedPreferences(filename, operatingMode)
-
openFileOutput(filename, operatingMode)
-
openOrCreateDatabase(filename, operatingMode, SQLiteDatabase.CursorFactory)
Android 提供各种 API 来在运行时检查、执行、授予和撤销权限。这些 API 是 android.content.Context
类的一部分,这个类提供有关应用程序环境的全局信息。例如,假设您想要优雅地处理权限,您可以确定您的应用程序是否被授予了访问 Internet 的权限(参见 确定 5)。
清单 5. 使用运行时 Permission
API 在运行时检查权限
if (context.checkCallingOrSelfPermission(Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) { // The Application requires permission to access the // Internet"); } else { // OK to access the Internet }
要了解其他在运行时检查、执行、授予和撤销权限的权限 API,请参考上下文类。
结束语
本文介绍了 Android 平台上的安全性,包括沙箱、应用程序签名、应用程序权限,以及文件和内容提供者权限。阅读完这篇介绍性文章之后,您将能够使用 Eclipse 手动创建数字证书,请求应用程序权限,以及允许或不允许应用程序访问文件和内容提供者。此外,您还简要了解了权限运行时 API,这些 API 允许您在运行时检查、执行、授予和撤销权限。
发表评论
-
资料上传备份
2012-07-02 07:28 0对付对付对付对付 -
Android-sharedUserId数据权限
2012-05-02 10:16 1445Android-sharedUserId数据权限 An ... -
Android Service学习之本地服务
2012-04-18 10:28 863转: Android Service学习之本地服务 htt ... -
match_parent和fill_parent的区别 .
2012-02-18 11:49 1840match_parent和fill_parent的区别 有 ... -
Android中SQLiteOpenHelper类的onUpgrade方法的作用
2012-02-09 11:50 4601Android中SQLiteOpenHelper类的onUpg ... -
Android启动各种系统服务线程
2012-02-09 10:59 1936Android启动各种系统服务 ... -
android
2012-02-08 09:22 0Android数据库内容变化的监听 首先介绍内容监 ... -
在线升级Android应用程序的思路
2012-02-07 11:34 880在线升级Android应用程序的思路 http://www. ... -
Android数据库内容变化的监听
2012-02-07 11:31 6033Android数据库内容变化的监听 首先介绍内容监 ... -
android中的数据库操作
2012-02-07 10:50 1451android中的数据库操作 ... -
SQLiteOpenHelper类与自动升级数据库
2012-02-07 10:31 2283SQLiteOpenHelper类与自动升级数据库 S ... -
SQLite外键的实现
2012-02-07 10:30 1717SQLite外键的实现 SQLite现在的版本还不支持 ... -
Android到处都在使用的回调分析
2011-12-21 15:53 3547Android到处都在使用的回调分析 ... -
android中LayoutInflater的使用
2011-12-21 11:35 1932android中LayoutInflater的使用 ... -
SIM卡满处理流程分析
2011-12-19 15:15 1882SIM卡满处理流程分析 //框架层分析 // SMSD ... -
短信发送状态报告流程分析
2011-12-19 15:07 2393短信发送状态报告流程分析 //应用层分析: //Sms ... -
Android平台 短信接送流程剖析(含编码)
2011-12-16 15:29 3228Android平台 短信接送流程剖析(含编码) ... -
修改语言环境方法
2011-12-16 15:20 1040修改语言环境方法 private void se ... -
Android平台 短信发送流程剖析(含编码)
2011-12-12 17:12 4334Android平台 短信发送流程剖析(含编码) 本文对A ... -
Android 应用程序签名
2011-11-27 11:34 1642Android 应用程序签名 转:http://www ...
相关推荐
理解 Android 上的安全性
综上所述,《深入理解Android 卷III》这本书不仅会从宏观角度讲解Android系统的整体架构,还会深入探讨具体的开发技术和性能优化方法。无论是对于想要深入学习Android内部机制的技术人员,还是希望提高自己开发水平...
在Android软件安全与逆向分析的第五...这一章的内容旨在帮助读者建立对Android应用安全性的全面理解,并掌握逆向分析的基本技能。无论是为了开发更安全的应用,还是为了检测和防御恶意软件,这些知识都将提供宝贵指导。
1. Android系统架构:理解Android系统的层次结构,包括Linux内核、HAL层、系统服务、应用程序框架以及用户界面。 2. Dalvik与ART:探讨Android运行时环境的Dalvik虚拟机和后来的ART(Android RunTime)如何执行应用...
这本书以其深度和全面性,为Android开发者提供了宝贵的洞察力,使得开发者能够深入理解Android系统的运行机制,从而更好地优化应用性能、解决实际问题。 在本书中,你可以学到以下关键知识点: 1. **Android系统...
通过阅读《Android软件安全与逆向分析》,读者不仅可以学习到Android安全的基础知识,还能掌握实战技能,对提高Android应用的安全性具有重要价值。无论是开发者还是安全研究人员,都能从中受益匪浅。
这些书籍是深入理解Android平台安全性的宝贵资源,对于开发者、安全研究人员以及对移动安全有兴趣的个人来说,具有很高的学习价值。 一、Android安全机制解析与应用实践 这本书主要探讨了Android操作系统的基础安全...
13. **安全性**:讨论Android应用的安全性问题,如何防止逆向工程,以及数据加密和隐私保护。 14. **性能优化**:分享性能分析技巧,如何进行代码优化,提高应用的响应速度和电量效率。 15. **单元测试与自动化...
《深入理解Android:WIFI模块 NFC和GPS卷》是一本专为Android开发者和爱好者准备的高级技术指南,旨在帮助读者全面掌握Android系统中无线通信、近场通信和定位服务的关键技术。这本书详细阐述了Android平台下WiFi、...
### 深入理解Android之Java Security #### 一、Java Security 背景知识 Java Security 是 Java 平台中的一个重要组成部分,它不仅在软件实现方面有着丰富的内容,而且还涉及一系列规范。从 Java 2 开始,Java ...
《深入理解Android:Telephony原理剖析与最佳实践》是一本专注于Android系统中Telephony模块的专著。Telephony是Android操作系统中的核心组件之一,主要负责处理手机的电话、短信等功能,涉及到了移动通信领域的诸多...
了解这些基础是理解Android安全问题的关键。作者会深入解析应用程序的生命周期、组件通信方式(如Intent)以及它们如何影响安全。 其次,书中会详细介绍Android应用的逆向工程,包括APK的结构、dex文件格式、Java...
5. **安全性**:讲解Android的安全模型,包括权限管理、数据加密和应用安全实践。 6. **NDK开发**:介绍Native Development Kit,如何使用C/C++进行原生代码开发,以及JNI的使用。 7. **Android测试**:涵盖单元...
通过学习《深入理解Android:卷一》,读者不仅可以掌握Android开发的高级技术,还能培养解决实际问题的能力,从而在Android开发领域更上一层楼。高清版的PDF使得阅读体验更好,便于随时查阅和学习。
Android作为全球最受欢迎的移动操作系统,其安全性至关重要,对于开发者、安全工程师以及对移动安全有兴趣的读者来说,理解其安全架构是必不可少的。 Android安全体系基于多个层次构建,包括硬件层、操作系统层、...
通过对“面向Android安全性的Smali混淆代码分析”的研究,我们不仅能够更加深入地理解Android系统安全性分析的复杂性和挑战,还可以掌握一种有效的代码混淆识别和分析方法。这对于保证Android平台应用的安全性,避免...
《深入理解Android》是邓凡平先生所著的一套关于Android开发的权威指南,分为卷I和卷II,这两部著作对于深入理解Android系统的工作原理和框架设计具有极高的参考价值。书中涵盖了从基础概念到高级技术的广泛内容,...