Android 安全要點

2018-08-02 18:29 更新

編寫:craftsmanBai - http://z1ng.net - 原文:http://developer.android.com/training/articles/security-tips.html

Android內(nèi)建的安全機制可以顯著地減少了應(yīng)用程序的安全問題。你可以在默認(rèn)的系統(tǒng)設(shè)置和文件權(quán)限設(shè)置的環(huán)境下建立應(yīng)用,避免針對一堆頭疼的安全問題尋找解決方案。

一些幫助建立應(yīng)用的核心安全特性如下:

  • Android應(yīng)用程序沙盒,將應(yīng)用數(shù)據(jù)和代碼的執(zhí)行與其他程序隔離。
  • 具有魯棒性的常見安全功能的應(yīng)用框架,例如加密,權(quán)限控制,安全I(xiàn)PC
  • 使用ASLR,NX,ProPolice,safe_iop,OpenBSD dlmalloc,OpenBSD calloc,Linux mmap_min_addr等技術(shù),減少了常見內(nèi)存管理錯誤。
  • 加密文件系統(tǒng)可以保護丟失或被盜走的設(shè)備數(shù)據(jù)。
  • 用戶權(quán)限控制限制訪問系統(tǒng)關(guān)鍵信息和用戶數(shù)據(jù)。
  • 應(yīng)用程序權(quán)限以單個應(yīng)用為基礎(chǔ)控制其數(shù)據(jù)。

盡管如此,熟悉Android安全特性仍然很重要。遵守這些習(xí)慣并將其作為優(yōu)秀的代碼風(fēng)格,能夠減少無意間給用戶帶來的安全問題。

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

對于一個Android的應(yīng)用程序來說,最為常見的安全問題是存放在設(shè)備上的數(shù)據(jù)能否被其他應(yīng)用獲取。在設(shè)備上存放數(shù)據(jù)基本方式有三種:

使用內(nèi)部存儲

默認(rèn)情況下,你在內(nèi)部存儲中創(chuàng)建的文件只有你的應(yīng)用可以訪問。Android實現(xiàn)了這種機制,并且對于大多數(shù)應(yīng)用程序都是有效的。 你應(yīng)該避免在IPC文件中使用MODE_WORLD_WRITEABLE或者MODE_WORLD_READABLE模式,因為它們不為特殊程序提供限制數(shù)據(jù)訪問的功能,它們也不對數(shù)據(jù)格式進(jìn)行任何控制。如果你想與其他應(yīng)用的進(jìn)程共享數(shù)據(jù),可以使用Content Provider,它可以給其他應(yīng)用提供了可讀寫權(quán)限以及逐項動態(tài)獲取權(quán)限。

如果想對敏感數(shù)據(jù)進(jìn)行特別保護,你可以使用應(yīng)用程序無法直接獲取的密鑰來加密本地文件。例如,密鑰可以存放在KeyStore而非設(shè)備上,使用用戶密碼進(jìn)行保護。盡管這種方式無法防止通過root權(quán)限查看用戶輸入的密碼,但是它可以為未進(jìn)行文件系統(tǒng)加密的丟失設(shè)備提供保護。

使用外部存儲

創(chuàng)建于外部存儲的文件,比如SD卡,是全局可讀寫的。 由于外部存儲器可被用戶移除并且能夠被任何應(yīng)用修改,因此不應(yīng)使用外部存儲保存應(yīng)用的敏感信息。 當(dāng)處理來自外部存儲的數(shù)據(jù)時,應(yīng)用程序應(yīng)該執(zhí)行輸入驗證(參看輸入驗證章節(jié)) 我們強烈建議應(yīng)用在動態(tài)加載之前不要把可執(zhí)行文件或class文件存儲到外部存儲中。 如果一個應(yīng)用從外部存儲檢索可執(zhí)行文件,那么在動態(tài)加載之前它們應(yīng)該進(jìn)行簽名與加密驗證。

使用Content Providers

ContentProviders提供了一種結(jié)構(gòu)存儲機制,它可以限制你自己的應(yīng)用,也可以允許其他應(yīng)用程序進(jìn)行訪問。 如果你不打算向其他應(yīng)用提供訪問你的ContentProvider功能,那么在manifest中標(biāo)記他們?yōu)?a rel="external nofollow" target="_blank" target="_blank">android:exported=false即可。 要建立一個給其他應(yīng)用使用的ContentProvider,你可以為讀寫操作指定一個單一的permission,或者在manifest中為讀寫操作指定確切的權(quán)限。我們強烈建議你對要分配的權(quán)限進(jìn)行限制,僅滿足目前有的功能即可。 記住,通常新的權(quán)限在新功能加入的時候同時增加,會比把現(xiàn)有權(quán)限撤銷并打斷已經(jīng)存在的用戶更合理。

如果Content Provider僅在自己的應(yīng)用中共享數(shù)據(jù),使用簽名級別android:protectionLevel的權(quán)限是更可取的。 簽名權(quán)限不需要用戶確認(rèn),當(dāng)應(yīng)用使用同樣的密鑰獲取數(shù)據(jù)時,這提供了更好的用戶體驗,也更好地控制了Content Provider數(shù)據(jù)的訪問。 Content Providers也可以通過聲明android:grantUriPermissions并在觸發(fā)組件的Intent對象中使用FLAG_GRANT_READ_URI_PERMISSIONFLAG_GRANT_WRITE_URI_PERMISSION標(biāo)志提供更細(xì)致的訪問。 這些許可的作用域可以通過grant-uri-permission進(jìn)一步限制。 當(dāng)訪問一個ContentProvider時,使用參數(shù)化的查詢方法,比如query(),update()delete()來避免來自不信任源潛在的SQL注入。 注意,如果selection語句是在提交給方法之前先連接用戶數(shù)據(jù)的,使用參數(shù)化的方法或許不夠。 不要對“寫”權(quán)限有一個錯誤的觀念。 考慮“寫”權(quán)限允許sql語句,它可以通過使用創(chuàng)造性的WHERE子句并且解析結(jié)果讓部分?jǐn)?shù)據(jù)的確認(rèn)變?yōu)榭赡堋?例如:入侵者可能在通話記錄中通過修改一條記錄來檢測某個特定存在的電話號碼,只要那個電話號碼已經(jīng)存在。 如果content provider數(shù)據(jù)有可預(yù)見的結(jié)構(gòu),提供“寫”權(quán)限也許等同于同時提供了“讀寫”權(quán)限。

使用權(quán)限

因為安卓沙盒將應(yīng)用程序隔離,程序必須顯式地共享資源和數(shù)據(jù)。它們通過聲明他們需要的權(quán)限來獲取額外的功能,而基本的沙盒不提供這些功能,比如相機訪問設(shè)備。

請求權(quán)限

我們建議最小化應(yīng)用請求的權(quán)限數(shù)量,不具有訪問敏感資料的權(quán)限可以減少無意中濫用這些權(quán)限的風(fēng)險,可以增加用戶接受度,并且減少應(yīng)用被攻擊者攻擊利用的可能性。

如果你的應(yīng)用可以設(shè)計成不需要任何權(quán)限,那最好不過。例如:與其請求訪問設(shè)備信息來建立一個標(biāo)識,不如建立一個GUID(這個例子在下文“處理用戶數(shù)據(jù)”中有說明)。

除了請求權(quán)限之外,你的應(yīng)用可以使用permissions來保護可能會暴露給其他應(yīng)用的安全敏感的IPC:比如ContentProvider。通常來說,我們建議使用訪問控制而不是用戶權(quán)限確認(rèn)許可,因為權(quán)限會使用戶感到困惑。例如,考慮在權(quán)限設(shè)置上為應(yīng)用間的IPC通信使用單一開發(fā)者提供的簽名保護級別。

不要泄漏受許可保護的數(shù)據(jù)。只有當(dāng)應(yīng)用通過IPC暴露數(shù)據(jù)才會發(fā)生這種情況,因為它具有特殊權(quán)限,卻不要求任何客戶端的IPC接口有那樣的權(quán)限。更多關(guān)于這方面的潛在影響以及這種問題發(fā)生的頻率在USENIX: http://www.cs.be rkeley.edu/~afelt/felt_usenixsec2011.pdf研究論文中都有說明。

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

通常,你應(yīng)該力求建立擁有盡量少權(quán)限的應(yīng)用,直至滿足你的安全需要。建立一個新的權(quán)限對于大多數(shù)應(yīng)用相對少見,因為系統(tǒng)定義的許可覆蓋很多情況。在適當(dāng)?shù)牡胤绞褂靡呀?jīng)存在的許可執(zhí)行訪問檢查。

如果必須建立一個新的權(quán)限,考慮能否使用signature protection level來完成你的任務(wù)。簽名許可對用戶是透明的并且只允許相同開發(fā)者簽名的應(yīng)用訪問,與應(yīng)用執(zhí)行權(quán)限檢查一樣。如果你建立一個dagerous protction level,那么用戶需要決定是否安裝這個應(yīng)用。這會使其他開發(fā)者困惑,也使用戶困惑。

如果你要建立一個危險的許可,則會有多種復(fù)雜情況需考慮:

  • 對于用戶將要做出的安全決定,許可需要用字符串對其進(jìn)行簡短的表述。
  • 許可字符串必須保證語言的國際化。
  • 用戶可能對一個許可感到困惑或者知曉風(fēng)險而選擇不安裝應(yīng)用
  • 當(dāng)許可的創(chuàng)造者未安裝的時候,應(yīng)用可能要求許可。

上面每一個因素都為應(yīng)用開發(fā)者帶來了重要的非技術(shù)挑戰(zhàn),同時也使用戶感到困惑,這也是我們不建議使用危險許可的原因。

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

網(wǎng)絡(luò)交易具有很高的安全風(fēng)險,因為它涉及到傳送私人的數(shù)據(jù)。人們對移動設(shè)備的隱私關(guān)注日益加深,特別是當(dāng)設(shè)備進(jìn)行網(wǎng)絡(luò)交易時,因此應(yīng)用采取最佳方式保護用戶數(shù)據(jù)安全極為重要。

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

Android下的網(wǎng)絡(luò)與Linux環(huán)境下的差別并不大。主要考慮的是確保對敏感數(shù)據(jù)采用了適當(dāng)?shù)膮f(xié)議,比如使用HTTPS進(jìn)行網(wǎng)絡(luò)傳輸。我們在任何支持HTTPS的服務(wù)器上更愿意使用HTTPS而不是HTTP,因為移動設(shè)備可能會頻繁連接不安全的網(wǎng)絡(luò),比如公共WiFi熱點。

授權(quán)且加密的套接層級別的通信可通過使用SSLSocket類輕松實現(xiàn)??紤]到Android設(shè)備使用WiFi連接不安全網(wǎng)絡(luò)的頻率,對于所有應(yīng)用來說,使用安全網(wǎng)絡(luò)是極力鼓勵支持的。

我們發(fā)現(xiàn)部分應(yīng)用使用localhost端口處理敏感的IPC。我們不鼓勵這種方法,是因為這些接口可被設(shè)備上的其他應(yīng)用訪問。相反,你應(yīng)該在可認(rèn)證的地方使用Android IPC機制,例如Service(比使用回環(huán)還糟的是綁定INADDR_ANY,因為你的應(yīng)用可能收到來自任何地方來的請求,我們也已經(jīng)見識過了)。

一個有必要重復(fù)的常見議題是,確保不信任從HTTP或者其他不安全協(xié)議下載的數(shù)據(jù)。這包括在WebView中的輸入驗證和對于http的任何響應(yīng)。

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

SMS協(xié)議是Android開發(fā)者使用最頻繁的電話協(xié)議,主要為用戶與用戶之間的通信設(shè)計,但對于想要傳送數(shù)據(jù)的應(yīng)用來說并不合適。由于SMS的限制性,我們強烈建議使用Google Cloud Messaging(GCM)和IP網(wǎng)絡(luò)從web服務(wù)器發(fā)送數(shù)據(jù)消息給用戶設(shè)備應(yīng)用。

很多開發(fā)者沒有意識到SMS在網(wǎng)絡(luò)上或者設(shè)備上是不加密的,也沒有牢固驗證。特別是任何SMS接收者應(yīng)該預(yù)料到惡意用戶也許已經(jīng)給你的應(yīng)用發(fā)送了SMS:不要指望未驗證的SMS數(shù)據(jù)執(zhí)行敏感操作。你也應(yīng)該注意到SMS在網(wǎng)絡(luò)上也許會遭到冒名頂替并且/或者攔截,對于Android設(shè)備本身,SMS消息是通過廣播intent傳遞的,所以他們也許會被其他擁有READ_SMS許可的應(yīng)用截獲。

輸入驗證

無論應(yīng)用運行在什么平臺上,功能不完善的輸入驗證是最常見的影響應(yīng)用安全問題之一。Android有平臺級別的對策,用于減少應(yīng)用的公開輸入驗證問題,你應(yīng)該在可能的地方使用這些功能。同樣需要注意的是,選擇類型安全的語言能減少輸入驗證問題。

如果你使用native代碼,那么任何從文件讀取的,通過網(wǎng)絡(luò)接收的,或者通過IPC接收的數(shù)據(jù)都有可能引發(fā)安全問題。最常見的問題是buffer overflows,use after free,和off-by-one。Android提供安全機制比如ASLR和DEP以減少這些漏洞的可利用性,但是沒有解決基本的問題。小心處理指針和管理緩存可以預(yù)防這些問題。

動態(tài)、基于字符串的語言,比如JavaScript和SQL,都常受到由轉(zhuǎn)義字符和腳本注入帶來的輸入驗證問題。

如果你使用提交到SQL Database或者Content Provider的數(shù)據(jù),SQL注入也許是個問題。最好的防御是使用參數(shù)化的查詢,就像ContentProviders中討論的那樣。限制權(quán)限為只讀或者只寫可以減少SQL注入的潛在危害。

如果你不能使用上面提到的安全功能,我們強烈建議使用結(jié)構(gòu)嚴(yán)謹(jǐn)?shù)臄?shù)據(jù)格式并且驗證符合期望的格式。黑名單策略與替換危險字符是有效的,但這些技術(shù)在實踐中是易錯的并且當(dāng)錯誤可能發(fā)生的時候應(yīng)該盡量避免。

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

通常來說,處理用戶數(shù)據(jù)安全最好的方法是最小化獲取敏感數(shù)據(jù)用戶個人數(shù)據(jù)的API使用。如果你對數(shù)據(jù)進(jìn)行訪問并且可以避免存儲或傳輸,那就不要存儲和傳輸數(shù)據(jù)。最后,思考是否有一種應(yīng)用邏輯可能被實現(xiàn)為使用hash或者不可逆形式的數(shù)據(jù)。例如,你的應(yīng)用也許使用一個email地址的hash作為主鍵,避免傳輸或存儲email地址,這減少無意間泄漏數(shù)據(jù)的機會,并且也能減少攻擊者嘗試?yán)媚愕膽?yīng)用的機會。

如果你的應(yīng)用訪問私人數(shù)據(jù),比如密碼或者用戶名,記住司法也許要求你提供一個使用和存儲這些數(shù)據(jù)的隱私策略的解釋。所以遵守最小化訪問用戶數(shù)據(jù)最佳的安全實踐也許只是簡單的服從。

你也應(yīng)該考慮到應(yīng)用是否會疏忽暴露個人信息給其他方,比如廣告第三方組件或者你應(yīng)用使用的第三方服務(wù)。如果你不知道為什么一個組件或者服務(wù)請求個人信息,那么就不要提供給它。通常來說,通過減少應(yīng)用訪問個人信息,會減少這個區(qū)域潛在的問題。

如果必須訪問敏感數(shù)據(jù),評估這個信息是否必須要傳到服務(wù)器,或者是否可以被客戶端操作。考慮客戶端上使用敏感數(shù)據(jù)運行的任何代碼,避免傳輸用戶數(shù)據(jù) 確保不會無意間通過過渡自由的IPC、world writable文件、或網(wǎng)絡(luò)socket暴露用戶數(shù)據(jù)給其他設(shè)備上的應(yīng)用。這里有一個泄漏權(quán)限保護數(shù)據(jù)的特別例子,在Requesting Permissions章節(jié)中討論。

如果需要GUID,建立一個大的、唯一的數(shù)字并保存它。不要使用電話標(biāo)識,比如與個人信息相關(guān)的電話號碼或者IMEI。這個話題在Android Developer Blog中有更詳細(xì)的討論。

應(yīng)用開發(fā)者應(yīng)謹(jǐn)慎的把log寫到機器上。在Android中,log是共享資源,一個帶有READ_LOGS許可的應(yīng)用可以訪問。即使電話log數(shù)據(jù)是臨時的并且在重啟之后會擦除,不恰當(dāng)?shù)赜涗浻脩粜畔o意間泄漏用戶數(shù)據(jù)給其他應(yīng)用。

使用WebView

因為WebView能包含HTML和JavaScript瀏覽網(wǎng)絡(luò)內(nèi)容,不恰當(dāng)?shù)氖褂脮氤R姷膚eb安全問題,比如跨站腳本攻擊(JavaScript注入)。Android采取一些機制通過限制WebView的能力到應(yīng)用請求功能最小化來減少這些潛在的問題。

如果你的應(yīng)用沒有在WebView內(nèi)直接使用JavaScript,不要調(diào)用setJavaScriptEnabled()。某些樣本代碼使用這種方法,可能會導(dǎo)致在產(chǎn)品應(yīng)用中改變用途:所以如果不需要的話移除它。默認(rèn)情況下WebView不執(zhí)行JavaScript,所以跨站腳本攻擊不會產(chǎn)生。

使用addJavaScriptInterface()要特別的小心,因為它允許JavaScript執(zhí)行通常保留給Android應(yīng)用的操作。只把addJavaScriptInterface()暴露給可靠的輸入源。如果不受信任的輸入是被允許的,不受信任的JavaScript也許會執(zhí)行Android方法??偟脕碚f,我們建議只把addJavaScriptInterface()暴露給你應(yīng)用內(nèi)包含的JavaScript。

如果你的應(yīng)用通過WebView訪問敏感數(shù)據(jù),你也許想要使用clearCache()方法來刪除任何存儲到本地的文件。服務(wù)端的header,比如no-cache,能用于指示應(yīng)用不應(yīng)該緩存特定的內(nèi)容。

處理證書

通常來說,我們建議請求用戶證書頻率最小化--使得釣魚攻擊更明顯,并且降低其成功的可能。取而代之使用授權(quán)令牌然后刷新它。

可能的情況下,用戶名和密碼不應(yīng)該存儲到設(shè)備上,而使用用戶提供的用戶名和密碼執(zhí)行初始認(rèn)證,然后使用一個短暫的、特定服務(wù)的授權(quán)令牌??梢员欢鄠€應(yīng)用訪問的service應(yīng)該使用AccountManager訪問。 如果可能的話,使用AccountManager類來執(zhí)行基于云的服務(wù)并且不把密碼存儲到設(shè)備上。

使用AccountManager獲取Account之后,進(jìn)入任何證書前檢查CREATOR,這樣你就不會因為疏忽而把證書傳遞給錯誤的應(yīng)用。

如果證書只是用于你創(chuàng)建的應(yīng)用,那么你能使用checkSignature()驗證訪問AccountManager的應(yīng)用?;蛘?,如果一個應(yīng)用要使用證書,你可以使用KeyStore來儲存。

使用加密

除了采取數(shù)據(jù)隔離,支持完整的文件系統(tǒng)加密,提供安全信道之外。Android提供大量加密算法來保護數(shù)據(jù)。

通常來說,嘗試使用最高級別的已存在framework的實現(xiàn)來支持,如果你需要安全的從一個已知的位置取回一個文件,一個簡單的HTTPS URI也許就足夠了,并且這部分不要求任何加密知識。如果你需要一個安全信道,考慮使用HttpsURLConnection或者SSLSocket要比使用你自己的協(xié)議好。

如果你發(fā)現(xiàn)的確需要實現(xiàn)一個自定義的協(xié)議,我們強烈建議你不要自己實現(xiàn)加密算法。使用已經(jīng)存在的加密算法,比如Cipher類中提供的AES或者RSA。

使用一個安全的隨機數(shù)生成器(SecureRandom)來初始化加密密鑰(KeyGenerator)。使用一個不安全隨機數(shù)生成器生成的密鑰嚴(yán)重削弱算法的優(yōu)點,而且可能遭到離線攻擊。

如果你需要存儲一個密鑰來重復(fù)使用,使用類似于KeyStore的機制,來提供長期儲存和檢索加密密鑰的功能。

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

一些Android應(yīng)用試圖使用傳統(tǒng)的Linux技術(shù)實現(xiàn)IPC,比如網(wǎng)絡(luò)socket和共享文件。我們強烈鼓勵使用Android系統(tǒng)IPC功能,比如IntentBinder,MessengerBroadcastReceiver。Android IPC機制允許你為每一個IPC機制驗證連接到你的IPC和設(shè)置安全策略的應(yīng)用的身份。

很多安全元素通過IPC機制共享。Broadcast Receiver, Activitie,和Service都在應(yīng)用的manifest中聲明。如果你的IPC機制不打算給其他應(yīng)用使用,設(shè)置android:exported屬性為false。這對于同一個UID內(nèi)包含多個進(jìn)程的應(yīng)用,或者在開發(fā)后期決定不想通過IPC暴露功能并且不想重寫代碼的時候非常有用。

如果你的IPC打算讓別的應(yīng)用訪問,你可以通過使用Permission標(biāo)記設(shè)置一個安全策略。如果IPC是使用同一個密鑰簽名的獨立的應(yīng)用間的,使用signature更好一些。

使用Intent

Intent是Android中異步IPC機制的首選。根據(jù)你應(yīng)用的需求,你也許使用sendBroadcast(),sendOrderedBroadcast()或者直接的intent來指定一個應(yīng)用組件。

注意,有序廣播可以被Receiver接收,所以他們也許不會被發(fā)送到所有的應(yīng)用中。 如果你要發(fā)送一個intent給指定的Receiver,這個intent必須被直接的發(fā)送給這個Receiver。

Intent的發(fā)送者能在發(fā)送的時候驗證Receiver是否有一個許可指定了一個non-Null Permission。只有有那個許可的應(yīng)用才會收到這個intent。如果廣播intent內(nèi)的數(shù)據(jù)是敏感的,你應(yīng)該考慮使用許可來保證惡意應(yīng)用沒有恰當(dāng)?shù)脑S可無法注冊接收那些消息。這種情況下,可以考慮直接執(zhí)行這個Receiver而不是發(fā)起一個廣播。

注意:Intent過濾器不能作為安全特性--組件可被intent顯式調(diào)用,可能會沒有符合intent過濾器的數(shù)據(jù)。你應(yīng)該在Intent Receiver內(nèi)執(zhí)行輸入驗證,確認(rèn)對于調(diào)用Receiver,Service、或Activity來說格式正確合理。

使用服務(wù)

Service經(jīng)常被用于為其他應(yīng)用提供服務(wù)。每個service類必須在它的manifest文件進(jìn)行相應(yīng)的聲明。

默認(rèn)情況下,Service不能被導(dǎo)出和被其他應(yīng)用執(zhí)行。如果你加入了任何Intent過濾器到服務(wù)的聲明中,那么它默認(rèn)為可以被導(dǎo)出。最好明確聲明android:exported元素來確定它按照你設(shè)想的運行??梢允褂?a rel="external nofollow" target="_blank" target="_blank">android:permission保護Service。這樣做,其他應(yīng)用在他們自己的manifest文件中將需要聲明相應(yīng)的元素來啟動、停止或者綁定到這個Service上。

一個Service可以使用許可保護單獨的IPC調(diào)用,在執(zhí)行調(diào)用前通過調(diào)用checkCallingPermission()來實現(xiàn)。我們建議使用manifest中聲明的許可,因為那些是不容易監(jiān)管的。

使用binder和messenger接口

在Android中,BindersMessenger是RPC風(fēng)格IPC的首選機制。必要的話,他們提供一個定義明確的接口,促進(jìn)彼此的端點認(rèn)證。

我們強烈鼓勵在一定程度上,設(shè)計不要求指定許可檢查的接口。Binder和Messenger不在應(yīng)用的manifest中聲明,因此你不能直接在Binder上應(yīng)用聲明的許可。它們在應(yīng)用的manifest中繼承許可聲明,Service或者Activity內(nèi)實現(xiàn)了許可。如果你打算創(chuàng)建一個接口,在一個指定binder接口上要求認(rèn)證和/或者訪問控制,這些控制必須在Binder和Messenger的接口中明確添加代碼。

如果提供一個需要訪問控制的接口,使用checkCallingPermission()來驗證調(diào)用者是否擁有必要的許可。由于你的應(yīng)用的id已經(jīng)被傳遞到別的接口,因此代表調(diào)用者訪問一個Service之前這尤其重要。如果調(diào)用一個Service提供的接口,如果你沒有對給定的Service訪問許可,bindService()請求也許會失敗。如果調(diào)用你自己的應(yīng)用提供的本地接口,使用clearCallingIdentity()來進(jìn)行內(nèi)部安全檢查是有用的。

更多關(guān)于用服務(wù)運行IPC的信息,參見Bound Services

利用BroadcastReceiver

Broadcast receivers是用來處理通過intent發(fā)起的異步請求。

默認(rèn)情況下,Receiver是導(dǎo)出的,并且可以被任何其他應(yīng)用執(zhí)行。如果你的BroadcastReceiver打算讓其他應(yīng)用使用,你也許想在應(yīng)用的manifest文件中使用元素對receiver使用安全許可。這將阻止沒有恰當(dāng)許可的應(yīng)用發(fā)送intent給這個BroadcastReceiver

動態(tài)加載代碼

我們不鼓勵從應(yīng)用文件外加載代碼??紤]到代碼注入或者代碼篡改,這樣做顯著增加了應(yīng)用暴露的可能,同時也增加了版本管理和應(yīng)用測試的復(fù)雜性。最終可能造成無法驗證應(yīng)用的行為,因此在某些環(huán)境下應(yīng)該被限制。

如果你的應(yīng)用確實動態(tài)加載了代碼,最重要的事情是記住運行動態(tài)加載的代碼與應(yīng)用具有相同的安全許可。用戶決定安裝你的應(yīng)用是基于你的id,他們期望你提供任何運行在應(yīng)用內(nèi)部的代碼,包括動態(tài)加載的代碼。

動態(tài)加載代碼主要的風(fēng)險在于代碼來源于可確認(rèn)的源頭。 如果這個模塊是之間直接包含在你的應(yīng)用中,那么它們不能被其他應(yīng)用修改,不論代碼是本地庫或者是使用DexClassLoader加載的類這都是事實。我們見過很多應(yīng)用實例嘗試從不安全的地方加載代碼,比如從網(wǎng)絡(luò)上通過非加密的協(xié)議或者從全局可寫的位置(比如外部存儲)下載數(shù)據(jù)。這些地方會允許網(wǎng)絡(luò)上其他人在傳輸過程中修改其內(nèi)容,或者允許用戶設(shè)備上的其他應(yīng)用修改其內(nèi)容。

在虛擬機器安全性

Dalvik是安卓的運行時虛擬機(VM)。Dalvik是特別為安卓建立的,但許多其他虛擬機相關(guān)的安全代碼的也適用于安卓。一般來說,你不應(yīng)該關(guān)心與自己有關(guān)的虛擬機的安全問題。你的應(yīng)用程序在一個安全的沙盒環(huán)境下運行,所以系統(tǒng)上的其他進(jìn)程無法訪問你的代碼或私人數(shù)據(jù)。

如果你想更深入了解虛擬機的安全問題,我們建議您熟悉一些現(xiàn)有文獻(xiàn)的主題。推薦兩個比較流行的資源:

這個文檔集中于安卓與其他VM環(huán)境不同地方。對于有在其他環(huán)境下有VM編程經(jīng)驗開發(fā)者來說,這里有兩個普遍的問題可能對于編寫Android應(yīng)用來說有些不同:

  • 一些虛擬機,比如JVM或者.Net,擔(dān)任一個安全的邊界作用,代碼與底層操作系統(tǒng)隔離。在Android上,Dalvik VM不是一個安全邊界:應(yīng)用沙箱是在系統(tǒng)級別實現(xiàn)的,所以Dalvik可以在同一個應(yīng)用與native代碼相互操作,沒有任何安全約束。
  • 已知的手機上的存儲限制,對來發(fā)者來說,想要建立模塊化應(yīng)用和使用動態(tài)類加載是很常見的。要這么做的時候需要考慮兩個資源:一是在哪里恢復(fù)你的應(yīng)用邏輯,二是在哪里存儲它們。不要從未驗證的資源使用動態(tài)類加載器,比如不安全的網(wǎng)絡(luò)資源或者外部存儲,因為那些代碼可能被修改為包含惡意行為。

本地代碼的安全

一般來說,對于大多數(shù)應(yīng)用開發(fā),我們鼓勵開發(fā)者使用Android SDK而不是使用[Android NDK](http://developer.android.com/tools/sdk/ndk/index.html) 的native代碼。編譯native代碼的應(yīng)用更為復(fù)雜,移植性差,更容易包含常見的內(nèi)存崩潰錯誤,比如緩沖區(qū)溢出。

Android使用Linux內(nèi)核編譯并且與Linux開發(fā)相似,如果你打算使用native代碼,安全策略尤其有用。與Linux有關(guān)的安全問題超出了本文的討論范圍,但讀者可以參考Secure Programming for Linux and Unix HOWTO。

與大多數(shù)Linux環(huán)境的一個重要區(qū)別是應(yīng)用沙箱。在Android中,所有的應(yīng)用運行在應(yīng)用沙箱中,包括用native代碼編寫的應(yīng)用。在最基本的級別中,與Linux相似,對于開發(fā)者來說最好的方式是知道每個應(yīng)用被分配一個權(quán)限非常有限的唯一UID。這里討論的比Android Security Overview中更細(xì)節(jié)化,你應(yīng)該熟悉應(yīng)用許可,即使你使用的是native代碼。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號