Android 應(yīng)用的安全總結(jié)

Android 操作系統(tǒng)內(nèi)置了安全功能,可顯著降低應(yīng)用出現(xiàn)安全問(wèn)題的頻率及其造成的影響。系統(tǒng)經(jīng)過(guò)精心設(shè)計(jì),您在通常情況下只需使用默認(rèn)的系統(tǒng)和文件權(quán)限即可打造自己的應(yīng)用,而無(wú)需費(fèi)心針對(duì)安全性作出艱難決策。

下面是一些可以幫助您打造安全應(yīng)用的核心安全功能:

  • Android 應(yīng)用沙盒,可以將您的應(yīng)用數(shù)據(jù)和代碼執(zhí)行與其他應(yīng)用分隔開(kāi)來(lái)。
  • 應(yīng)用框架,可以穩(wěn)健實(shí)現(xiàn)常見(jiàn)的安全性功能,例如加密、權(quán)限和安全 IPC。
  • ASLR、NX、ProPolice、safe_iop、OpenBSD dlmalloc、OpenBSD calloc 和 Linux mmap_min_addr 等多項(xiàng)技術(shù),可降低與常見(jiàn)內(nèi)存管理錯(cuò)誤相關(guān)的風(fēng)險(xiǎn)。
  • 加密的文件系統(tǒng),啟用后可保護(hù)丟失或被盜設(shè)備上的數(shù)據(jù)。
  • 用戶(hù)授予的權(quán)限,可用來(lái)限制對(duì)系統(tǒng)功能和用戶(hù)數(shù)據(jù)的使用。
  • 應(yīng)用定義的權(quán)限,可針對(duì)各個(gè)應(yīng)用分別控制應(yīng)用數(shù)據(jù)。

不過(guò),我們?nèi)越ㄗh您熟悉一下本文檔中所述的 Android 安全性最佳做法。遵循這些最佳做法,養(yǎng)成常規(guī)編碼習(xí)慣,就可以有效減少因疏忽而引發(fā)安全問(wèn)題的幾率,防止對(duì)用戶(hù)產(chǎn)生不利的影響。

存儲(chǔ)數(shù)據(jù)

對(duì)于 Android 應(yīng)用,最常見(jiàn)的安全問(wèn)題就是其他應(yīng)用能否訪(fǎng)問(wèn)用戶(hù)保存在設(shè)備上的數(shù)據(jù)。下面介紹了將數(shù)據(jù)保存在設(shè)備上的三種基本方法:

使用內(nèi)部存儲(chǔ)空間

默認(rèn)情況下,您在內(nèi)部存儲(chǔ)空間中創(chuàng)建的文件僅供您的應(yīng)用訪(fǎng)問(wèn)。這項(xiàng)保護(hù)措施由 Android 實(shí)現(xiàn),而且這對(duì)于大多數(shù)應(yīng)用來(lái)說(shuō)足夠了。

一般情況下,建議您盡量避免將 MODE_WORLD_WRITEABLE或 MODE_WORLD_READABLE模式用于IPC文件,因?yàn)樵谶@兩種模式下,系統(tǒng)不提供針對(duì)特定應(yīng)用限制數(shù)據(jù)訪(fǎng)問(wèn)的功能,也不會(huì)對(duì)數(shù)據(jù)格式進(jìn)行任何控制。如果您想與其他應(yīng)用進(jìn)程共享數(shù)據(jù),不妨考慮使用ContentProvider,它可以為其他應(yīng)用提供讀取和寫(xiě)入權(quán)限,還能針對(duì)各種具體情況授予動(dòng)態(tài)權(quán)限。

要為敏感數(shù)據(jù)提供額外的保護(hù),您可以選擇使用該應(yīng)用無(wú)法直接訪(fǎng)問(wèn)的密鑰來(lái)對(duì)本地文件進(jìn)行加密。例如,您可以將密鑰存儲(chǔ)在 KeyStore 中,并使用未存儲(chǔ)在相應(yīng)設(shè)備上的用戶(hù)密碼加以保護(hù)。不過(guò),如果攻擊者獲得超級(jí)用戶(hù)權(quán)限,就可以在用戶(hù)輸入密碼時(shí)進(jìn)行監(jiān)控,數(shù)據(jù)也就失去了這層保護(hù)屏障;但是,這種方式可以保護(hù)丟失設(shè)備上的數(shù)據(jù),而無(wú)需進(jìn)行文件系統(tǒng)加密。

使用外部存儲(chǔ)設(shè)備

在外部存儲(chǔ)設(shè)備(例如 SD 卡)上創(chuàng)建的文件不受任何讀取和寫(xiě)入權(quán)限的限制。對(duì)于外部存儲(chǔ)設(shè)備中的內(nèi)容,不僅用戶(hù)可以將其移除,而且任何應(yīng)用都可以對(duì)其進(jìn)行修改,因此最好不要使用外部存儲(chǔ)設(shè)備來(lái)存儲(chǔ)敏感信息。

就像處理來(lái)源不受信任的數(shù)據(jù)一樣,您應(yīng)對(duì)外部存儲(chǔ)設(shè)備中的數(shù)據(jù)執(zhí)行輸入驗(yàn)證。強(qiáng)烈建議您不要在動(dòng)態(tài)加載前將可執(zhí)行文件或類(lèi)文件存儲(chǔ)在外部存儲(chǔ)設(shè)備中。如果您的應(yīng)用確實(shí)從外部存儲(chǔ)設(shè)備中檢索可執(zhí)行文件,請(qǐng)?jiān)趧?dòng)態(tài)加載前對(duì)這些文件執(zhí)行簽名和加密驗(yàn)證。

使用內(nèi)容提供程序

ContentProvider提供結(jié)構(gòu)化存儲(chǔ)機(jī)制,可以將內(nèi)容限制為僅供自己的應(yīng)用訪(fǎng)問(wèn),也可以將內(nèi)容導(dǎo)出以供其他應(yīng)用訪(fǎng)問(wèn)。如果您不打算向其他應(yīng)用授予訪(fǎng)問(wèn)您的ContentProvider 的權(quán)限,請(qǐng)?jiān)趹?yīng)用清單中將其標(biāo)記為 android:exported=false;要允許其他應(yīng)用訪(fǎng)問(wèn)存儲(chǔ)的數(shù)據(jù),請(qǐng)將 android:exported 屬性設(shè)置為 "true"

在創(chuàng)建要導(dǎo)出以供其他應(yīng)用使用的 ContentProvider 時(shí),您可以在清單中指定允許讀取和寫(xiě)入的單一權(quán)限,也可以針對(duì)讀取和寫(xiě)入操作分別指定權(quán)限。我們建議您僅對(duì)需要完成相應(yīng)任務(wù)的應(yīng)用授予權(quán)限。請(qǐng)注意,與其移除權(quán)限而影響到現(xiàn)有用戶(hù),不如以后要使用新功能時(shí)再添加權(quán)限。

如果您要使用內(nèi)容提供程序僅在自己的應(yīng)用之間共享數(shù)據(jù),最好將 android:protectionLevel屬性設(shè)置為 "signature" 保護(hù)級(jí)別。簽名權(quán)限不需要用戶(hù)確認(rèn),因此,這種方式不僅能提升用戶(hù)體驗(yàn),而且在相關(guān)應(yīng)用使用相同的密鑰進(jìn)行簽名來(lái)訪(fǎng)問(wèn)數(shù)據(jù)時(shí),還能更好地控制對(duì)內(nèi)容提供程序數(shù)據(jù)的訪(fǎng)問(wèn)。

內(nèi)容提供程序還可以通過(guò)以下方式提供更細(xì)化的訪(fǎng)問(wèn)權(quán)限:聲明 android:grantUriPermissions屬性,并使用用來(lái)啟動(dòng)組件的 Intent 對(duì)象中的 FLAG_GRANT_READ_URI_PERMISSION 標(biāo)記。使用 <grant-uri-permission element> 還能進(jìn)一步限制這些權(quán)限的范圍。

訪(fǎng)問(wèn)內(nèi)容提供程序時(shí),請(qǐng)使用參數(shù)化的查詢(xún)方法(例如 query())update()delete()),以免產(chǎn)生來(lái)源不受信任的 SQL 注入風(fēng)險(xiǎn)。請(qǐng)注意,如果以組合用戶(hù)數(shù)據(jù)的方式構(gòu)建 selection 參數(shù),然后再將其提交至參數(shù)化方法,則使用參數(shù)化方法可能不夠安全。

請(qǐng)不要誤以為提供寫(xiě)入權(quán)限很安全。設(shè)想一下,寫(xiě)入權(quán)限允許使用 SQL 語(yǔ)句,這使得攻擊者可以通過(guò)使用各種 WHERE 子句以及對(duì)相關(guān)結(jié)果進(jìn)行解析來(lái)確認(rèn)某些數(shù)據(jù)。例如,如果攻擊者想要探查通話(huà)記錄中是否存在某個(gè)特定電話(huà)號(hào)碼,只要該號(hào)碼已經(jīng)存在,攻擊者就可以通過(guò)修改其中的一行來(lái)獲知。如果內(nèi)容提供程序數(shù)據(jù)采用可預(yù)測(cè)的結(jié)構(gòu),那么授予寫(xiě)入權(quán)限相當(dāng)于同時(shí)提供了讀取和寫(xiě)入權(quán)限。

使用權(quán)限

由于 Android 通過(guò)沙盒機(jī)制管理各個(gè)應(yīng)用,因此應(yīng)用必須以明確的方式共享資源和數(shù)據(jù)。應(yīng)用會(huì)通過(guò)聲明自己需要的權(quán)限來(lái)獲取基本沙盒未提供的額外功能(包括對(duì)相機(jī)等設(shè)備功能的訪(fǎng)問(wèn)權(quán)限),從而實(shí)現(xiàn)這一點(diǎn)。

請(qǐng)求權(quán)限

我們建議您盡量減少應(yīng)用請(qǐng)求的權(quán)限。如果不具備對(duì)敏感數(shù)據(jù)的訪(fǎng)問(wèn)權(quán)限,就能降低不慎誤用這類(lèi)權(quán)限的風(fēng)險(xiǎn),并可提高用戶(hù)的采用率,同時(shí)讓您的應(yīng)用不那么容易受到攻擊者的攻擊。一般來(lái)說(shuō),如果您的應(yīng)用無(wú)需某項(xiàng)權(quán)限也能正常運(yùn)行,就不要請(qǐng)求該權(quán)限。

如果可以采用不需要任何權(quán)限的方式設(shè)計(jì)應(yīng)用,建議采用這種方式。例如,與其請(qǐng)求訪(fǎng)問(wèn)設(shè)備信息的權(quán)限以創(chuàng)建唯一標(biāo)識(shí)符,不如為您的應(yīng)用創(chuàng)建一個(gè) GUID(請(qǐng)參閱處理用戶(hù)數(shù)據(jù)的相關(guān)部分)?;蛘?,您也可以不將數(shù)據(jù)存儲(chǔ)在外部存儲(chǔ)設(shè)備(需要請(qǐng)求權(quán)限),而將其存儲(chǔ)在內(nèi)部存儲(chǔ)空間。

除了請(qǐng)求權(quán)限之外,您的應(yīng)用也可以使用 <permissions> 來(lái)保護(hù)對(duì)安全性要求較高且會(huì)被其他應(yīng)用訪(fǎng)問(wèn)的 IPC,例如 ContentProvider。一般而言,我們建議您盡量使用訪(fǎng)問(wèn)權(quán)限控制,而不使用需要用戶(hù)確認(rèn)的權(quán)限,因?yàn)闄?quán)限管理對(duì)用戶(hù)來(lái)說(shuō)可能比較復(fù)雜。例如,對(duì)于同一開(kāi)發(fā)者提供的不同應(yīng)用之間的 IPC 通信,不妨使用 "signature" 保護(hù)級(jí)別。

請(qǐng)勿泄露受權(quán)限保護(hù)的數(shù)據(jù)。當(dāng)您的應(yīng)用通過(guò) IPC 傳輸數(shù)據(jù)時(shí)可能會(huì)出現(xiàn)泄漏,不過(guò),只有您的應(yīng)用擁有特定權(quán)限時(shí),才可能發(fā)生數(shù)據(jù)泄漏。應(yīng)用 IPC 接口的客戶(hù)端可能沒(méi)有相同的數(shù)據(jù)訪(fǎng)問(wèn)權(quán)限。要詳細(xì)了解潛在影響以及這類(lèi)問(wèn)題發(fā)生的頻率,請(qǐng)參閱在 USENIX 上發(fā)布的這篇研究論文。

創(chuàng)建權(quán)限

一般來(lái)說(shuō),您應(yīng)在滿(mǎn)足安全性要求的前提下盡可能少定義權(quán)限。對(duì)于大多數(shù)應(yīng)用來(lái)說(shuō),它們很少會(huì)創(chuàng)建新權(quán)限,因?yàn)?a target="_blank" rel="nofollow">系統(tǒng)定義的權(quán)限就能滿(mǎn)足大部分的需求。請(qǐng)視需要使用現(xiàn)有權(quán)限執(zhí)行訪(fǎng)問(wèn)權(quán)限檢查。

如果必須創(chuàng)建新權(quán)限,請(qǐng)盡量考慮創(chuàng)建 "signature" 保護(hù)級(jí)別的權(quán)限?!昂灻奔?jí)別權(quán)限的內(nèi)容對(duì)用戶(hù)完全透明開(kāi)放,而且只有由執(zhí)行權(quán)限檢查的應(yīng)用的開(kāi)發(fā)者簽名的應(yīng)用才可訪(fǎng)問(wèn)這些內(nèi)容。

如果您創(chuàng)建了 "dangerous" 保護(hù)級(jí)別的權(quán)限,則事情就會(huì)更加復(fù)雜,您需要注意:

  • 該權(quán)限必須包含一個(gè)字符串,向用戶(hù)清楚明確地說(shuō)明他們需要做出的安全決策。
  • 該權(quán)限的字符串必須翻譯成多種不同語(yǔ)言。
  • 用戶(hù)可能會(huì)因?yàn)闄?quán)限含糊不清或存在風(fēng)險(xiǎn)而選擇不安裝應(yīng)用。
  • 應(yīng)用可能會(huì)在權(quán)限創(chuàng)建程序尚未安裝的情況下請(qǐng)求權(quán)限。

這些事情會(huì)給開(kāi)發(fā)者帶來(lái)巨大的非技術(shù)性挑戰(zhàn),也讓用戶(hù)感到困惑,因此我們不鼓勵(lì)使用 "dangerous" 權(quán)限級(jí)別。

使用網(wǎng)絡(luò)

網(wǎng)絡(luò)交易涉及傳輸對(duì)用戶(hù)而言可能比較私密的數(shù)據(jù),因此本質(zhì)上就存在安全風(fēng)險(xiǎn)。用戶(hù)開(kāi)始逐漸意識(shí)到移動(dòng)設(shè)備存在的隱私泄漏問(wèn)題,尤其是在通過(guò)設(shè)備進(jìn)行網(wǎng)絡(luò)交易時(shí)。因此,請(qǐng)務(wù)必對(duì)您的應(yīng)用采取各種最佳做法,以始終確保用戶(hù)的數(shù)據(jù)安全。

使用 IP 網(wǎng)絡(luò)

Android 網(wǎng)絡(luò)運(yùn)行機(jī)制與其他 Linux 環(huán)境差別不大,關(guān)鍵是確保對(duì)敏感數(shù)據(jù)使用合適的協(xié)議,如使用 HttpsURLConnection 來(lái)保證網(wǎng)絡(luò)流量安全。我們建議您在服務(wù)器支持 HTTPS 的情況下一律使用 HTTPS(而非 HTTP),因?yàn)橐苿?dòng)設(shè)備經(jīng)常會(huì)連接到不安全的網(wǎng)絡(luò)(如公共 WLAN 熱點(diǎn))。

您可以使用 SSLSocket 類(lèi)輕松實(shí)現(xiàn)經(jīng)過(guò)身份驗(yàn)證和加密的套接字層通信??紤]到 Android 設(shè)備會(huì)頻繁使用 WLAN 連接到不安全的無(wú)線(xiàn)網(wǎng)絡(luò),我們強(qiáng)烈建議所有通過(guò)網(wǎng)絡(luò)通信的應(yīng)用使用安全的網(wǎng)絡(luò)。

我們發(fā)現(xiàn)有些應(yīng)用使用 localhost 網(wǎng)絡(luò)端口處理敏感的 IPC。我們不建議采用這種方法,因?yàn)樵O(shè)備上的其他應(yīng)用也可以訪(fǎng)問(wèn)這些接口。相反,您應(yīng)該使用可通過(guò) Service 等進(jìn)行身份驗(yàn)證的 Android IPC 機(jī)制。(綁定到 INADDR_ANY 比使用回送功能還要糟糕,因?yàn)檫@樣一來(lái),您的應(yīng)用可能會(huì)收到任何位置發(fā)來(lái)的請(qǐng)求。)

此外,還有一個(gè)需要再三強(qiáng)調(diào)的常見(jiàn)問(wèn)題就是,切勿相信通過(guò) HTTP 或其他非安全協(xié)議下載的數(shù)據(jù),包括 WebView 中的輸入驗(yàn)證以及對(duì)通過(guò) HTTP 發(fā)出的 intent 的任何響應(yīng)。

使用電話(huà)網(wǎng)絡(luò)

短信協(xié)議主要是為用戶(hù)間通信設(shè)計(jì)的,并不適合要傳輸數(shù)據(jù)的應(yīng)用??紤]到短信的局限性,因此,想從網(wǎng)絡(luò)服務(wù)器向用戶(hù)設(shè)備上安裝的應(yīng)用發(fā)送數(shù)據(jù)消息時(shí),我們強(qiáng)烈建議您使用Google 云消息傳遞(GCM) 和 IP 網(wǎng)絡(luò)。

請(qǐng)注意,短信在網(wǎng)絡(luò)上和設(shè)備上均未經(jīng)過(guò)加密,也沒(méi)有經(jīng)過(guò)嚴(yán)格的身份驗(yàn)證。而且,短信的所有接收者都應(yīng)明白,您的應(yīng)用收到的短信可能來(lái)自惡意用戶(hù)。因此,切勿使用未經(jīng)身份驗(yàn)證的短信數(shù)據(jù)執(zhí)行敏感命令。還需要注意的是,短信可能包含欺騙性?xún)?nèi)容,也有可能在網(wǎng)絡(luò)上傳輸時(shí)被攔截。在 Android 設(shè)備上,短信會(huì)以廣播 intent 的形式傳輸,因此可能會(huì)被其他擁有 READ_SMS 權(quán)限的應(yīng)用讀取或捕獲。

執(zhí)行輸入驗(yàn)證

無(wú)論應(yīng)用是在哪種平臺(tái)上運(yùn)行,輸入驗(yàn)證功能不完善都是影響應(yīng)用的最常見(jiàn)安全問(wèn)題。Android 為此提供了平臺(tái)級(jí)對(duì)策,可降低應(yīng)用出現(xiàn)輸入驗(yàn)證問(wèn)題的可能性。如果可行,請(qǐng)盡量使用這些功能。另請(qǐng)注意,選擇類(lèi)型安全的語(yǔ)言通常也有助于降低出現(xiàn)輸入驗(yàn)證問(wèn)題的可能性。

如果使用原生代碼,那么系統(tǒng)從文件讀取、通過(guò)網(wǎng)絡(luò)接收或從 IPC 接收的任何數(shù)據(jù)都有可能會(huì)引發(fā)安全問(wèn)題。最常見(jiàn)的問(wèn)題包括緩沖區(qū)溢出釋放后重用差一錯(cuò)誤。Android 為此提供了多項(xiàng)技術(shù),例如 ASLR和 DEP,可以降低這些錯(cuò)誤被利用的可能性,但無(wú)法解決根本問(wèn)題。因此,請(qǐng)謹(jǐn)慎管理指針和緩沖區(qū),預(yù)防這些漏洞造成破壞。

使用基于字符串的動(dòng)態(tài)語(yǔ)言(如 JavaScript 和 SQL)也可能因?yàn)檗D(zhuǎn)義字符和腳本注入而出現(xiàn)輸入驗(yàn)證問(wèn)題。

如果使用提交到 SQL 數(shù)據(jù)庫(kù)或內(nèi)容提供程序的查詢(xún)中的數(shù)據(jù),也可能出現(xiàn) SQL 注入問(wèn)題。最好的預(yù)防措施是使用參數(shù)化查詢(xún)(請(qǐng)參閱上文內(nèi)容提供程序部分的相關(guān)內(nèi)容)。將權(quán)限限制為只讀或只寫(xiě),也可以降低 SQL 注入引發(fā)破壞的可能性。

如果您無(wú)法使用上述安全功能,我們強(qiáng)烈建議您使用結(jié)構(gòu)合理的數(shù)據(jù)格式,并驗(yàn)證數(shù)據(jù)是否符合預(yù)期的格式。雖然將字符列入黑名單或替換字符是一種有效的策略,但這些技術(shù)在實(shí)際操作中很容易出錯(cuò),因此應(yīng)盡量避免使用。

處理用戶(hù)數(shù)據(jù)

通常情況下,確保用戶(hù)數(shù)據(jù)安全的最佳做法是盡量避免使用會(huì)訪(fǎng)問(wèn)用戶(hù)敏感數(shù)據(jù)或個(gè)人數(shù)據(jù)的 API。如果您擁有用戶(hù)數(shù)據(jù)的訪(fǎng)問(wèn)權(quán)限,并且能夠避免存儲(chǔ)或傳輸這些信息,那么就不要存儲(chǔ)或傳輸這些數(shù)據(jù)。最后,請(qǐng)?jiān)u估您的應(yīng)用邏輯能否使用經(jīng)過(guò)哈希算法處理或不可逆的數(shù)據(jù)格式進(jìn)行實(shí)現(xiàn)。例如,您的應(yīng)用可能會(huì)使用電子郵件地址的哈希值作為主要密鑰,以避免傳輸或存儲(chǔ)電子郵件地址。這樣可降低在無(wú)意之中泄露數(shù)據(jù)的可能性,還可以降低攻擊者嘗試?yán)媚膽?yīng)用搞破壞的可能性。

請(qǐng)注意,如果您的應(yīng)用會(huì)訪(fǎng)問(wèn)密碼或用戶(hù)名等個(gè)人信息,部分司法轄區(qū)可能會(huì)要求您提供隱私權(quán)政策,以說(shuō)明您如何使用或存儲(chǔ)這類(lèi)數(shù)據(jù)。因此,遵循安全最佳做法(即盡可能減少對(duì)用戶(hù)數(shù)據(jù)的訪(fǎng)問(wèn))也有助于簡(jiǎn)化合規(guī)工作。

此外,您還應(yīng)考慮自己的應(yīng)用是否會(huì)在無(wú)意之中將個(gè)人信息泄露給其他方,如廣告使用的第三方組件或應(yīng)用使用的第三方服務(wù)。如果不知道某個(gè)組件或服務(wù)為什么需要個(gè)人信息,就不要提供個(gè)人信息。通常,減少您的應(yīng)用對(duì)個(gè)人信息的訪(fǎng)問(wèn),可以降低引發(fā)這方面問(wèn)題的可能性。

如果必須訪(fǎng)問(wèn)敏感數(shù)據(jù),請(qǐng)判斷這些信息是必須傳輸至服務(wù)器,還是可以在客戶(hù)端上執(zhí)行相應(yīng)操作。建議您在客戶(hù)端上運(yùn)行所有需要使用敏感數(shù)據(jù)的代碼,以避免傳輸用戶(hù)數(shù)據(jù)。

此外,請(qǐng)務(wù)必不要使用權(quán)限過(guò)于寬松的 IPC、完全沒(méi)有寫(xiě)入限制的文件或網(wǎng)絡(luò)套接字,避免在無(wú)意之中將用戶(hù)數(shù)據(jù)泄露給設(shè)備上的其他應(yīng)用。這屬于一種造成受權(quán)限保護(hù)的數(shù)據(jù)遭泄露的特殊情況,我們已在請(qǐng)求權(quán)限部分討論過(guò)。

如果需要GUI ,請(qǐng)創(chuàng)建一個(gè)較長(zhǎng)的具有唯一性的編號(hào)并加以存儲(chǔ)。請(qǐng)勿使用可能與個(gè)人信息關(guān)聯(lián)的電話(huà)標(biāo)識(shí)符,如電話(huà)號(hào)碼或 IMEI。有關(guān)此主題的詳情,請(qǐng)參閱 Android 開(kāi)發(fā)者博客。

向設(shè)備上的日志寫(xiě)入內(nèi)容時(shí),請(qǐng)務(wù)必謹(jǐn)慎小心。在 Android 中,日志是共享資源,擁有 READ_LOGS 權(quán)限的所有應(yīng)用均可訪(fǎng)問(wèn)。即使電話(huà)日志數(shù)據(jù)是臨時(shí)數(shù)據(jù)并會(huì)在重新啟動(dòng)時(shí)清空,不當(dāng)記錄用戶(hù)信息也可能在無(wú)意之中將用戶(hù)數(shù)據(jù)泄露給其他應(yīng)用。

使用 WebView

由于 WebView 使用的網(wǎng)絡(luò)內(nèi)容可能包含 HTML 和 JavaScript,當(dāng)?shù)氖褂每赡芤氤R?jiàn)的網(wǎng)絡(luò)安全問(wèn)題,例如跨站腳本攻擊(JavaScript 注入)。Android 內(nèi)置了多種機(jī)制,可將 WebView 的功能限制為您應(yīng)用所需的最低功能,以縮小這些潛在問(wèn)題的影響范圍。

如果您的應(yīng)用不直接使用 WebView 中的 JavaScript,請(qǐng)調(diào)用 setJavaScriptEnabled()。部分示例代碼會(huì)使用這種方法,不過(guò)您可能需要在實(shí)際應(yīng)用時(shí)根據(jù)具體情況進(jìn)行調(diào)整。因此,如果不需要使用這種調(diào)用方法,請(qǐng)將其移除。默認(rèn)情況下,WebView 不會(huì)執(zhí)行 JavaScript,因此不可能出現(xiàn)跨站腳本攻擊這樣的安全問(wèn)題。

addJavaScriptInterface() 允許 JavaScript 調(diào)用正常情況下是為 Android 應(yīng)用預(yù)留的操作,因此在使用時(shí)請(qǐng)格外小心。如果要使用,請(qǐng)僅將 addJavaScriptInterface() 用于所有輸入內(nèi)容都可信的網(wǎng)頁(yè)。如果您接受不受信任的輸入內(nèi)容,那么不受信任的 JavaScript 可能會(huì)調(diào)用您應(yīng)用中的 Android 方法。一般情況下,我們建議您僅將 addJavaScriptInterface() 用于應(yīng)用 APK 內(nèi)含的 JavaScript。

如果您的應(yīng)用通過(guò) WebView 訪(fǎng)問(wèn)敏感數(shù)據(jù),您可能需要使用 clearCache() 方法來(lái)刪除本地存儲(chǔ)的所有文件。您也可以使用服務(wù)器端標(biāo)頭(例如 no-cache)來(lái)指示應(yīng)用不應(yīng)緩存特定內(nèi)容。

在 Android 4.4(API 級(jí)別 19)之前平臺(tái)上運(yùn)行的設(shè)備使用的 webkit 版本存在多個(gè)安全問(wèn)題。如果您的應(yīng)用在這些設(shè)備上運(yùn)行,解決方法是確認(rèn) WebView 對(duì)象只顯示值得信任的內(nèi)容。還應(yīng)使用可更新的安全 Provider 對(duì)象確保您的應(yīng)用在 SSL 中不會(huì)暴露給潛在的漏洞,如更新您的安全提供程序以防范 SSL 攻擊中所述。如果您的應(yīng)用必須從開(kāi)放網(wǎng)絡(luò)渲染內(nèi)容,請(qǐng)考慮提供您自己的渲染程序,以便使用最新的安全補(bǔ)丁程序保持其處于最新?tīng)顟B(tài)。

處理憑據(jù)

一般情況下,我們建議您盡量降低要求用戶(hù)憑據(jù)的頻率;這樣會(huì)讓釣魚(yú)攻擊顯得比較可疑,從而能夠降低其成功率。作為替代方法,您可以使用授權(quán)令牌并根據(jù)需要刷新。

請(qǐng)盡量避免將用戶(hù)名和密碼存儲(chǔ)在設(shè)備上。您可以使用用戶(hù)提供的用戶(hù)名和密碼進(jìn)行初始身份驗(yàn)證,然后使用針對(duì)特定服務(wù)的短時(shí)效授權(quán)令牌。

可供多個(gè)應(yīng)用訪(fǎng)問(wèn)的服務(wù)應(yīng)使用 AccountManager 進(jìn)行訪(fǎng)問(wèn)。如果可行,請(qǐng)使用 AccountManager 類(lèi)來(lái)調(diào)用基于云的服務(wù);此外,請(qǐng)勿將密碼存儲(chǔ)在設(shè)備上。

使用 AccountManager 檢索 Account 后,請(qǐng)先確認(rèn) CREATOR 再傳送憑據(jù),以免無(wú)意中將憑據(jù)傳送給錯(cuò)誤的應(yīng)用。

如果憑據(jù)僅供您創(chuàng)建的應(yīng)用使用,那么您可以使用 checkSignature() 驗(yàn)證訪(fǎng)問(wèn) AccountManager 的應(yīng)用。另外,如果只有一個(gè)應(yīng)用使用該憑據(jù),那么您可以使用 KeyStore 存儲(chǔ)憑據(jù)。

使用加密

Android 不僅提供數(shù)據(jù)隔離機(jī)制、支持完整文件系統(tǒng)加密并提供安全通信通道,還提供大量使用加密來(lái)保護(hù)數(shù)據(jù)的算法。

一般情況下,請(qǐng)嘗試根據(jù)您的具體情況使用已經(jīng)實(shí)現(xiàn)的最高級(jí)別的框架。如果您需要從某個(gè)已知位置安全地檢索文件,使用簡(jiǎn)單的 HTTPS URI 即可滿(mǎn)足需要,無(wú)需具備加密知識(shí)。如果您需要一個(gè)安全通道,不妨考慮使用 HttpsURLConnectionSSLSocket,而無(wú)需自行編寫(xiě)協(xié)議。

如果您需要實(shí)現(xiàn)自己的協(xié)議,我們強(qiáng)烈建議您不要實(shí)現(xiàn)自己的加密算法。請(qǐng)使用現(xiàn)有加密算法,例如 Cipher 類(lèi)中提供的 AES 或 RSA 實(shí)現(xiàn)中的算法。

使用安全隨機(jī)數(shù)生成器 SecureRandom 初始化任意加密密鑰 KeyGenerator。如果使用的密鑰不是安全隨機(jī)數(shù)生成器生成的,那么會(huì)顯著降低算法的強(qiáng)度,容易導(dǎo)致出現(xiàn)離線(xiàn)攻擊。

如果您需要存儲(chǔ)密鑰以供重復(fù)使用,請(qǐng)使用 KeyStore 等可以長(zhǎng)期存儲(chǔ)和檢索加密密鑰的機(jī)制。

使用進(jìn)程間通信

部分應(yīng)用會(huì)嘗試使用傳統(tǒng) Linux 技術(shù)(如網(wǎng)絡(luò)套接字和共享文件)來(lái)實(shí)現(xiàn) IPC。強(qiáng)烈建議您改為使用 Android 針對(duì) IPC 提供的系統(tǒng)功能,例如使用 ServiceIntent、BinderMessenger,以及BroadcastReceiver`。Android IPC 機(jī)制讓您驗(yàn)證連接至 IPC 的應(yīng)用的身份,并為每種 IPC 機(jī)制設(shè)置安全策略。

許多安全元素在各種 IPC 機(jī)制之間是共享的。如果您的 IPC 機(jī)制并不打算讓其他應(yīng)用使用,請(qǐng)?jiān)谠摻M件的清單元素(例如 <service> 元素)中將 android:exported 屬性設(shè)置為 "false"。對(duì)于同一 UID 中包含多項(xiàng)進(jìn)程的應(yīng)用,這種做法非常有用;當(dāng)您在以后的開(kāi)發(fā)過(guò)程中決定不以 IPC 的形式提供功能但又不想重新編寫(xiě)代碼時(shí),這樣做也會(huì)有所助益。

如果您的 IPC 預(yù)期供其他應(yīng)用訪(fǎng)問(wèn),您可以使用 <permission> 元素應(yīng)用安全策略。如果 IPC 是在您自己的不同應(yīng)用(以同一密鑰登錄)之間使用,建議您在 android:protectionLevel 中使用 "signature" 級(jí)別權(quán)限。

使用 Intent

Intent 是 Android 中異步 IPC 的首選機(jī)制。根據(jù)您的應(yīng)用要求,您可能會(huì)對(duì)特定的應(yīng)用組件使用 sendBroadcast()、sendOrderedBroadcast() 或顯式 intent。

請(qǐng)注意,排序后的廣播可能會(huì)被接收者“占用”,因此它們可能不會(huì)傳遞到所有應(yīng)用。如果您要發(fā)送必須傳遞到特定接收者的 intent,那么必須使用以 nameintent 聲明接收者的顯式 intent。

Intent 的發(fā)送器會(huì)驗(yàn)證接收者是否有權(quán)通過(guò)方法調(diào)用來(lái)指定非空權(quán)限。只有具有該權(quán)限的應(yīng)用才會(huì)收到 intent。如果廣播 intent 中的數(shù)據(jù)屬于敏感數(shù)據(jù),則不妨考慮應(yīng)用相應(yīng)權(quán)限,以確保惡意應(yīng)用在沒(méi)有相應(yīng)權(quán)限的情況下無(wú)法注冊(cè)以接收這些消息。在這些情況下,您還可以考慮直接調(diào)用接收器,而不是發(fā)起廣播。

:請(qǐng)勿將 intent 過(guò)濾條件視為安全功能 - 組件可通過(guò)顯式 intent 調(diào)用,但不一定擁有符合 intent 過(guò)濾條件的數(shù)據(jù)。您需要在 intent 接收器中執(zhí)行輸入驗(yàn)證,以確認(rèn) intent 的格式正確無(wú)誤,可用于調(diào)用的接收器、服務(wù)或 Activity。

使用服務(wù)

Service 通常用于提供其他應(yīng)用要使用的功能。每個(gè)服務(wù)類(lèi)在其清單文件中都必須有相應(yīng)的 <service>聲明。

默認(rèn)情況下,服務(wù)不會(huì)被導(dǎo)出,而且無(wú)法由任何其他應(yīng)用調(diào)用。不過(guò),如果您將任何 intent 過(guò)濾條件添加到服務(wù)聲明中,那么默認(rèn)就會(huì)導(dǎo)出該服務(wù)。最好是明確聲明 android:exported屬性,以確保其行為符合您的需要。您也可以使用 android:permission 屬性來(lái)保護(hù)服務(wù)。這樣一來(lái),其他應(yīng)用只有在自己的清單中聲明相應(yīng)的 <uses-permission>元素,才能啟動(dòng)、停止或綁定到服務(wù)。

服務(wù)可以先調(diào)用 checkCallingPermission(),然后再實(shí)現(xiàn)該調(diào)用,從而保護(hù)針對(duì)該服務(wù)、擁有相應(yīng)權(quán)限的各個(gè) IPC 調(diào)用。通常情況下,我們建議您在清單中使用聲明式權(quán)限,因?yàn)檫@些權(quán)限不容易被忽略。

使用 Binder 和 Messenger 接口

使用 BinderMessenger 是 Android 中 RPC 式 IPC 的首選機(jī)制。它們提供了定義完善的接口,可讓端點(diǎn)互相進(jìn)行身份驗(yàn)證(如果需要)。

我們強(qiáng)烈建議您在設(shè)計(jì)接口時(shí),采取無(wú)需針對(duì)接口進(jìn)行特定權(quán)限檢查的方式。應(yīng)用清單中并未聲明 BindeMessenger 對(duì)象,因此您無(wú)法向這些對(duì)象直接應(yīng)用聲明式權(quán)限。一般情況下,如果您在 ServiceActivity 中實(shí)現(xiàn)了這些對(duì)象,那么它們會(huì)繼承 Service 或 Activity 的應(yīng)用清單中聲明的權(quán)限。如果您要?jiǎng)?chuàng)建一個(gè)需要身份驗(yàn)證和/或訪(fǎng)問(wèn)控件的接口,則這些控件必須以代碼的形式明確添加到 BindeMessenger 接口中。

如果您提供的接口確實(shí)需要訪(fǎng)問(wèn)控件,請(qǐng)使用 checkCallingPermission() 驗(yàn)證調(diào)用者是否具備所需權(quán)限。在代表調(diào)用者訪(fǎng)問(wèn)服務(wù)前,請(qǐng)務(wù)必執(zhí)行此操作,因?yàn)槟鷳?yīng)用的身份會(huì)傳遞到其他接口。如果您調(diào)用的是 Service 提供的接口,在沒(méi)有訪(fǎng)問(wèn)指定服務(wù)的權(quán)限的情況下,bindService 調(diào)用可能會(huì)失敗。如果您調(diào)用的是自己的應(yīng)用提供的本地接口,不妨使用 clearCallingIdentity() 來(lái)確保滿(mǎn)足內(nèi)部安全檢查的要求。

使用廣播接收器

BroadcastReceiver 會(huì)處理 Intent 發(fā)起的異步請(qǐng)求。

默認(rèn)情況下,接收器會(huì)被導(dǎo)出,而且可以由任何其他應(yīng)用調(diào)用。如果您的 BroadcastReceiver 預(yù)期供其他應(yīng)用使用,您可能需要使用應(yīng)用清單中的 <receiver> 元素向接收器應(yīng)用安全權(quán)限。這樣可防止沒(méi)有相應(yīng)權(quán)限的應(yīng)用向 BroadcastReceiver 發(fā)送 intent。

動(dòng)態(tài)加載代碼

我們強(qiáng)烈建議您不要從應(yīng)用 APK 外部加載代碼。這樣做不僅會(huì)明顯加大應(yīng)用因代碼注入或代碼篡改產(chǎn)生問(wèn)題的可能性,還會(huì)增加版本管理和應(yīng)用測(cè)試的難度。這最終會(huì)導(dǎo)致無(wú)法驗(yàn)證應(yīng)用的行為,因此,某些環(huán)境中可能會(huì)禁止采用此做法。

如果您的應(yīng)用會(huì)動(dòng)態(tài)加載代碼,您務(wù)必謹(jǐn)記,運(yùn)行動(dòng)態(tài)加載的代碼需要擁有與應(yīng)用 APK 相同的安全權(quán)限。用戶(hù)是因?yàn)槟艣Q定安裝您的應(yīng)用的,因此他們希望您提供的是在您的應(yīng)用內(nèi)運(yùn)行的代碼,包括動(dòng)態(tài)加載的代碼。

與動(dòng)態(tài)加載代碼相關(guān)的主要安全風(fēng)險(xiǎn)與這樣的代碼需要來(lái)自可驗(yàn)證的來(lái)源有關(guān)。如果這些模塊已直接納入您的 APK 中,那么其他應(yīng)用就無(wú)法對(duì)其進(jìn)行修改;無(wú)論代碼是原生庫(kù)代碼還是使用 DexClassLoader 加載的類(lèi),均是如此。我們見(jiàn)過(guò)很多應(yīng)用嘗試從不安全的位置(例如,通過(guò)未加密的協(xié)議從網(wǎng)絡(luò)上進(jìn)行下載)或任何人都可寫(xiě)入內(nèi)容的位置(如外部存儲(chǔ)設(shè)備)加載代碼的例子;對(duì)于前一種位置,網(wǎng)絡(luò)上的用戶(hù)將可以修改正在傳輸?shù)膬?nèi)容,對(duì)于后一種位置,用戶(hù)設(shè)備上的其他應(yīng)用將可以修改設(shè)備上的內(nèi)容。

虛擬機(jī)中的安全性

Dalvik 是 Android 的運(yùn)行時(shí)虛擬機(jī) (VM)。雖然 Dalvik 是專(zhuān)為 Android 而設(shè)計(jì)的,但是其他虛擬機(jī)中遇到的很多安全代碼問(wèn)題在 Android 中也會(huì)出現(xiàn)。一般情況下,您無(wú)需擔(dān)心有關(guān)虛擬機(jī)的安全問(wèn)題。您的應(yīng)用在安全的沙盒環(huán)境中運(yùn)行,因此系統(tǒng)中的其他進(jìn)程無(wú)法訪(fǎng)問(wèn)您的代碼或隱私數(shù)據(jù)。

如果希望深入了解虛擬機(jī)安全性,建議您研讀有關(guān)這方面的一些現(xiàn)有文獻(xiàn)。下面是兩種比較受歡迎的資源:

本文將重點(diǎn)說(shuō)明 Android 特有或不同于其他虛擬機(jī)環(huán)境的方面。對(duì)于熟悉在其他環(huán)境中進(jìn)行虛擬機(jī)編程的開(kāi)發(fā)者,需要注意為 Android 編寫(xiě)應(yīng)用的兩大不同之處:

  • 有些虛擬機(jī)(例如 JVM 或 .net 運(yùn)行時(shí))會(huì)充當(dāng)安全邊界,將代碼與基本操作系統(tǒng)功能分隔開(kāi)來(lái)。在 Android 上,Dalvik 虛擬機(jī)不起安全邊界的作用 — 應(yīng)用沙盒是在操作系統(tǒng)級(jí)別進(jìn)行實(shí)現(xiàn)的,因此 Dalvik 可與同一應(yīng)用中的原生代碼進(jìn)行互操作,沒(méi)有安全限制。
  • 鑒于移動(dòng)設(shè)備上的存儲(chǔ)空間有限,開(kāi)發(fā)者一般希望開(kāi)發(fā)模塊化應(yīng)用并使用動(dòng)態(tài)類(lèi)加載。這樣做時(shí),請(qǐng)同時(shí)考慮您檢索應(yīng)用邏輯的來(lái)源以及您在本地存儲(chǔ)應(yīng)用邏輯的位置。請(qǐng)勿使用從未經(jīng)驗(yàn)證的來(lái)源(如不安全的網(wǎng)絡(luò)來(lái)源或外部存儲(chǔ)設(shè)備)加載的動(dòng)態(tài)類(lèi),因?yàn)檫@類(lèi)代碼可能遭到篡改,從而執(zhí)行某些惡意操作。

原生代碼中的安全性

一般情況下,我們鼓勵(lì)開(kāi)發(fā)者使用 Android SDK 來(lái)開(kāi)發(fā)應(yīng)用,而不要使用 Android NDK 編寫(xiě)原生代碼。通過(guò)原生代碼開(kāi)發(fā)的應(yīng)用比較復(fù)雜、可移植性較差,并且很可能會(huì)出現(xiàn)常見(jiàn)的內(nèi)存損壞錯(cuò)誤,如緩沖區(qū)溢出。

Android 使用 Linux 內(nèi)核構(gòu)建而成。如果您要使用原生代碼,熟悉一下 Linux 開(kāi)發(fā)安全最佳做法會(huì)非常有用。本文中沒(méi)有介紹 Linux 安全做法,不過(guò)您可以查閱非常受歡迎的《Secure Programming for Linux and Unix HOWTO》,網(wǎng)址為 http://www.dwheeler.com/secure-programs

Android 與大多數(shù) Linux 環(huán)境之間的一個(gè)重要區(qū)別在于應(yīng)用沙盒。在 Android 上,所有應(yīng)用都在應(yīng)用沙盒中運(yùn)行,包括那些采用原生代碼編寫(xiě)的應(yīng)用。對(duì)于熟悉 Linux 的開(kāi)發(fā)者而言,其本質(zhì)完全可以匯總成一句話(huà):每個(gè)應(yīng)用都被賦予唯一的 UID和非常有限的權(quán)限。這樣就很好理解了。此外,即使您使用的是原生代碼,也最好熟悉各種應(yīng)用權(quán)限。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容