(4.1.55)Android 沙箱机制
(4.1.55)Android 沙箱机制
沙箱(sandbox)是为执行中的程序提供隔离环境的一种安全机制。它通过严格控制执行的程序所访问的资源,以确保系统的安全。
文章目录
由于Android是建立在Linux系统之上的,所以Android系统继承了Linux的 类Unix继承进程隔离机制与最小权限原则,并且在原有Linux的进程管理基础上对UID的使用做了改进,形成了Android应用的”沙箱“机制。
简单点说就是在Android的世界中每一个应用相当与一个Linux中的用户,他们相互独立,不能相互共享与访问,(这也就解释了Android系统中为什么需要进程间通信),正是由于沙盒机制的存在最大程度的保护了应用之间的安全,但是也带来了每一个应用所分配的内存大小是有限制的问题。
一、Android系统架构
Android采用分层的系统架构,由下往上分别是:
- linux内核层
- 硬件抽象层
- 系统运行时库层
- 应用程序框架层
- 应用程序层。
【android 系统构架图】
Android以Linux操作系统内核为基础,实现硬件设备驱动、进程和内存管理、网络协议栈、电源管理等核心系统功能。除此以外,Android还增加了一些面向移动设备的特有功能,如低内存管理LMK(Low Memory Killer)、匿名共享内存(Ashmem: Anonymous Shared Memory),以及进程间通信Binder机制。这些功能的增强进一步提升了Android在内存管理、进程间通信等方面的安全性。
Android之前的版本并不存在硬件抽象层。鉴于硬件厂商并不希望公开其设备驱动的源代码,Google对此将Linux内核驱动程序进行封装,屏蔽掉底层的实现细节,向上提供统一的接口,这就是硬件抽象层。
【HAL】
HAL(Hardware Abstraction Layer)规定了一套应用层对硬件层的读写和配置的统一接口,本质上是将硬件的驱动分为用户空间和内核空间,其中内核驱动程序运行在内核空间,HAL运行在用户空间。上图中的Stub,以so库的形式存在,可以理解为proxy。上层通过调用标识获得HAL的相关Stub,进而取得相应操作。
系统运行时库由系统类库和Android运行时构成。系统类库基本上用C/C++编写,基本功能说明如下:
系统类库 | 功能说明 |
---|---|
Surface Manager | 执行多个应用程序时,管理子系统显示,对2D和3D图形提供支持 |
Media Framework | 基于PacketVideoOpenCore多媒体库,支持多种常用的音频视频格式录制和回放。支持的编码格式包括MPEG4、MP3、H.264、AAC、ARM |
SQLite | 本地小型关系型数据库,以代替传统的耗费资源JDBC API |
OpenGL ES | 基于OpenGL ES 1.0 API标准实现的3D跨平台图形库 |
FreeType | 用于显示位图和矢量字体 |
Webkit | Web浏览器软件引擎 |
SSL | 安全套接层 |
SGL | 底层2D图形引擎 |
Libc(bionic libc) | 继承自BSD的C函数库bionic libc,更适合基于嵌入式Linux的移动设备 |
当然,还有Android NDK(Native Development Kit),使得应用程序可以不依赖Dalvik虚拟机进行开发。Android运行时核心库提供android.os, android.net, android.media等核心API,而Dalvik虚拟机依赖Linux内核,实现进程隔离与线程调度管理、安全与异常管理、垃圾回收等功能,并被改进以适应低内存、低处理器速度的移动设备环境。
再往上就是应用程序框架层了。一系列的Android应用程序所需的类库,使得开发人员可以快速地进行程序开发,也可以通过继承实现个性化的扩展。如Activity Manager负责主线程ActivityThread的创建、Activity生命周期的维护,并为窗口提供交互的接口。
应用层就是与用户直接交互的应用程序,如SMS短信、图片浏览器、地图以及开发人员所开发的应用程序。
二、Android安全机制
Android将安全设计贯穿系统架构的各个层面,覆盖系统内核、虚拟机、应用程序框架层以及应用层各个环节,力求在开放的同时,也恰当保护用户的数据、应用程序和设备的安全。Android安全模型主要提供以下几种安全机制:
- 进程沙箱隔离机制
- 进程沙箱隔离机制,使得Android应用程序在安装时被赋予独特的用户标识(UID),并永久保持。应用程序及其运行的Dalvik虚拟机运行在独立的Linux进程空间,与其它应用程序完全隔离。
- 在特殊情况下,进程间还可以存在相互信任关系。如源自同一开发者或同一开发机构的应用程序,通过Android提供的共享UID(Shared UserId)机制,使得具备信任关系的应用程序可以运行在同一进程空间。
- 应用程序签名机制
- 应用程序签名机制,规定APK文件必须被开发者进行数字签名,以便标识应用程序作者和在应用程序之间的信任关系。在安装应用程序APK时,系统安装程序首先检查APK是否被签名,有签名才能安装。当应用程序升级时,需要检查新版应用的数字签名与已安装的应用程序的签名是否相同,否则,会被当做一个新的应用程序。Android开发者有可能把安装包命名为相同的名字,通过不同的签名可以把他们区分开来,也保证签名不同的包不被替换,同时防止恶意软件替换安装的应用。
- 权限声明机制
- 权限声明机制,要想获得在对象上进行操作,就需要把权限和此对象的操作进行绑定。不同级别要求应用程序行使权限的认证方式也不一样,Normal级申请就可以使用,Dangerous级需要安装时由用户确认,Signature和Signatureorsystem级则必须是系统用户才可用。
- 访问控制机制
- 访问控制机制,确保系统文件和用户数据不受非法访问
- 进程通信机制
- 进程通信机制,基于共享内存的Binder实现,提供轻量级的远程进程调用(RPC)。通过接口描述语言(AIDL)定义接口与交换数据的类型,确保进程间通信的数据不会溢出越界。
- 内存管理机制
- 基于Linux的低内存管理机制,设计实现了独特的LMK,将进程重要性分级、分组,当内存不足时,自动清理级别进程所占用的内存空间。同时,引入的Ashmem内存机制,使得Android具备清理不再使用共享内存区域的能力。
正是因为Android采用多层架构,在保护信息安全的同时,也保证开放平台的灵活性。
三、Android沿用Linux权限模型
Android sandbox本质是为了实现不同应用程序之间的互相隔离,而这种隔离策略是通过让不同的应用程序运行于各自己的虚拟机进程中实现的。
沙箱,对使用者来说可以理解为一种安全环境,对恶意访问者来说是一种限制。
在Android系统中,应用(通常)都在一个独立的沙箱中运行,即每一个Android应用程序都在它自己的进程中运行,都拥有一个独立的Dalvik虚拟机实例。Dalvik经过优化,允许在有限的内存中同时高效地运行多个虚拟机的实例,并且每一个Dalvik应用作为一个独立的Linux进程执行。Android这种基于Linux的进程“沙箱”机制,是整个安全设计的基础之一。
Android从Linux继承了已经深入人心的类Unix进程隔离机制与最小权限原则,同时结合移动终端的具体应用特点,进行了许多有益的改进与提升。具体而言,进程以隔离的用户环境运行,不能相互干扰,比如发送信号或者访问其他进程的内存空间。因此,Android沙箱的核心机制基于以下几个概念:
- 标准的Linux进程隔离
- 大多数进程拥有唯一的用户ID(UID)
- 以及严格限制文件系统权限。
Android系统沿用了Linux的UID/GID权限模型,即用户ID和用户组ID,但并没有使用传统的passwd和group文件来存储用户与用户组的认证凭据,作为替代,Android定义了从名称到独特标识符Android ID(AID)的映射表。初始的AID映射表包含了一些与特权用户及系统关键用户(如system用户/用户组)对应的静态保留条目。
除了AID,Android还使用了辅助用户组机制,以允许进程访问共享或受保护的资源。例如,sdcard_rw用户组中的成员允许进程读写/sdcard目录,因为它的加载项规定了哪些用户组可以读写该目录。这与许多Linux发行版中对辅助用户组机制的使用是类似的。除了用来实施文件系统访问,辅助用户组还会被用于向进程授予额外的权限。权限是关于允许或限制应用程序(而不是用户)访问设备资源。
Android扩展了Linux内核安全模型的用户与权限机制,将多用户操作系统的用户隔离机制巧妙地移植为应用程序隔离。
- 在linux中,一个用户标识(UID)识别一个给定用户;
- 在Android上,一个UID则识别一个应用程序。在安装应用程序时向其分配UID。应用程序在设备上存续期间内,其UID保持不变。仅限用于允许或限制应用程序(而非用户)对设备资源的访问。
如此,Android的安全机制与Linux内核的安全模型完美衔接!不同的应用程序分别属于不同的用户,因此,应用程序运行于自己独立的进程空间,与UID不同的应用程序自然形成资源隔离,如此便形成了一个操作系统级别的应用程序“沙箱”。
四、Android沙箱模型
Android 安全架构的中心设计点是:在默认情况下任何应用都没有权限执行对其他应用、操作系统或用户有不利影响的任何操作。这包括读取或写入用户的私有数据(例如联系人或电子邮件)、读取或写入其他应用程序的文件、执行网络访问、使设备保持唤醒状态等。
由于每个 Android 应用都是在进程沙盒中运行,因此应用必须显式共享资源和数据。它们的方法是声明需要哪些权限来获取基本沙盒未提供的额外功能。应用以静态方式声明它们需要的权限,然后 Android 系统提示用户同意。
应用沙盒不依赖用于开发应用的技术。特别是,Dalvik VM 不是安全边界,任何应用都可运行原生代码(请参阅 Android NDK)。各类应用 — Java、原生和混合 — 以同样的方式放在沙盒中,彼此采用相同程度的安全防护。
4.1 应用程序在独立的进程
应用程序进程之间,应用程序与操作系统之间的安全性由Linux操作系统的标准进程级安全机制实现。
**在默认状态下,应用程序之间无法交互,运行在进程沙箱内的应用程序没有被分配权限,无法访问系统或资源。
因此,无论是直接运行于操作系统之上的应用程序,还是运行于Dalvik虚拟机的应用程序都得到同样的安全隔离与保护,被限制在各自“沙箱”内的应用程序互不干扰,对系统与其他应用程序的损害可降至最低
Android应用程序的“沙箱”机制如下图 1,互相不具备信任关系的应用程序相互隔离,独自运行,箭头访问是禁止的:
【沙箱】
Android 是一个多用户系统,每个应用是一个独立的用户。系统为每个应用分配一个唯一的用户标识(UID),并为应用中所有文件设置该用户才能访问的权限。每个进程中有一个独立的VM。每个应用在自己的进程中运行,应用的组件需要执行时,系统创建该进程;当系统内存不存时,系统会销毁该进程。
4.2 应用程序在同一个进程(共享UID)
Android 应用程序运行在它们自己的 Linux 进程上,并被分配一个惟一的用户 ID。在安装时,Android 为每个软件包提供唯一的 Linux 用户 ID。此 ID 在软件包在该设备上的使用寿命期间保持不变。在不同设备上,相同软件包可能有不同的 UID;重要的是每个软件包在指定设备上的 UID 是唯一的。
默认情况下,运行在基本沙箱进程中的应用程序没有被分配权限,因而防止了此类应用程序访问系统或资源。
但是 Android 应用程序可以通过应用程序的 manifest 文件请求权限。通过做到以下两点,Android 应用程序可以允许其他应用程序访问它们的资源:
- 声明适当的 manifest 权限;
- 与其他受信任的应用程序运行在同一进程中,从而共享对其数据和代码的访问。
【沙箱2】
在很多情况下,源自同一开发者或同一开发机构的应用程序,相互间存在信任关系。Android系统提供一种所谓共享UID(SharedUserID)机制,使具备信任关系的应用程序可以运行于同一进程空间。通常 ,这种信任关系由应用程序的数字签名确定,并且需要应用程序在manifest文件中使用相同的UID。
由于在进程级实施安全性,因此任何两个软件包的代码通常都不能在同一进程中运行,因为它们需要作为不同的 Linux 用户运行。您可以在每个软件包的 AndroidManifest.xml 的 manifest 标记中使用 sharedUserId 属性,为它们分配相同的用户 ID。这样做以后,出于安全目的,两个软件包将被视为同一个应用,具有相同的用户 ID 和文件权限。请注意,为保持安全性,只有两个签署了相同签名(并且请求相同的 sharedUserId)的应用才被分配同一用户 ID。
应用存储的任何数据都会被分配该应用的用户 ID,并且其他软件包通常无法访问这些数据。使用 getSharedPreferences(String, int)、openFileOutput(String, int) 或 openOrCreateDatabase(String, int, SQLiteDatabase.CursorFactory) 创建新文件时,可以使用 MODE_WORLD_READABLE 和/或 MODE_WORLD_WRITEABLE 标记允许任何其他软件包读取/写入文件。设置这些标记时,文件仍归您的应用所有,但其全局读取和/或写入权限已适当设置,使任何其他应用都可看见它。
参考文献
更多推荐
所有评论(0)