最佳實務-android程式安全

來源:互聯網
上載者:User

自文章主要是翻譯的官網文章,同時也加入了自己的理解,如有不準確之處,請指正
http://developer.android.com/guide/practices/security.html

一些虛擬機器運行在一個安全邊界內,與所在的作業系統的程式隔離開來,比如java虛擬機器和.net 運行環境。
在android上,Dalvik虛擬機器沒有這樣的安全邊界,應用程式沙箱是實現在作業系統層級的,因此
在同一個程式,Dalvik與native code進行互動沒有任何的安全邊界。

給行動裝置閑置儲存策略。正常情況下,開發人員想建立模組化的應用程式,通過動態類載入實現。當做這件事的
時候要考慮兩個問題:程式邏輯和儲存位置。不要使用沒有檢查的class資源,比如不安全的網路資源或者外部儲存
裝置上的資源,因為這樣的資源可以被修改,可以包含進惡意的動作。

使用native code

一般情況下,我們建議開發人員使用android sdk開發大多數的程式,而不是使用native code。程式使用native code去
構建會更加的複雜,龐大,還有可能會有一些常見的記憶體使用量錯誤,比如緩衝區異常。

android是構建在Linux核心之上的,如果你熟悉Linux開發的話,使用native code是比較好。這個文檔只是用了很少的篇幅
介紹了這個最近實踐,要想瞭解更多關於為LInux和Unix編程安全的資源,請訪問這個網址http://www.dwheeler.com/secure-programs

android與其他的大多數Linux運行環境一個重要的不同是:程式沙箱。在android上,所有的程式都是在沙箱內運行,即使程式包含
native 代碼。熟悉Linux的開發人員都知道每個程式被分配一個唯一的UID和有限的許可權,當然即使你對Linux不熟悉,也要明白這一點。
如果你使用native code需要熟悉程式許可權的內容。http://source.android.com/tech/security/index.html

儲存資料
使用程式內部儲存
預設情況下,在程式內部建立的檔案只能被本程式使用。對於大多數程式的安全儲存已經足夠了。

在進程間使用全域的讀或者寫入權限不建議,這樣的話不能限制一些特定的程式去訪問資料,同時也不能控制資料格式。
做為一種選擇是,使用ContentProvider同讀寫允許,也可以根據具體情況動態授予是否允許訪問資料。

為了給敏感性資料提供更多的保護,一些程式選擇使用金鑰組本地檔案加密的方式。比如,密鑰放在keystore中,用
來保護使用者的密碼,而不是直接儲存在裝置上。然而這樣的情況下不能保護資料:裝置是root過的,使用者的輸入的密碼
可以被監聽到。可以保護有檔案加密系統的裝置丟失的情況。

使用外部儲存

在外部存放裝置上隱藏檔時全域的讀寫權限,比如在SD卡上。因為外部存放裝置可以使用者移除,可以被任何程式修改,
不要把敏感的資料使用外部存放裝置儲存。

對於從任何不可以信任的源擷取的資料,程式從外部儲存擷取的都應該對輸入進行檢查。我們強烈的建議不要在外部存放裝置上
儲存動態載入的可執行檔或者類檔案。如果程式從外部儲存載入可執行檔檔案,檔案必須是簽過名的和加密的,並且在載入前檢查。

使用內容提供者

ContentProvider提供一個儲存機制,這個機制可以限制自己的程式,也可以為其他程式提供一個訪問入口。預設情況下,
一個ContentProvider是其他程式提供給使用者的入口。如果你不想讓其他程式訪問你的ContentProvider,在manifest檔案中
這樣表明android:exported=false.

建立一個ContentProvider,將會為其他程式開啟了一個入口,你可以指定一個讀寫權限或者把讀寫權限分開指定。我們建議
你把許可權分開,按需分配。記住,通常情況為以後的新功能增加許可權更容易一些,而不是去移走他們,而影響已經存在的使用者。

如果ContentProvider是用來在同一個開發人員開發的兩個程式之間共用資料,應該傾向於使用簽名層級的許可權,簽名許可權不需要使用者確認,
因此會有更加好的使用者體驗,更多對ContentProvider的存取控制。

ContentProvider還尅提供更多反問聲明,通過grantUriPermison元素指定,使用FLAG_GRANT_READ_URI_PERMISSION 和 FLAG_GRANT_WRITE_URI_PERMISSION
這些標誌在Intent對象上。許可權的範圍可以同grant-uri-permisstion元素進一步限制。

當訪問ContentProvider的時候,使用帶參數的方法,例如query(),update()和delete(),可以防止不信任資料潛在的sql注入風險。
注意,如果使用組裝起來的資料提交到這些方法的話,使用參數化的方法還不夠安全。

不要有對寫入權限有這樣一個錯誤的看法,可以想象一下,寫入權限允許使用sql語句,使一些資料可以使用where子句組裝結果。
舉個例子,一個攻擊者可能為了查看一個已經存在的電話號碼,如果那個號碼已經存在的話,就在call-log修改一行資料。
如果這個內容提供者有個可被預見的結構的話,這個寫入權限會相當於同時提供了讀與寫入權限。

Using Interprocess Communication (IPC)
使用處理序間通訊

一些android程式企圖使用傳統的Linux處理序間通訊技術,比如網路socket和共用檔案。我們強烈件事使用android系統的進程
通訊技術,不如Intent,Binder,Service和Receiver.android的IPC機制允許你驗證程式串連你的IPC程式是否合法,可以
為IPC設定安全性原則。

很多安全性群組件都是通過IPC機制共用資料的。廣播接收者,活動,服務都是在程式的manifest中聲明的。如果你的IPC機制不想
讓其他的程式訪問,設定android:exported的屬性為false。這是非常有用處,對於多個程式的多個進程使用同一UID,或者
你後來決定不想通過IPC共用資料,就不需要重寫代碼了。

如果你的IPC是為了讓其他的程式器訪問的,你可以通過設定許可權標誌作為安全性原則。如果IPC是同一個開發人員的程式,
應該使用簽名層級的許可權控制,簽名許可權不需要使用者確認,因此會有一個更好的使用者體驗,更多的IPC存取控制。

使用intent過濾的地方容易混淆,注意,intent過濾不應該認為是安全的特徵,這個組件可以被直接調用,並且不會有
對intent過濾的確認。你應該執行輸入驗證,確保你的intent接受者接到receiver,service,和activity發送的格式正確。
 
Using intents

意圖是android中推薦的非同步IPC機制。基於你的程式需求,你可以使用sendBroadcaset(),sendOrderedBraodcast()或者
直接發送intent給指定的程式組件。

注意,ordered broadcast可以被所有的接收者消費掉,可能不會發送到所有的程式。如果你想發送給一個指定的接收者一個intent,這個intent必須直接發送
給指定的這個接受者。

如果沒有指定許可權限制的intent,可能會被別的接收者收到。限制成只有指定許可權的接收者才能收到這個intent.設定intent的許可權,可以
提高安全性。

使用 binder 和 AIDL 介面
binder是android遠程調用IPC的推薦機制。

We strongly encourage designing interfaces in a manner that does not require interface specific
 permission checks. Binders are not declared within the application manifest, and therefore you 
cannot apply declarative permissions directly to a Binder. Binders generally inherit permissions 
declared in the application manifest for the Service or Activity within which they are implemented. 
If you are creating an interface that requires authentication and/or access controls on a specific 
binder interface, those controls must be explicitly added as code in the interface.

If providing an interface that does require access controls, use checkCallingPermission() 
to verify whether the caller of the Binder has a required permission. This is especially 
important before accessing a Service on behalf of the caller, as the identify of your 
application is passed to other interfaces. If invoking an interface provided by a Service, 
the bindService() invocation may fail if you do not have permission to access the given Service. 
If calling an interface provided locally by your own application, it may be useful to use the
 clearCallingIdentity() to satisfy internal security checks.

使用ip網路:
建議使用Https協議的網路,其他不安全性通訊協定的網路盡量不要使用。當使用公用wiff熱點的時候,這些開放的網路都是沒有
加密的網路。

使用電話網路
有sms這個技術是為了人對人之間的通訊設計的,所以對於某些程式來說並不合適,建議使用C2DM和ip網路發送資料資訊到裝置。
sms在網路傳輸的過程中,沒有對資料加密,沒有很強的驗證機制。特別是,任何sms接收者都可以接收到惡意者發送的資訊到你的程式,
不要使用沒有經過認證的sms執行操作敏感資訊的命令。還有認識到一點,sms可能會被截獲或者通過sms進行欺騙。在android的裝置
上,SMS資訊傳輸是通過廣播意圖的形式發送的,因此訊息有可能被擁有能夠閱讀SMS許可權的程式給截獲閱讀。

動態載入代碼

我們強烈的不推薦apk程式不要從外部動態載入代碼。如果這樣做的話會增加代碼注入和代碼篡改的風險。
並且還會影響版本控制盒程式測試。最後,還會導致程式的行為不好驗證,因此在某些情況下程式會被阻止掉。

如果你的程式做了動態載入代碼,最重要的一點,要時刻記住動態載入的代碼所在的apk要和載入程式要有相同的安全許可權。使用者決定
安裝你的程式是基於統一的標示認證。

動態載入代碼最大的安全風險是驗證代碼來源。如果程式模組直接包含到你的apk中,那麼其他程式是不能去修改的。不管是native庫還是通過DexClassLoader載入的
代碼都是如此。我們已經遇到過很多程式去試圖載入不安全位元置的代碼,比如像從網路上下載沒有經過安全性通訊協定加密的代碼,或者從想外部儲存等
有全域寫入權限的位置載入代碼。這些位置會允許一些人在網路傳輸過程中修改資料的內容,或者安裝在裝置上的程式去修改資料內容。

使用 WebView

因為WebView這個組件可以解析HTML和Javascript等網頁內容,這樣可能會遇到一些常見的安全問題,比如跨站指令碼攻擊(cross-site-scripting,javascript注入)。
android包含了大量的安全機制用來減少這種跨域的譴責問題,像通過限制WebView使用最少功能這樣的措施。

如果你的程式中的WebView不直接使用Javascript的話,不要調用setJavaScriptEnabled()。預設情況下,WebView不會執行跨站指令碼
javascript的執行。

使用addJavaScriptInterface()時要特別注意,因為這樣可以允許javascript去調用android程式碼去執行程式。
只把addJavaScriptInterface()開放給信任的輸入源,如果不是這樣的話有時會使不信任的javascript去調用android的函數。
通常情況下,我們推薦只對本程式內的javascript開放addJavaScriptInterface()入口。

不要相信通過http下載的資料,要使用Https代替。如果你僅是訪問單個網站,即使是信任並且可控的,HTTP可能會受到中間過程的攻擊,
傳輸過程中資料被截取。在使用addJavaScriptInterface()的時候要提高警惕,一定不要相信通過http下載的沒有經過驗證的指令碼。
注意:即使是用的https,addJavaScriptInterface()也會增加了程式被攻擊的可能性,雖然包括伺服器的進行了安全設定和android裝置擁有所有的信任的CA。

如果你同過WebView訪問敏感資訊,你應該通過clearCache()方法去刪除儲存在本地的任何快取檔案。伺服器端的小訊息頭可以使用
像no-cache這樣的標誌去告訴程式不要緩衝特定的內容。

執行輸入檢查

一個常見的安全問題是沒有對輸入進行充足的安全檢查就直接讓其運行。android有一個平台層級的措施去減少暴露給程式沒有進行輸入檢查的問題,
你應該儘可能的在可以使用的任何地方去使用這個特性。同時要注意,選擇安全類型的語言可以減少輸入驗證的問題。我們強烈建議使用android SDK
去構建你的程式。

如果使用從檔案,網路,IPC上擷取的native code,也會增加潛在的安全問題。常見的問題是緩衝區溢位,使用者退出,off-by-one錯誤等。android
提供了很多像ASLR和DEP的技術去減少開發時的那些錯誤,但是他們不能解決這些潛在的錯誤。那些技術可以用來預防指標控制和緩衝區管理的問題。

動態,基於字串的語言,像javascript和sql語言,進行輸入檢查可以防止特殊字元和指令碼注入問題。

如果經行資料查詢的時候有使用sql資料庫或者內容提供者的時候,sql注入會使一個問題。最後的反擊措施是使用參數化的查詢,就想在內容提供者
部分介紹的一樣。限制成唯讀和唯寫許可權也可以減少潛在的sql注入風險。

如果你使用WebView一定要考慮誇張指令碼攻擊(XSS)的可能性。如果你的程式,WebView不直接使用javascript,
不要調用setJavaScriptEnabled(),那麼XSS就不會發生。如果程式必須使用javascript,那麼要考慮其他的安全措施
去防止XSS。

如果你不能使用上述的安全特性,我們強烈建議使用良好結構的資料格式,並且充分驗證資料格式,同時要做好特殊字元黑名單,和字元替換庫,這樣
會使一個比較有效策略。這些技術是使用的過程中非常容易出錯,所以一定要盡量的避免出現錯誤。

處理使用者資料

通常情況下,最有效方式是盡量的少使用API去訪問敏感性資料和個人資訊。如果真的訪問的了這些資料的話,那麼就不乣儲存和傳輸這些資料。
最後,考慮使用一種方式是,使用雜湊演算法或者無法復原的演算法方式去處理資料。比如,如果你的程式使用hash演算法用對email的雜湊值作為key,一定要
避免儲存和傳輸email地址。這樣可以防止因為疏忽而把資料暴露在外面,這樣也可以減少暴露在外面的程式被攻擊的機會。

如果你的程式要訪問想使用者名稱,密碼之類的個人資訊是,一定要記住使用隱私協議去解釋你使用和儲存的資訊。因此,
在後面的的安全最佳實務中,要盡量的減少訪問使用者資料

你也需要考慮你的程式是否會在不經意間把個人資訊暴露給其他的程式部分,比如像在你的程式中使用的第三方廣告組件或者第三方服務等。
如果你不知道為什麼這些組件或者服務需要個人資訊幹什麼的話,就不要提供給程式。通常情況下,減少訪問個人資訊,可以減少程式潛在的
安全問題。

如果必須要訪問敏感性資料,要評估一下這些資料是否要傳輸到伺服器,或者是否要在用戶端執行。允許在用戶端的代碼用到敏感性資料的
時候要盡量禁止使用者資料的傳輸。

同時要確保,不要把使用者資料通過寬鬆的IPC,全域可寫的檔案,或者網路不經意間暴露給其他程式。這裡有一個關於許可權重複授權的特殊案例將在請求許可權
的部分討論。

建立一個數比較大,唯一的全域唯一標識儲存它是非常必要的。不要使用像電話號碼或者IMEI這樣的電話的標識,因為這些關係到個人資訊。
這個話題的更多資訊在android開發人員部落格上。http://android-developers.blogspot.com/2011/03/identifying-app-installations.html

程式開發人員需要特別注意寫在裝置上的日誌資訊,在android上,日誌是共用資源,要防止程式擁有READ_LOGS許可權。
即使手機的日誌是臨時的或者重啟就刪除的,記錄使用者資訊的日誌有可能會泄露使用者的資訊給其他程式。

Handling Credentials
處理憑證
通常情況下,我建議最小頻率的要使用者的憑證資訊,可以減少釣魚攻擊的成功率。而是使用授權令牌的方式,並且要重新整理權杖。

不管任何情況下都不要把使用者名稱密碼儲存在裝置上。
只有在第一次認證的時候需要使用使用者提供的使用者名稱和密碼,並且使用短活動周期,指定服務的授權令牌。

如果一個服務需要訪問多個程式的話,應該需要使用AccountManager.如果可能的話,使用AcctountMangaer類去調用雲端服務,不要把
密碼儲存在裝置上。http://developer.android.com/reference/android/accounts/AccountManager.html

After using AccountManager to retrieve an Account, check the CREATOR before passing in any credentials, 
so that you do not inadvertently pass credentials to the wrong application.
使用AccountManager取回帳號後,傳遞憑證之前都要檢查一下建立者,不要把憑證傳給錯誤的程式。

如果憑證資訊之允許自己程式使用,當程式訪問AccounManager的時候要使用checkSignature()這個方法去雁陣程式的簽名。
如果只有一個程式訪問憑證資訊,可以使用KeyStore去儲存憑證資訊。

Using Cryptography
使用加密技術

增加資料的隔離,可以支援全檔案系統的加密,提供安全通道訪問。android提供了多種數組密碼編譯演算法保護資料。

通常情況下,使用已經存在的進階別的架構可以支援大多數使用方式。如果你需要安全的從一個位置取迴文件,簡單的Https URI已經足夠滿足了。
如果你需要一個安全通道,考慮使用HttpsURLConnection or SSLSocket,而不是去寫自己的協議。

If you do find yourself needing to implement your own protocol, we strongly recommend that you not implement your
 own cryptographic algorithms. Use existing cryptographic algorithms such as those in the implementation of AES or 
RSA provided in the Cipher class.
如果你需要實現自己的協議,強烈建議不要實現自己的密碼編譯演算法。通過Cipher類使用已經存在的密碼編譯演算法,比如AES或者RSA。

使用安全的隨機數產生器(SecureRandom)去初始化任何加密的key(KeyGenerator).如果使用的key不是用安全產生的隨機數的話,會減少加密強度,
並且會允許離線攻擊。

如果你想把key存起來重複使用的話,可以使用想KeyStore之類的機制,通過加密金鑰進行長期的存取。

結論
android為開發人員提哦那個了設計程式安全多種措施。這些最佳實務確保你的程式能從安全擷取一些受益。

You can receive more information on these topics and discuss security best practices with 
other developers in the Android Security Discuss Google Group

你可以在Android Security Discuss Google Group中看到更多關於安全的話題或者討論。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.