Android 操作系統(tǒng)內(nèi)置了安全功能漏益,可顯著降低應(yīng)用出現(xiàn)安全問題的頻率及其造成的影響憎乙。系統(tǒng)經(jīng)過精心設(shè)計拟杉,您在通常情況下只需使用默認(rèn)的系統(tǒng)和文件權(quán)限即可打造自己的應(yīng)用,而無需費心針對安全性作出艱難決策文留。
下面是一些可以幫助您打造安全應(yīng)用的核心安全功能:
- Android 應(yīng)用沙盒,可以將您的應(yīng)用數(shù)據(jù)和代碼執(zhí)行與其他應(yīng)用分隔開來竭沫。
- 應(yīng)用框架厂庇,可以穩(wěn)健實現(xiàn)常見的安全性功能,例如加密输吏、權(quán)限和安全 IPC权旷。
- ASLR、NX、ProPolice拄氯、safe_iop躲查、OpenBSD dlmalloc、OpenBSD calloc 和 Linux mmap_min_addr 等多項技術(shù)译柏,可降低與常見內(nèi)存管理錯誤相關(guān)的風(fēng)險镣煮。
- 加密的文件系統(tǒng),啟用后可保護丟失或被盜設(shè)備上的數(shù)據(jù)鄙麦。
- 用戶授予的權(quán)限典唇,可用來限制對系統(tǒng)功能和用戶數(shù)據(jù)的使用。
- 應(yīng)用定義的權(quán)限胯府,可針對各個應(yīng)用分別控制應(yīng)用數(shù)據(jù)介衔。
不過,我們?nèi)越ㄗh您熟悉一下本文檔中所述的 Android 安全性最佳做法骂因。遵循這些最佳做法炎咖,養(yǎng)成常規(guī)編碼習(xí)慣,就可以有效減少因疏忽而引發(fā)安全問題的幾率寒波,防止對用戶產(chǎn)生不利的影響乘盼。
存儲數(shù)據(jù)
對于 Android 應(yīng)用,最常見的安全問題就是其他應(yīng)用能否訪問用戶保存在設(shè)備上的數(shù)據(jù)俄烁。下面介紹了將數(shù)據(jù)保存在設(shè)備上的三種基本方法:
使用內(nèi)部存儲空間
默認(rèn)情況下绸栅,您在內(nèi)部存儲空間中創(chuàng)建的文件僅供您的應(yīng)用訪問。這項保護措施由 Android 實現(xiàn)页屠,而且這對于大多數(shù)應(yīng)用來說足夠了阴幌。
一般情況下,建議您盡量避免將 MODE_WORLD_WRITEABLE或 MODE_WORLD_READABLE模式用于IPC文件卷中,因為在這兩種模式下矛双,系統(tǒng)不提供針對特定應(yīng)用限制數(shù)據(jù)訪問的功能,也不會對數(shù)據(jù)格式進行任何控制蟆豫。如果您想與其他應(yīng)用進程共享數(shù)據(jù)议忽,不妨考慮使用ContentProvider,它可以為其他應(yīng)用提供讀取和寫入權(quán)限十减,還能針對各種具體情況授予動態(tài)權(quán)限栈幸。
要為敏感數(shù)據(jù)提供額外的保護,您可以選擇使用該應(yīng)用無法直接訪問的密鑰來對本地文件進行加密帮辟。例如速址,您可以將密鑰存儲在 KeyStore 中,并使用未存儲在相應(yīng)設(shè)備上的用戶密碼加以保護由驹。不過芍锚,如果攻擊者獲得超級用戶權(quán)限,就可以在用戶輸入密碼時進行監(jiān)控,數(shù)據(jù)也就失去了這層保護屏障并炮;但是默刚,這種方式可以保護丟失設(shè)備上的數(shù)據(jù),而無需進行文件系統(tǒng)加密逃魄。
使用外部存儲設(shè)備
在外部存儲設(shè)備(例如 SD 卡)上創(chuàng)建的文件不受任何讀取和寫入權(quán)限的限制荤西。對于外部存儲設(shè)備中的內(nèi)容,不僅用戶可以將其移除伍俘,而且任何應(yīng)用都可以對其進行修改邪锌,因此最好不要使用外部存儲設(shè)備來存儲敏感信息。
就像處理來源不受信任的數(shù)據(jù)一樣癌瘾,您應(yīng)對外部存儲設(shè)備中的數(shù)據(jù)執(zhí)行輸入驗證觅丰。強烈建議您不要在動態(tài)加載前將可執(zhí)行文件或類文件存儲在外部存儲設(shè)備中。如果您的應(yīng)用確實從外部存儲設(shè)備中檢索可執(zhí)行文件柳弄,請在動態(tài)加載前對這些文件執(zhí)行簽名和加密驗證舶胀。
使用內(nèi)容提供程序
ContentProvider提供結(jié)構(gòu)化存儲機制概说,可以將內(nèi)容限制為僅供自己的應(yīng)用訪問碧注,也可以將內(nèi)容導(dǎo)出以供其他應(yīng)用訪問。如果您不打算向其他應(yīng)用授予訪問您的ContentProvider 的權(quán)限糖赔,請在應(yīng)用清單中將其標(biāo)記為 android:exported=false
萍丐;要允許其他應(yīng)用訪問存儲的數(shù)據(jù),請將 android:exported
屬性設(shè)置為 "true"
放典。
在創(chuàng)建要導(dǎo)出以供其他應(yīng)用使用的 ContentProvider
時逝变,您可以在清單中指定允許讀取和寫入的單一權(quán)限,也可以針對讀取和寫入操作分別指定權(quán)限奋构。我們建議您僅對需要完成相應(yīng)任務(wù)的應(yīng)用授予權(quán)限壳影。請注意,與其移除權(quán)限而影響到現(xiàn)有用戶弥臼,不如以后要使用新功能時再添加權(quán)限宴咧。
如果您要使用內(nèi)容提供程序僅在自己的應(yīng)用之間共享數(shù)據(jù),最好將 android:protectionLevel
屬性設(shè)置為 "signature"
保護級別径缅。簽名權(quán)限不需要用戶確認(rèn)掺栅,因此,這種方式不僅能提升用戶體驗纳猪,而且在相關(guān)應(yīng)用使用相同的密鑰進行簽名來訪問數(shù)據(jù)時氧卧,還能更好地控制對內(nèi)容提供程序數(shù)據(jù)的訪問。
內(nèi)容提供程序還可以通過以下方式提供更細(xì)化的訪問權(quán)限:聲明 android:grantUriPermissions
屬性氏堤,并使用用來啟動組件的 Intent 對象中的 FLAG_GRANT_READ_URI_PERMISSION
標(biāo)記沙绝。使用 <grant-uri-permission element>
還能進一步限制這些權(quán)限的范圍。
訪問內(nèi)容提供程序時,請使用參數(shù)化的查詢方法(例如 query())
宿饱、update()
和 delete()
)熏瞄,以免產(chǎn)生來源不受信任的 SQL 注入風(fēng)險。請注意谬以,如果以組合用戶數(shù)據(jù)的方式構(gòu)建 selection
參數(shù)强饮,然后再將其提交至參數(shù)化方法,則使用參數(shù)化方法可能不夠安全为黎。
請不要誤以為提供寫入權(quán)限很安全邮丰。設(shè)想一下,寫入權(quán)限允許使用 SQL 語句铭乾,這使得攻擊者可以通過使用各種 WHERE
子句以及對相關(guān)結(jié)果進行解析來確認(rèn)某些數(shù)據(jù)剪廉。例如,如果攻擊者想要探查通話記錄中是否存在某個特定電話號碼炕檩,只要該號碼已經(jīng)存在斗蒋,攻擊者就可以通過修改其中的一行來獲知。如果內(nèi)容提供程序數(shù)據(jù)采用可預(yù)測的結(jié)構(gòu)笛质,那么授予寫入權(quán)限相當(dāng)于同時提供了讀取和寫入權(quán)限泉沾。
使用權(quán)限
由于 Android 通過沙盒機制管理各個應(yīng)用,因此應(yīng)用必須以明確的方式共享資源和數(shù)據(jù)妇押。應(yīng)用會通過聲明自己需要的權(quán)限來獲取基本沙盒未提供的額外功能(包括對相機等設(shè)備功能的訪問權(quán)限)跷究,從而實現(xiàn)這一點。
請求權(quán)限
我們建議您盡量減少應(yīng)用請求的權(quán)限敲霍。如果不具備對敏感數(shù)據(jù)的訪問權(quán)限俊马,就能降低不慎誤用這類權(quán)限的風(fēng)險,并可提高用戶的采用率肩杈,同時讓您的應(yīng)用不那么容易受到攻擊者的攻擊柴我。一般來說,如果您的應(yīng)用無需某項權(quán)限也能正常運行扩然,就不要請求該權(quán)限艘儒。
如果可以采用不需要任何權(quán)限的方式設(shè)計應(yīng)用,建議采用這種方式与学。例如彤悔,與其請求訪問設(shè)備信息的權(quán)限以創(chuàng)建唯一標(biāo)識符,不如為您的應(yīng)用創(chuàng)建一個 GUID(請參閱處理用戶數(shù)據(jù)的相關(guān)部分)索守≡我ぃ或者,您也可以不將數(shù)據(jù)存儲在外部存儲設(shè)備(需要請求權(quán)限)卵佛,而將其存儲在內(nèi)部存儲空間杨赤。
除了請求權(quán)限之外敞斋,您的應(yīng)用也可以使用 <permissions>
來保護對安全性要求較高且會被其他應(yīng)用訪問的 IPC,例如 ContentProvider
疾牲。一般而言植捎,我們建議您盡量使用訪問權(quán)限控制,而不使用需要用戶確認(rèn)的權(quán)限阳柔,因為權(quán)限管理對用戶來說可能比較復(fù)雜焰枢。例如,對于同一開發(fā)者提供的不同應(yīng)用之間的 IPC 通信舌剂,不妨使用 "signature" 保護級別济锄。
請勿泄露受權(quán)限保護的數(shù)據(jù)。當(dāng)您的應(yīng)用通過 IPC 傳輸數(shù)據(jù)時可能會出現(xiàn)泄漏霍转,不過荐绝,只有您的應(yīng)用擁有特定權(quán)限時,才可能發(fā)生數(shù)據(jù)泄漏避消。應(yīng)用 IPC 接口的客戶端可能沒有相同的數(shù)據(jù)訪問權(quán)限低滩。要詳細(xì)了解潛在影響以及這類問題發(fā)生的頻率,請參閱在 USENIX 上發(fā)布的這篇研究論文岩喷。
創(chuàng)建權(quán)限
一般來說恕沫,您應(yīng)在滿足安全性要求的前提下盡可能少定義權(quán)限。對于大多數(shù)應(yīng)用來說均驶,它們很少會創(chuàng)建新權(quán)限昏兆,因為系統(tǒng)定義的權(quán)限就能滿足大部分的需求枫虏。請視需要使用現(xiàn)有權(quán)限執(zhí)行訪問權(quán)限檢查妇穴。
如果必須創(chuàng)建新權(quán)限,請盡量考慮創(chuàng)建 "signature" 保護級別的權(quán)限隶债√谒“簽名”級別權(quán)限的內(nèi)容對用戶完全透明開放,而且只有由執(zhí)行權(quán)限檢查的應(yīng)用的開發(fā)者簽名的應(yīng)用才可訪問這些內(nèi)容死讹。
如果您創(chuàng)建了 "dangerous" 保護級別的權(quán)限瞒滴,則事情就會更加復(fù)雜,您需要注意:
- 該權(quán)限必須包含一個字符串赞警,向用戶清楚明確地說明他們需要做出的安全決策妓忍。
- 該權(quán)限的字符串必須翻譯成多種不同語言。
- 用戶可能會因為權(quán)限含糊不清或存在風(fēng)險而選擇不安裝應(yīng)用愧旦。
- 應(yīng)用可能會在權(quán)限創(chuàng)建程序尚未安裝的情況下請求權(quán)限世剖。
這些事情會給開發(fā)者帶來巨大的非技術(shù)性挑戰(zhàn),也讓用戶感到困惑笤虫,因此我們不鼓勵使用 "dangerous" 權(quán)限級別旁瘫。
使用網(wǎng)絡(luò)
網(wǎng)絡(luò)交易涉及傳輸對用戶而言可能比較私密的數(shù)據(jù)祖凫,因此本質(zhì)上就存在安全風(fēng)險。用戶開始逐漸意識到移動設(shè)備存在的隱私泄漏問題酬凳,尤其是在通過設(shè)備進行網(wǎng)絡(luò)交易時惠况。因此,請務(wù)必對您的應(yīng)用采取各種最佳做法宁仔,以始終確保用戶的數(shù)據(jù)安全稠屠。
使用 IP 網(wǎng)絡(luò)
Android 網(wǎng)絡(luò)運行機制與其他 Linux 環(huán)境差別不大,關(guān)鍵是確保對敏感數(shù)據(jù)使用合適的協(xié)議翎苫,如使用 HttpsURLConnection
來保證網(wǎng)絡(luò)流量安全完箩。我們建議您在服務(wù)器支持 HTTPS 的情況下一律使用 HTTPS(而非 HTTP),因為移動設(shè)備經(jīng)常會連接到不安全的網(wǎng)絡(luò)(如公共 WLAN 熱點)拉队。
您可以使用 SSLSocket
類輕松實現(xiàn)經(jīng)過身份驗證和加密的套接字層通信弊知。考慮到 Android 設(shè)備會頻繁使用 WLAN 連接到不安全的無線網(wǎng)絡(luò)粱快,我們強烈建議所有通過網(wǎng)絡(luò)通信的應(yīng)用使用安全的網(wǎng)絡(luò)秩彤。
我們發(fā)現(xiàn)有些應(yīng)用使用 localhost 網(wǎng)絡(luò)端口處理敏感的 IPC。我們不建議采用這種方法事哭,因為設(shè)備上的其他應(yīng)用也可以訪問這些接口漫雷。相反,您應(yīng)該使用可通過 Service
等進行身份驗證的 Android IPC 機制鳍咱。(綁定到 INADDR_ANY 比使用回送功能還要糟糕降盹,因為這樣一來,您的應(yīng)用可能會收到任何位置發(fā)來的請求谤辜。)
此外蓄坏,還有一個需要再三強調(diào)的常見問題就是,切勿相信通過 HTTP 或其他非安全協(xié)議下載的數(shù)據(jù)丑念,包括 WebView
中的輸入驗證以及對通過 HTTP 發(fā)出的 intent 的任何響應(yīng)涡戳。
使用電話網(wǎng)絡(luò)
短信協(xié)議主要是為用戶間通信設(shè)計的,并不適合要傳輸數(shù)據(jù)的應(yīng)用脯倚∮嬲茫考慮到短信的局限性,因此推正,想從網(wǎng)絡(luò)服務(wù)器向用戶設(shè)備上安裝的應(yīng)用發(fā)送數(shù)據(jù)消息時恍涂,我們強烈建議您使用Google 云消息傳遞(GCM) 和 IP 網(wǎng)絡(luò)。
請注意植榕,短信在網(wǎng)絡(luò)上和設(shè)備上均未經(jīng)過加密再沧,也沒有經(jīng)過嚴(yán)格的身份驗證。而且内贮,短信的所有接收者都應(yīng)明白产园,您的應(yīng)用收到的短信可能來自惡意用戶汞斧。因此,切勿使用未經(jīng)身份驗證的短信數(shù)據(jù)執(zhí)行敏感命令什燕。還需要注意的是粘勒,短信可能包含欺騙性內(nèi)容,也有可能在網(wǎng)絡(luò)上傳輸時被攔截屎即。在 Android 設(shè)備上庙睡,短信會以廣播 intent 的形式傳輸,因此可能會被其他擁有 READ_SMS
權(quán)限的應(yīng)用讀取或捕獲技俐。
執(zhí)行輸入驗證
無論應(yīng)用是在哪種平臺上運行乘陪,輸入驗證功能不完善都是影響應(yīng)用的最常見安全問題。Android 為此提供了平臺級對策雕擂,可降低應(yīng)用出現(xiàn)輸入驗證問題的可能性啡邑。如果可行,請盡量使用這些功能井赌。另請注意谤逼,選擇類型安全的語言通常也有助于降低出現(xiàn)輸入驗證問題的可能性。
如果使用原生代碼仇穗,那么系統(tǒng)從文件讀取流部、通過網(wǎng)絡(luò)接收或從 IPC 接收的任何數(shù)據(jù)都有可能會引發(fā)安全問題。最常見的問題包括緩沖區(qū)溢出纹坐、釋放后重用和差一錯誤枝冀。Android 為此提供了多項技術(shù),例如 ASLR和 DEP耘子,可以降低這些錯誤被利用的可能性果漾,但無法解決根本問題。因此拴还,請謹(jǐn)慎管理指針和緩沖區(qū)跨晴,預(yù)防這些漏洞造成破壞欧聘。
使用基于字符串的動態(tài)語言(如 JavaScript 和 SQL)也可能因為轉(zhuǎn)義字符和腳本注入而出現(xiàn)輸入驗證問題片林。
如果使用提交到 SQL 數(shù)據(jù)庫或內(nèi)容提供程序的查詢中的數(shù)據(jù),也可能出現(xiàn) SQL 注入問題怀骤。最好的預(yù)防措施是使用參數(shù)化查詢(請參閱上文內(nèi)容提供程序部分的相關(guān)內(nèi)容)费封。將權(quán)限限制為只讀或只寫,也可以降低 SQL 注入引發(fā)破壞的可能性蒋伦。
如果您無法使用上述安全功能弓摘,我們強烈建議您使用結(jié)構(gòu)合理的數(shù)據(jù)格式,并驗證數(shù)據(jù)是否符合預(yù)期的格式痕届。雖然將字符列入黑名單或替換字符是一種有效的策略韧献,但這些技術(shù)在實際操作中很容易出錯末患,因此應(yīng)盡量避免使用。
處理用戶數(shù)據(jù)
通常情況下锤窑,確保用戶數(shù)據(jù)安全的最佳做法是盡量避免使用會訪問用戶敏感數(shù)據(jù)或個人數(shù)據(jù)的 API璧针。如果您擁有用戶數(shù)據(jù)的訪問權(quán)限,并且能夠避免存儲或傳輸這些信息渊啰,那么就不要存儲或傳輸這些數(shù)據(jù)探橱。最后,請評估您的應(yīng)用邏輯能否使用經(jīng)過哈希算法處理或不可逆的數(shù)據(jù)格式進行實現(xiàn)绘证。例如隧膏,您的應(yīng)用可能會使用電子郵件地址的哈希值作為主要密鑰,以避免傳輸或存儲電子郵件地址嚷那。這樣可降低在無意之中泄露數(shù)據(jù)的可能性胞枕,還可以降低攻擊者嘗試?yán)媚膽?yīng)用搞破壞的可能性。
請注意魏宽,如果您的應(yīng)用會訪問密碼或用戶名等個人信息曲稼,部分司法轄區(qū)可能會要求您提供隱私權(quán)政策,以說明您如何使用或存儲這類數(shù)據(jù)湖员。因此贫悄,遵循安全最佳做法(即盡可能減少對用戶數(shù)據(jù)的訪問)也有助于簡化合規(guī)工作。
此外娘摔,您還應(yīng)考慮自己的應(yīng)用是否會在無意之中將個人信息泄露給其他方窄坦,如廣告使用的第三方組件或應(yīng)用使用的第三方服務(wù)。如果不知道某個組件或服務(wù)為什么需要個人信息凳寺,就不要提供個人信息鸭津。通常,減少您的應(yīng)用對個人信息的訪問肠缨,可以降低引發(fā)這方面問題的可能性逆趋。
如果必須訪問敏感數(shù)據(jù),請判斷這些信息是必須傳輸至服務(wù)器晒奕,還是可以在客戶端上執(zhí)行相應(yīng)操作闻书。建議您在客戶端上運行所有需要使用敏感數(shù)據(jù)的代碼,以避免傳輸用戶數(shù)據(jù)脑慧。
此外魄眉,請務(wù)必不要使用權(quán)限過于寬松的 IPC、完全沒有寫入限制的文件或網(wǎng)絡(luò)套接字闷袒,避免在無意之中將用戶數(shù)據(jù)泄露給設(shè)備上的其他應(yīng)用坑律。這屬于一種造成受權(quán)限保護的數(shù)據(jù)遭泄露的特殊情況,我們已在請求權(quán)限部分討論過囊骤。
如果需要GUI 晃择,請創(chuàng)建一個較長的具有唯一性的編號并加以存儲冀值。請勿使用可能與個人信息關(guān)聯(lián)的電話標(biāo)識符,如電話號碼或 IMEI宫屠。有關(guān)此主題的詳情池摧,請參閱 Android 開發(fā)者博客。
向設(shè)備上的日志寫入內(nèi)容時激况,請務(wù)必謹(jǐn)慎小心作彤。在 Android 中,日志是共享資源乌逐,擁有 READ_LOGS
權(quán)限的所有應(yīng)用均可訪問竭讳。即使電話日志數(shù)據(jù)是臨時數(shù)據(jù)并會在重新啟動時清空,不當(dāng)記錄用戶信息也可能在無意之中將用戶數(shù)據(jù)泄露給其他應(yīng)用浙踢。
使用 WebView
由于 WebView
使用的網(wǎng)絡(luò)內(nèi)容可能包含 HTML 和 JavaScript绢慢,當(dāng)?shù)氖褂每赡芤氤R姷木W(wǎng)絡(luò)安全問題,例如跨站腳本攻擊(JavaScript 注入)洛波。Android 內(nèi)置了多種機制胰舆,可將 WebView
的功能限制為您應(yīng)用所需的最低功能,以縮小這些潛在問題的影響范圍蹬挤。
如果您的應(yīng)用不直接使用 WebView
中的 JavaScript缚窿,請勿調(diào)用 setJavaScriptEnabled()
。部分示例代碼會使用這種方法倦零,不過您可能需要在實際應(yīng)用時根據(jù)具體情況進行調(diào)整吨悍。因此,如果不需要使用這種調(diào)用方法育瓜,請將其移除葫隙。默認(rèn)情況下躏仇,WebView
不會執(zhí)行 JavaScript,因此不可能出現(xiàn)跨站腳本攻擊這樣的安全問題钙态。
addJavaScriptInterface()
允許 JavaScript 調(diào)用正常情況下是為 Android 應(yīng)用預(yù)留的操作慧起,因此在使用時請格外小心。如果要使用,請僅將 addJavaScriptInterface()
用于所有輸入內(nèi)容都可信的網(wǎng)頁驻子。如果您接受不受信任的輸入內(nèi)容,那么不受信任的 JavaScript 可能會調(diào)用您應(yīng)用中的 Android 方法缤剧。一般情況下域慷,我們建議您僅將 addJavaScriptInterface()
用于應(yīng)用 APK 內(nèi)含的 JavaScript。
如果您的應(yīng)用通過 WebView
訪問敏感數(shù)據(jù)抵窒,您可能需要使用 clearCache()
方法來刪除本地存儲的所有文件李皇。您也可以使用服務(wù)器端標(biāo)頭(例如 no-cache
)來指示應(yīng)用不應(yīng)緩存特定內(nèi)容宙枷。
在 Android 4.4(API 級別 19)之前平臺上運行的設(shè)備使用的 webkit
版本存在多個安全問題。如果您的應(yīng)用在這些設(shè)備上運行卓囚,解決方法是確認(rèn) WebView
對象只顯示值得信任的內(nèi)容捍岳。還應(yīng)使用可更新的安全 Provider
對象確保您的應(yīng)用在 SSL 中不會暴露給潛在的漏洞睬隶,如更新您的安全提供程序以防范 SSL 攻擊中所述。如果您的應(yīng)用必須從開放網(wǎng)絡(luò)渲染內(nèi)容银萍,請考慮提供您自己的渲染程序贴唇,以便使用最新的安全補丁程序保持其處于最新狀態(tài)飞袋。
處理憑據(jù)
一般情況下,我們建議您盡量降低要求用戶憑據(jù)的頻率瓶您;這樣會讓釣魚攻擊顯得比較可疑呀袱,從而能夠降低其成功率。作為替代方法夜赵,您可以使用授權(quán)令牌并根據(jù)需要刷新。
請盡量避免將用戶名和密碼存儲在設(shè)備上摊腋。您可以使用用戶提供的用戶名和密碼進行初始身份驗證兴蒸,然后使用針對特定服務(wù)的短時效授權(quán)令牌心包。
可供多個應(yīng)用訪問的服務(wù)應(yīng)使用 AccountManager
進行訪問蟹腾。如果可行,請使用 AccountManager
類來調(diào)用基于云的服務(wù)值戳;此外炉爆,請勿將密碼存儲在設(shè)備上芬首。
使用 AccountManager
檢索 Account
后,請先確認(rèn) CREATOR
再傳送憑據(jù)赦政,以免無意中將憑據(jù)傳送給錯誤的應(yīng)用恢着。
如果憑據(jù)僅供您創(chuàng)建的應(yīng)用使用财破,那么您可以使用 checkSignature()
驗證訪問 AccountManager
的應(yīng)用。另外靡羡,如果只有一個應(yīng)用使用該憑據(jù)亿眠,那么您可以使用 KeyStore
存儲憑據(jù)磅废。
使用加密
Android 不僅提供數(shù)據(jù)隔離機制拯勉、支持完整文件系統(tǒng)加密并提供安全通信通道,還提供大量使用加密來保護數(shù)據(jù)的算法岔帽。
一般情況下犀勒,請嘗試根據(jù)您的具體情況使用已經(jīng)實現(xiàn)的最高級別的框架妥曲。如果您需要從某個已知位置安全地檢索文件檐盟,使用簡單的 HTTPS URI 即可滿足需要,無需具備加密知識导犹。如果您需要一個安全通道羡忘,不妨考慮使用 HttpsURLConnection
或 SSLSocket
卷雕,而無需自行編寫協(xié)議。
如果您需要實現(xiàn)自己的協(xié)議沐批,我們強烈建議您不要實現(xiàn)自己的加密算法九孩。請使用現(xiàn)有加密算法发框,例如 Cipher
類中提供的 AES 或 RSA 實現(xiàn)中的算法。
使用安全隨機數(shù)生成器 SecureRandom
初始化任意加密密鑰 KeyGenerator
宪拥。如果使用的密鑰不是安全隨機數(shù)生成器生成的她君,那么會顯著降低算法的強度,容易導(dǎo)致出現(xiàn)離線攻擊球涛。
如果您需要存儲密鑰以供重復(fù)使用亿扁,請使用 KeyStore
等可以長期存儲和檢索加密密鑰的機制鸟廓。
使用進程間通信
部分應(yīng)用會嘗試使用傳統(tǒng) Linux 技術(shù)(如網(wǎng)絡(luò)套接字和共享文件)來實現(xiàn) IPC引谜。強烈建議您改為使用 Android 針對 IPC 提供的系統(tǒng)功能,例如使用 Service
的 Intent
呐赡、Binder或
Messenger链嘀,以及
BroadcastReceiver`档玻。Android IPC 機制讓您驗證連接至 IPC 的應(yīng)用的身份误趴,并為每種 IPC 機制設(shè)置安全策略凉当。
許多安全元素在各種 IPC 機制之間是共享的。如果您的 IPC 機制并不打算讓其他應(yīng)用使用忠藤,請在該組件的清單元素(例如 <service>
元素)中將 android:exported
屬性設(shè)置為 "false"
模孩。對于同一 UID 中包含多項進程的應(yīng)用,這種做法非常有用介却;當(dāng)您在以后的開發(fā)過程中決定不以 IPC 的形式提供功能但又不想重新編寫代碼時齿坷,這樣做也會有所助益龟劲。
如果您的 IPC 預(yù)期供其他應(yīng)用訪問轴或,您可以使用 <permission>
元素應(yīng)用安全策略照雁。如果 IPC 是在您自己的不同應(yīng)用(以同一密鑰登錄)之間使用饺蚊,建議您在 android:protectionLevel
中使用 "signature"
級別權(quán)限。
使用 Intent
Intent 是 Android 中異步 IPC 的首選機制裕坊。根據(jù)您的應(yīng)用要求籍凝,您可能會對特定的應(yīng)用組件使用 sendBroadcast()
苗缩、sendOrderedBroadcast()
或顯式 intent酱讶。
請注意,排序后的廣播可能會被接收者“占用”渊迁,因此它們可能不會傳遞到所有應(yīng)用琉朽。如果您要發(fā)送必須傳遞到特定接收者的 intent膏萧,那么必須使用以 nameintent 聲明接收者的顯式 intent。
Intent 的發(fā)送器會驗證接收者是否有權(quán)通過方法調(diào)用來指定非空權(quán)限噩斟。只有具有該權(quán)限的應(yīng)用才會收到 intent孤个。如果廣播 intent 中的數(shù)據(jù)屬于敏感數(shù)據(jù)齐鲤,則不妨考慮應(yīng)用相應(yīng)權(quán)限给郊,以確保惡意應(yīng)用在沒有相應(yīng)權(quán)限的情況下無法注冊以接收這些消息。在這些情況下统锤,您還可以考慮直接調(diào)用接收器饲窿,而不是發(fā)起廣播焕蹄。
注:請勿將 intent 過濾條件視為安全功能 - 組件可通過顯式 intent 調(diào)用腻脏,但不一定擁有符合 intent 過濾條件的數(shù)據(jù)迹卢。您需要在 intent 接收器中執(zhí)行輸入驗證,以確認(rèn) intent 的格式正確無誤誊垢,可用于調(diào)用的接收器喂走、服務(wù)或 Activity谋作。
使用服務(wù)
Service
通常用于提供其他應(yīng)用要使用的功能遵蚜。每個服務(wù)類在其清單文件中都必須有相應(yīng)的 <service>
聲明坛吁。
默認(rèn)情況下,服務(wù)不會被導(dǎo)出蹋盆,而且無法由任何其他應(yīng)用調(diào)用柒爵。不過庶柿,如果您將任何 intent 過濾條件添加到服務(wù)聲明中浮庐,那么默認(rèn)就會導(dǎo)出該服務(wù)兼呵。最好是明確聲明 android:exported
屬性击喂,以確保其行為符合您的需要懂昂。您也可以使用 android:permission
屬性來保護服務(wù)没宾。這樣一來循衰,其他應(yīng)用只有在自己的清單中聲明相應(yīng)的 <uses-permission>
元素会钝,才能啟動、停止或綁定到服務(wù)先鱼。
服務(wù)可以先調(diào)用 checkCallingPermission()
焙畔,然后再實現(xiàn)該調(diào)用串远,從而保護針對該服務(wù)、擁有相應(yīng)權(quán)限的各個 IPC 調(diào)用姥闪。通常情況下筐喳,我們建議您在清單中使用聲明式權(quán)限函喉,因為這些權(quán)限不容易被忽略管呵。
使用 Binder 和 Messenger 接口
使用 Binder
或 Messenger
是 Android 中 RPC 式 IPC 的首選機制捐下。它們提供了定義完善的接口坷襟,可讓端點互相進行身份驗證(如果需要)。
我們強烈建議您在設(shè)計接口時廓奕,采取無需針對接口進行特定權(quán)限檢查的方式桌粉。應(yīng)用清單中并未聲明 Binde
和 Messenger
對象铃肯,因此您無法向這些對象直接應(yīng)用聲明式權(quán)限传蹈。一般情況下卡睦,如果您在 Service
或 Activity
中實現(xiàn)了這些對象表锻,那么它們會繼承 Service 或 Activity 的應(yīng)用清單中聲明的權(quán)限。如果您要創(chuàng)建一個需要身份驗證和/或訪問控件的接口显歧,則這些控件必須以代碼的形式明確添加到 Binde
或 Messenger
接口中士骤。
如果您提供的接口確實需要訪問控件拷肌,請使用 checkCallingPermission()
驗證調(diào)用者是否具備所需權(quán)限巨缘。在代表調(diào)用者訪問服務(wù)前,請務(wù)必執(zhí)行此操作搁骑,因為您應(yīng)用的身份會傳遞到其他接口仲器。如果您調(diào)用的是 Service
提供的接口乏冀,在沒有訪問指定服務(wù)的權(quán)限的情況下煤辨,bindService
調(diào)用可能會失敗木张。如果您調(diào)用的是自己的應(yīng)用提供的本地接口舷礼,不妨使用 clearCallingIdentity()
來確保滿足內(nèi)部安全檢查的要求妻献。
使用廣播接收器
BroadcastReceiver
會處理 Intent
發(fā)起的異步請求育拨。
默認(rèn)情況下熬丧,接收器會被導(dǎo)出怀挠,而且可以由任何其他應(yīng)用調(diào)用。如果您的 BroadcastReceiver
預(yù)期供其他應(yīng)用使用尝盼,您可能需要使用應(yīng)用清單中的 <receiver>
元素向接收器應(yīng)用安全權(quán)限盾沫。這樣可防止沒有相應(yīng)權(quán)限的應(yīng)用向 BroadcastReceiver
發(fā)送 intent赴精。
動態(tài)加載代碼
我們強烈建議您不要從應(yīng)用 APK 外部加載代碼祖娘。這樣做不僅會明顯加大應(yīng)用因代碼注入或代碼篡改產(chǎn)生問題的可能性渐苏,還會增加版本管理和應(yīng)用測試的難度菇夸。這最終會導(dǎo)致無法驗證應(yīng)用的行為庄新,因此择诈,某些環(huán)境中可能會禁止采用此做法羞芍。
如果您的應(yīng)用會動態(tài)加載代碼荷科,您務(wù)必謹(jǐn)記,運行動態(tài)加載的代碼需要擁有與應(yīng)用 APK 相同的安全權(quán)限胆胰。用戶是因為您才決定安裝您的應(yīng)用的蜀涨,因此他們希望您提供的是在您的應(yīng)用內(nèi)運行的代碼勉盅,包括動態(tài)加載的代碼草娜。
與動態(tài)加載代碼相關(guān)的主要安全風(fēng)險與這樣的代碼需要來自可驗證的來源有關(guān)宰闰。如果這些模塊已直接納入您的 APK 中,那么其他應(yīng)用就無法對其進行修改移袍;無論代碼是原生庫代碼還是使用 DexClassLoader
加載的類解藻,均是如此。我們見過很多應(yīng)用嘗試從不安全的位置(例如葡盗,通過未加密的協(xié)議從網(wǎng)絡(luò)上進行下載)或任何人都可寫入內(nèi)容的位置(如外部存儲設(shè)備)加載代碼的例子螟左;對于前一種位置,網(wǎng)絡(luò)上的用戶將可以修改正在傳輸?shù)膬?nèi)容觅够,對于后一種位置胶背,用戶設(shè)備上的其他應(yīng)用將可以修改設(shè)備上的內(nèi)容喘先。
虛擬機中的安全性
Dalvik 是 Android 的運行時虛擬機 (VM)钳吟。雖然 Dalvik 是專為 Android 而設(shè)計的,但是其他虛擬機中遇到的很多安全代碼問題在 Android 中也會出現(xiàn)窘拯。一般情況下红且,您無需擔(dān)心有關(guān)虛擬機的安全問題。您的應(yīng)用在安全的沙盒環(huán)境中運行涤姊,因此系統(tǒng)中的其他進程無法訪問您的代碼或隱私數(shù)據(jù)暇番。
如果希望深入了解虛擬機安全性,建議您研讀有關(guān)這方面的一些現(xiàn)有文獻思喊。下面是兩種比較受歡迎的資源:
本文將重點說明 Android 特有或不同于其他虛擬機環(huán)境的方面奔誓。對于熟悉在其他環(huán)境中進行虛擬機編程的開發(fā)者,需要注意為 Android 編寫應(yīng)用的兩大不同之處:
- 有些虛擬機(例如 JVM 或 .net 運行時)會充當(dāng)安全邊界搔涝,將代碼與基本操作系統(tǒng)功能分隔開來。在 Android 上和措,Dalvik 虛擬機不起安全邊界的作用 — 應(yīng)用沙盒是在操作系統(tǒng)級別進行實現(xiàn)的庄呈,因此 Dalvik 可與同一應(yīng)用中的原生代碼進行互操作,沒有安全限制派阱。
- 鑒于移動設(shè)備上的存儲空間有限诬留,開發(fā)者一般希望開發(fā)模塊化應(yīng)用并使用動態(tài)類加載。這樣做時,請同時考慮您檢索應(yīng)用邏輯的來源以及您在本地存儲應(yīng)用邏輯的位置文兑。請勿使用從未經(jīng)驗證的來源(如不安全的網(wǎng)絡(luò)來源或外部存儲設(shè)備)加載的動態(tài)類盒刚,因為這類代碼可能遭到篡改,從而執(zhí)行某些惡意操作绿贞。
原生代碼中的安全性
一般情況下因块,我們鼓勵開發(fā)者使用 Android SDK 來開發(fā)應(yīng)用,而不要使用 Android NDK 編寫原生代碼籍铁。通過原生代碼開發(fā)的應(yīng)用比較復(fù)雜涡上、可移植性較差,并且很可能會出現(xiàn)常見的內(nèi)存損壞錯誤拒名,如緩沖區(qū)溢出吩愧。
Android 使用 Linux 內(nèi)核構(gòu)建而成。如果您要使用原生代碼增显,熟悉一下 Linux 開發(fā)安全最佳做法會非常有用雁佳。本文中沒有介紹 Linux 安全做法,不過您可以查閱非常受歡迎的《Secure Programming for Linux and Unix HOWTO》同云,網(wǎng)址為 http://www.dwheeler.com/secure-programs糖权。
Android 與大多數(shù) Linux 環(huán)境之間的一個重要區(qū)別在于應(yīng)用沙盒。在 Android 上梢杭,所有應(yīng)用都在應(yīng)用沙盒中運行温兼,包括那些采用原生代碼編寫的應(yīng)用。對于熟悉 Linux 的開發(fā)者而言武契,其本質(zhì)完全可以匯總成一句話:每個應(yīng)用都被賦予唯一的 UID和非常有限的權(quán)限募判。這樣就很好理解了。此外咒唆,即使您使用的是原生代碼届垫,也最好熟悉各種應(yīng)用權(quán)限。