Android安全開發之Provider組件安全

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

1 Content Provider組件簡介

Content Provider組件是Android應用的重要組件之一,管理對數據的訪問,主要用於不一樣的應用程序之間實現數據共享的功能。Content Provider的數據源不止包括SQLite數據庫,還能夠是文件數據。經過將數據儲存層和應用層分離,Content Provider爲各類數據源提供了一個通用的接口。
圖片描述html5

建立一個本身的Content Provider須要繼承自ContentProvider抽象類,須要重寫其中的onCreate()、query()、insert()、update()、delete()、getType()六個抽象方法,這些方法實現對底層數據源的增刪改查等操做。還需在AndroidManifest文件註冊Content Provider,註冊時指定訪問權限、exported屬性、authority屬性值等。
圖片描述android

其它APP使用ContentResolver對象來查詢和操做Content Provider,此對象具備Content Provider中同名的方法名。這樣其餘APP接就能夠訪問Content Provider對應的數據源的底層數據,而無須知道數據的結構或實現。
如何定位到具體的數據?
採用Content Uri,一個Content Uri以下所示:git

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

它的組成通常分爲三部分:
1) content://:做爲 content Uri的特殊標識(必須);
2) 權(authority):用於惟一標識這個Content Provider,外部訪問者能夠根據這個標識找到它;在AndroidManifest中也配置的有;
3) 路徑(path): 所須要訪問數據的路徑,根據業務而定。github

這些內容就不具體展開詳談了,詳見參考1web

2 風險簡介

若是在AndroidManifest文件中將某個Content Provider的exported屬性設置爲true,則多了一個攻擊該APP的攻擊點。若是此Content Provider的實現有問題,則可能產生任意數據訪問、SQL注入、目錄遍歷等風險。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 防止目錄遍歷

一、去除Content Provider中沒有必要的openFile()接口。
二、過濾限制跨域訪問,對訪問的目標文件的路徑進行有效判斷:
使用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

做者:伊樵、呆狐@阿里聚安全,更多安全技術文章,請訪問阿里聚安全博客

相關文章
相關標籤/搜索