Android安全开发之Provider组件安全

Android安全开发之Provider组件安全

作者:伊樵、呆狐@阿里聚安全

1 Content Provider组件简介

Content Provider组件是Android应用的重要组件之一,管理对数据的访问,主要用于不同的应用程序之间实现数据共享的功能。Content Provider的数据源不止包括SQLite数据库,还可以是文件数据。通过将数据储存层和应用层分离,Content Provider为各种数据源提供了一个通用的接口。

创建一个自己的Content Provider需要继承自ContentProvider抽象类,需要重写其中的onCreate()、query()、insert()、update()、delete()、getType()六个抽象方法,这些方法实现对底层数据源的增删改查等操作。还需在AndroidManifest文件注册Content
Provider,注册时指定访问权限、exported属性、authority属性值等。

其它APP使用ContentResolver对象来查询和操作Content Provider,此对象具有Content Provider中同名的方法名。这样其他APP接就可以访问Content Provider对应的数据源的底层数据,而无须知道数据的结构或实现。

如何定位到具体的数据?

采用Content Uri,一个Content Uri如下所示:

content://com.jaq.providertest.friendsprovider/friends

它的组成一般分为三部分:

  • (1)content://:作为 content Uri的特殊标识(必须);
  • (2)权(authority):用于唯一标识这个Content Provider,外部访问者可以根据这个标识找到它;在AndroidManifest中也配置的有;
  • (3)路径(path): 所需要访问数据的路径,根据业务而定。

这些内容就不具体展开详谈了,详见参考[1][4]。

2 风险简介

如果在AndroidManifest文件中将某个Content Provider的exported属性设置为true,则多了一个攻击该APP的攻击点。如果此Content Provider的实现有问题,则可能产生任意数据访问、SQL注入、目录遍历等风险。

2.1 私有权限定义错误导致数据被任意访问

私有权限定义经常发生的风险是:定义了私有权限,但是却根本没有定义私有权限的级别,或者定义的权限级别不够,导致恶意应用只要声明这个权限就能够访问到相应的Content Provider提供的数据,造成数据泄露。

以公开的乌云漏洞WooYun-2014-57590为例:

某网盘客户端使用了自己的私有权限,但是在AndroidManifest中却没有定义私有权限,其它APP只要声明这个权限就能访问此网盘客户端提供的Provider,从而访问到用户数据。

在网盘客户端的AndroidManifest中注册Provider时,声明了访问时需要的读写权限,并且权限为客户端自定义的私有权限:

但是在AndroidManifest中却没有见到私有权限“com.huawei.dbank.v7.provider.DBank.READ_DATABASE”和“com.huawei.dbank.v7.provider.DBank.WRITE_DATABASE”的定义:

反编译客户端后查看到的URI,根据这些可以构造访问到Provider的URI:

编写POC 

以查看网盘下载的文件列表为例,

在POC的AndroidManifest中声明私有权限,权限的保护级别定义为最低级“normal”:

主要代码为:

拿到数据库中保存的下载列表数据:

对应的数据库:

这样任意的恶意应用程序就可以访问到用户网盘的上传、下载记录,网盘里面存的文件列表等隐私信息。

再以公开的乌云漏洞wooyun-2013-039697为例: 

定义了私有权限,但是保护等级设置成为了dangerous或者normal,这样的保护等级对于一些应用的Provide重要性相比保护级低了。

Provider为:

私有权限“com.renren.mobile.android.permission.PERMISSION_ADD_ACCOUNT”的定义为:

反编译客户端,看到AcountProvider对应的实现:

编写POC:

在AndroidManifest中定义和声明权限:

主要代码为:

可看到用户的账户信息,包括uid,手机号,加密后的密码等:

2.2 本地SQL注入

当Content Provider的数据源是SQLite数据库时,如果实现不当,而Provider又是暴露的话,则可能会引发本地SQL注入漏洞。

Content Provider的query( )的方法定义为:

其中参数:

  • uri: 为content Uri,要查询的数据库;
  • projection:为要查询的列名;
  • selection和selectionArgs:要指定查询条件;
  • sortOrder:查询结果如何排序。

query() 与 SQL 查询对比如下:

如果query( )中使用的是拼接字符串组成SQL语句的形式去查询底层的SQLite数据库时,容易发生SQL注入。

以乌云公开漏洞wooyun-2016-0175294为例:

客户端的com.sohu.sohuvideo.provider.PlayHistoryProvider的exported属性为“true”:

反编译客户端,追踪PlayHistoryProvider的实现,发现是用拼接字符串形式构造原始的SQL查询语句:

使用drozer工具,证明漏洞:

2.3 目录遍历漏洞

对外暴露的Content Provider实现了openFile()接口,因此其他有相应调用该Content Provider权限的应用即可调用Content Provider的openFile()接口进行文件数据访问。但是如果没有进行Content Provider访问权限控制和对访问的目标文件的Uri进行有效判断,攻击者利用文件目录遍历可访问任意可读文件,更有甚者可以往手机设备可写目录中写入任意数据。

例子1 以乌云公开漏洞wooyun-2013-044407为例: 

此APP实现中定义了一个可以访问本地文件的Content Provider组件,为com.ganji.android.jobs.html5.LocalFileContentProvider,因为使用了minSdkServison为“8”,targetSdkVersion=”13”,即此Content Provider采用默认的导出配置,即android:exported=”true”:

该Provider实现了openFile()接口:

通过此接口可以访问内部存储app_webview目录下的数据,由于后台未能对目标文件地址进行有效判断,可以通过”../”实现目录遍历,实现对任意私有数据的访问。

例子2 

某社交应用客户端,使用了的minSDKVersion为8,定义了私有权限,并且android:protectionLevel设为了signature

有一个对外暴露的Content Provider,即com.facebook.lite.photo.MediaContentProvider,此Provider没有设置访问权限,而另外一个Provider是设置了访问权限的:

在MediaContentProvider中实现了openFile()接口,没有对传入的URI进行限制和过滤:

此接口本来只想让用户访问照片信息的,但是却可以突破限制,读取其他文件:

POC:

读取到其他文件的内容为:

另外看到Openfile()接口的实现中,如果要访问的文件不存在,就会创建此文件,还有可能的风险就是在应用的目录中写入任意文件。

3 阿里聚安全开发者建议

在进行APP设计时,要清楚哪些Provider的数据是用户隐私数据或者其他重要数据,考虑是否要提供给外部应用使用,如果不需要提供,则在AndroidManifes文件中将其exported属性显式的设为“false”,这样就会减少了很大一部分的攻击面。

人工排查肯定比较麻烦,建议开发者使用阿里聚安全提供的安全扫描服务,在APP上线前进行自动化的安全扫描,尽早发现并规避这样的风险。

注意: 

由于Android组件Content Provider无法在Android 2.2(即API Level 8)系统上设为不导出,因此建议声明最低SDK版本为8以上版本(这已经是好几年前的SDK了,现在一般都会大于此版本);

由于API level 在17以下的所有应用的“android:exported”属性默认值都为true,因此如果应用的Content Provider不必要导出,建议显式设置注册的Content Provider组件的“android:exported”属性为false;

如果必须要有数据提供给外部应用使用,则做好设计,做好权限控制,明确什么样的外部应用可以使用,如对于本公司的应用在权限定义时用相同签名即可,合作方的应用检查其签名;不过还是尽量不提供用户隐私敏感信息。

对于必须暴露的Provider,如第二部分遇到的风险解决办法如下:

3.1 正确的定义私有权限

在AndroidManifest中定义私有权限的语法为:

其中android:protectionLevel的可选值分别表示:

  • normal:默认值,低风险权限,在安装的时候,系统会自动授予权限给 application。
  • dangerous:高风险权限,如发短信,打电话,读写通讯录。使用此protectionLevel来标识用户可能关注的一些权限。Android将会在安装程序时,警示用户关于这些权限的需求,具体的行为可能依据Android版本或者所安装的移动设备而有所变化。
  • signature: 签名权限,在其他 app 引用声明的权限的时候,需要保证两个 app 的签名一致。这样系统就会自动授予权限给第三方 app,而不提示给用户。
  • signatureOrSystem:除了具有相同签名的APP可以访问外,Android系统中的程序有权限访问。

大部分开放的Provider,是提供给本公司的其他应用使用的,一般的话一个公司打包签名APP的签名证书都应该是一致的,这种情况下,Provider的android:protectionLevel应为设为“signature”。

3.2 防止本地SQL注入

注意:一定不要使用拼接来组装SQL语句。

如果Content Provider的数据源是SQLite数据库,如果使用拼接字符串的形式组成原始SQL语句执行,则会导致SQL注入。

如下的选择子句:

如果执行此操作,则会允许用户将恶意 SQL 串连到 SQL 语句上。

例如,用户可以为 mUserInput 输入“nothing; DROP TABLE ** ; ”,这会生成选择子句

var = nothing; DROP TABLE **;

由于选择子句是作为SQL语句处理,因此这可能会导致提供程序擦除基础 SQLite 数据库中的所有表(除非提供程序设置为可捕获 SQL 注入尝试)。

使用参数化查询:

要避免此问题,可使用一个“ ? ” 作为可替换参数的选择子句以及一个单独的选择参数数组。

执行此操作时,用户输入直接受查询约束,而不解释为 SQL 语句的一部分。

由于用户输入未作为 SQL 处理,因此无法注入恶意 SQL。

请使用此选择子句,而不要使用串连来包括用户输入:

String mSelectionClause = “var = ?”;

按如下所示设置选择参数数组:

String[] selectionArgs = {“”};

按如下所示将值置于选择参数数组中:

selectionArgs[0] = mUserInput;

还可调用SQLiteDatabase类中的参数化查询query()方法:

3.3 防止目录遍历

1、去除Content Provider中没有必要的openFile()接口。

2、过滤限制跨域访问,对访问的目标文件的路径进行有效判断:

使用Uri.decode()先对Content Query Uri进行解码后,再过滤如可通过“../”实现任意可读文件的访问的Uri字符串,如:

3.4 通过检测签名来授权合作方应用访问

如果必须给合作方的APP提供Provider的访问权限,而合作方的APP签名证书又于自己公司的不同,可将合作方的APP的签名哈希值预埋在提供Provider的APP中,提供Provider的APP要检查请求访问此Provider的APP的签名,签名匹配通过才让访问。

参考

[1]《内容提供程序基础知识

》 https://developer.android.com/guide/topics/providers/content-provider-basics.html

[2]《Android app端的sql注入》http://zone.wooyun.org/content/15097

[3]《Android - Content Providers》 http://www.tutorialspoint.com/android/android_content_providers.htm

[4] http://www.compiletimeerror.com/2013/12/content-provider-in-android.html

[5] https://developer.android.com/guide/topics/manifest/permission-element.html?hl=zh-cn

[6] https://developer.android.com/guide/topics/manifest/permission-element.html

[7] http://www.wooyun.org/bugs/wooyun-2013-039697

[8] http://www.wooyun.org/bugs/wooyun-2014-057590

[9] 《Android Content Provider Security》http://drops.wooyun.org/tips/4314

[10] http://www.wooyun.org/bugs/wooyun-2016-0175294

[11]《Android Content Provider Security

http://drops.wooyun.org/tips/4314

[12] http://www.wooyun.org/bugs/wooyun-2013-044407

[13] http://www.wooyun.org/bugs/wooyun-2013-044411

[14] 《Content Provider文件目录遍历漏洞浅析》,https://jaq.alibaba.com/blog.htm?id=61

[15] https://github.com/programa-stic/security-advisories/tree/master/FacebookLite

作者:伊樵、呆狐@阿里聚安全,更多安全技术文章,请访问阿里聚安全博客

时间: 2024-11-05 13:43:31

Android安全开发之Provider组件安全的相关文章

Android安全开发之ZIP文件目录遍历

1.ZIP文件目录遍历简介 因为ZIP压缩包文件中允许存在"../"的字符串,攻击者可以利用多个"../"在解压时改变ZIP包中某个文件的存放位置,覆盖掉应用原有的文件.如果被覆盖掉的文件是动态链接so.dex或者odex文件,轻则产生本地拒绝服务漏洞,影响应用的可用性,重则可能造成任意代码执行漏洞,危害用户的设备安全和信息安全.比如近段时间发现的"寄生兽"漏洞.海豚浏览器远程命令执行漏洞.三星默认输入法远程代码执行漏洞等都与ZIP文件目录遍历有

Android快速开发之appBase——(6).HttpReq和APICloudSDK

Android快速开发之appBase--(6).HttpReq和APICloudSDK HttpReq和APICloudSDK都是网络请求组件,都是基于xUtils的HttpUtils重新封装的.接下来讲一下使用方法. 1.HttpReq 看以看到有这么几个方法 GET:GET方式请求 POST:普通的POST表单提交 POST:将数据以流的形式传递 /** * POST请求,用InputStream的方式传递请求参数 * * @param api * 接口地址 * @param reques

Android快速开发之appBase——(1).appBase介绍

Android快速开发之appBase--(1).appBase介绍 一直想写博客,苦于自己的文笔实在不行,在CSDN潜水了好几年,中间差不多3年没有写过博客.原因有二:1.文笔差:2.没时间. 今年开始,时间充裕了,开始计划练练自己的文笔,也让自己成长起来,希望从中能够提升自己的能力.望大家多多支持和关注!! 导读:appBase是什么? appBase是一个Android app开发的基础集合,目的是任何应用都可以在这个基础之上开发app,省去了搭建框架的时间. appBase=xutils

Android快速开发之appBase——(2).万能的Adapter

Android快速开发之appBase--(2).万能的Adapter android的Adapter是常用的一个组件,自定义的adapter基本上都是集成BaseAdapter,然后实现getView等一系列方法.时间长了,难免让人感觉到写的重复性代码过多,那么万能的Adapter讲解放你的双手. 对比 BaseAdapter package com.snicesoft.appbase.demo; import java.util.ArrayList; import java.util.Lis

【Android】Android软件开发之ListView 详解

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://xys289187120.blog.51cto.com/3361352/657171 ListView的使用方法 ListView是Android软件开发中非常重要组件之一,基本上是个软件基本都会使用ListView ,今天我通过一个demo来教大家怎么样使用ListView组件 绘制出漂亮的列表,说道ListView就不得不说Adapter适配器,因为只有通过Adapter才可

Android快速开发之appBase——实战《购物车》

Android快速开发之appBase--实战<购物车> 最近将appBase实战于各种项目中,也发现了不少问题,并优化了很多功能.今天带给大家一个实战–<购物车>.购物车,在商城app中是必不可少的一部分,也是使用的比较多的,这里简单的做一个效果. 先来看看效果图 1.创建项目 第一种.引用appBase项目即可 第二种.将appBase的jar文件copy到libs下 我用的第二种,如上图所示. 2.代码生成 通过代码生成器生成Activity.Presenter.Adapte

Android快速开发之appBase——(3).详解IHolder和IData

Android快速开发之appBase--(3).详解IHolder和IData IHolder和IData是AVLib的两个组件,在前面已经使用过了,那么这一篇将会详细说明这两个组件的用法. IHolder IHolder是AVLib中View自动绑定的组件规范,所有@Id使用只能存在IHolder派生的类中. 源码 package com.snicesoft.avlib.rule; /** * @author zhe * @since 2015年4月15日 上午9:54:17 * @vers

Android 安全开发之 ZIP 文件目录遍历

1.ZIP文件目录遍历简介 因为ZIP压缩包文件中允许存在"../"的字符串,攻击者可以利用多个"../"在解压时改变ZIP包中某个文件的存放位置,覆盖掉应用原有的文件.如果被覆盖掉的文件是动态链接so.dex或者odex文件,轻则产生本地拒绝服务漏洞,影响应用的可用性,重则可能造成任意代码执行漏洞,危害用户的设备安全和信息安全.比如近段时间发现的"寄生兽"漏洞.海豚浏览器远程命令执行漏洞.三星默认输入法远程代码执行漏洞等都与ZIP文件目录遍历有

Android底层开发之Audio HAL

http://blog.csdn.net/kangear/article/details/44939429 Android底层开发之Audio HAL 在Android音频底层调试-基于tinyalsa中以「抛开Android的天生复杂,回归嵌入式Linux的本质」的方式介绍如何调试Linux内核中的音频驱动. 这里向上再伸展一下进入HAL层,看是如何将tinyalsa封装给Frameworks使用的. 基于4.2.2版本源码进行讨论.Android官方教程是Audio Implementing