安卓開發開發規範手冊V1.0

  • 2019 年 10 月 3 日
  • 筆記

安卓開發開發規範手冊V1.0

之前發佈過一份Web安全開發規範手冊V1.0,看到收藏文章的讀者挺多,發現整理這些文檔還挺有意義。

最近周末抽了些時間把之前收集關於安卓安全開發的資料也整理了一下,整理出一份安卓安全開發手冊,大部分內容都是在一些博客看到各位師傅的分享。

一、manifest文件安全

1.1 禁止PermissionGroup的屬性為空

PermissionGroup可以對permission進行一個邏輯上的分組。如果PermissionGroup的屬性為空,會導致權限定義無效,且其他app無法使用該權限。

開發建議

設置PermissionGroup屬性值或者不使用PermissionGroup

1.2 系統權限確認

App如果使用一些系統限制權限,諸如android.permission.WRITE_SECURE_SETTINGS和android.permission.INSTALL_PACKAGES,則該app應該是設備自帶的系統或google自帶的app,並且應該放置在/system/app目錄下。否則就是一個惡意app。

App使用下述權限,則該app有較高權限,要謹慎使用。

android.permission.MOUNT_FORMAT_FILESYSTEMS,    android.permission.MOUNT_UNMOUNT_FILESYSTEMS,    android.permission.RESTART_PACKAGES。

開發建議

根據業務需求,如非必要,移除該權限。

1.3 protectionLevel屬性設置

由於對app的自定義permission的protectionLevel屬性設置不當,會導致組件(如:content provider)數據泄露危險。最好的權限設置應為signature或signatureOrSystem,進而避免被第三方應用利用。

開發建議

注意使用signature或signatureOrSystem防止其他app註冊或接受該app的消息,提高安全性。

1.4 合理設置sharedUserId權限

通過sharedUserId,可以讓擁有同一個User Id的多個apk運行在同一個進程中,互相訪問任意資源。將sharedUserId設置為android.uid.system,可以把app放到系統進程中,app將獲得極大的權限。如果app同時有master key漏洞,容易導致被root。

開發建議

合理設置軟件權限。

1.5 設置allowBackup為false

當這個標誌被設置成true或不設置該標誌位時,應用程序數據可以備份和恢復,adb調試備份允許惡意攻擊者複製應用程序數據。

開發建議

設置AndroidManifest.xml的android:allowBackup標誌為false。

影響範圍

API >= 8

1.6 禁止Debuggable為true

在AndroidManifest.xml中定義Debuggable項,如果該項被打開,app存在被惡意程序調試的風險,可能導致泄露敏感信息等問題。

開發建議

顯示的設置AndroidManifest.xml的debuggable標誌為false。

二、組件安全

2.1 合理設置導出Activity、activity-alias、service、receiver

Activity、activity-alias、service、receiver組件對外暴露會導致數據泄露和惡意的dos攻擊。

開發建議

  1. 最小化組件暴露。對不會參與跨應用調用的組件添加android:exported=false屬性。
  2. 設置組件訪問權限。對跨應用間調用的組件或者公開的receiver、service、activity和activity-alias設置權限,同時將權限的protectionLevel設置為signature或signatureOrSystem。
  3. 組件傳輸數據驗證。對組件之間,特別是跨應用的組件之間的數據傳入與返回做驗證和增加異常處理,防止惡意調試數據傳入,更要防止敏感數據返回。

2.2 Contentprovider信息泄露風險

provider組件導出可能會帶來信息泄露隱患。api level在17以下的所有應用的android:exported屬性默認值為true,17及以上默認值為false。

開發建議

  1. 最小化組件暴露。對不會參與跨應用調用的組件添加android:exported=false屬性。
  2. 設置組件訪問權限。對導出的provider組件設置權限,同時將權限的protectionLevel設置為signature或signatureOrSystem。
  3. 由於Contentprovider無法在2(API-8)申明為私有。故建議將min sdk設為8以上。

影響範圍

api level在17以下的所有應用的android:exported屬性默認值為true,17及以上默認值為false。

2.3 嚴格過濾openFile對uri訪問

該漏洞由於Content provider組件暴露,沒有對Content provider組件訪問權限進行限制且對Uri路徑沒有進行過濾,攻擊者通過Content provider實現的OpenFile接口進行攻擊,如通過../的方式訪問任意的目錄文件,造成隱私泄露。

開發建議

  1. 將不必要導出的Content provider設置為不導出
  2. 由於Android組件Content provider無法在Android 2.2(即API Level 8)系統上設為不導出,因此如果應用的Content provider不必要導出,阿里聚安全建議聲明最低SDK版本為8以上版本;
  3. 由於API level 在17以下的所有應用的android:exported屬性默認值都為,因此如果應用的Content provider不必要導出,阿里聚安全建議顯示設置註冊的Content provider組件的android:exported屬性為false;
  4. 去除沒有必要的penFile()接口
  5. 如果應用的Content provider組件沒有必要實現penFile()接口,阿里聚安全建議移除該Content provider的不必要的penFile()接口。
  6. 過濾限制跨域訪問,對訪問的目標文件的路徑進行有效判斷
  7. 使用decode()先對Content Query Uri進行解碼後,再過濾如可通過../實現任意可讀文件的訪問的Uri字符串;
  8. 設置權限來進行內部應用通過Content provider的數據共享
  9. 使用簽名驗證來控制Content provider共享數據的訪問權限,如設置protectionLevel=signature或signatureOrSystem;
  10. 公開的content provider確保不存儲敏感數據
  11. 提供asset文件時注意權限保護

2.4 使用顯式Intent 調用bindService()

創建隱式Intent 時,Android 系統通過將Intent 的內容與在設備上其他應用的清單文件中聲明的Intent 過濾器進行比較,從而找到要啟動的相應組件。如果Intent 與Intent 過濾器匹配,則系統將啟動該組件,並將其傳遞給對象。如果多個Intent 過濾器兼容,則系統會顯示一個對話框,支持用戶選取要使用的應用。

為了確保應用的安全性,啟動Service 時,請始終使用顯式Intent,且不要為服務聲明Intent 過濾器。使用隱式Intent 啟動服務存在安全隱患,因為您無法確定哪些服務將響應Intent,且用戶無法看到哪些服務已啟動。從Android 5.0(API 級別21)開始,如果使用隱式Intent 調用bindService(),系統會拋出異常。

開發建議

為了確保應用的安全性,啟動 Service 時,請始終使用顯式 Intent,且不要為服務聲明 Intent 過濾器。使用隱式 Intent 啟動服務存在安全隱患,因為您無法確定哪些服務將響應Intent,且用戶無法看到哪些服務已啟動。從 Android 5.0(API 級別 21)開始,如果使用隱式 Intent 調用 bindService(),系統會拋出異常。

影響範圍

全部。從Android 5.0(API 級別21)開始,如果使用隱式Intent 調用bindService(),系統會拋出異常。

2.5 合理處理Intent Scheme URL

Intent Scheme URI是一種特殊的URL格式,用來通過Web頁面啟動已安裝應用的Activity組件,大多數主流瀏覽器都支持此功能。

Android Browser的攻擊手段——Intent Scheme URLs攻擊。這種攻擊方式利用了瀏覽器保護措施的不足,通過瀏覽器作為橋樑間接實現Intend-Based攻擊。相比於普通Intend-Based攻擊,這種方式極具隱蔽性,

如果在app中,沒有檢查獲取到的load_url的值,攻擊者可以構造釣魚網站,誘導用戶點擊加載,就可以盜取用戶信息。所以,對Intent URI的處理不當時,就會導致基於Intent的攻擊。

如果瀏覽器支持Intent Scheme URI語法,一般會分三個步驟進行處理:

  1. 利用parseUri解析uri,獲取原始的intent對象;
  2. 對intent對象設置過濾規則;
  3. 通過startActivityIfNeeded或者startActivity發送intent;其中步驟2起關鍵作用,過濾規則缺失或者存在缺陷都會導致Intent Schem URL攻擊。

關鍵點

Intent.parseUri函數,通過掃描出所有調用了Intent.parseUri方法的路徑,並檢測是否使用如下的策略。

比較安全的使用Intent Scheme URI方法是:

如果使用了Intent.parseUri函數,獲取的intent必須嚴格過濾,intent至少包含addCategory(android.intent.category.BROWSABLE),setComponent(null),setSelector(null)3個策略。

所以,在檢的時候只要根據Intent.parseUri函數返回的Intent對象有沒有按照以下方式實現即可做出判斷:

// convert intent scheme URL to intent object    Intent intent = Intent.parseUri(uri);     // forbid launching activities without BROWSABLE category    intent.addCategory(android.intent.category.BROWSABLE);    // forbid explicit call    intent.setComponent(null);     // forbid intent with selector intent  intent.setSelector(null);    // start the activity by the intent    context.startActivityIfNeeded(intent, -1)

開發建議

如果使用了Intent.parseUri函數,獲取的intent必須嚴格過濾,intent至少包含addCategory(android.intent.category.BROWSABLE),setComponent(null),setSelector(null)3個策略。除了以上做法,最佳處理不要信任任何來自網頁端的任何intent,為了安全起見,使用網頁傳過來的intent時,要進行過濾和檢查

2.6 本地拒絕服務

Android系統提供了Activity、Service和Broadcast Receiver等組件,並提供了Intent機制來協助應用間的交互與通訊,Intent負責對應用中一次操作的動作、動作涉及數據、附加數據進行描述,Android系統則根據此Intent的描述,負責找到對應的組件,將Intent傳遞給調用的組件,並完成組件的調用。Android應用本地拒絕服務漏洞源於程序沒有對Intent.GetXXXExtra()獲取的異常或者畸形數據處理時沒有進行異常捕獲,從而導致攻擊者可通過向受害者應用發送此類空數據、異常或者畸形數據來達到使該應用Crash的目的,簡單的說就是攻擊者通過Intent發送空數據、異常或畸形數據給受害者應用,導致其崩潰。

對導出的組件傳遞一個不存在的序列化對象,若沒有try…catch捕獲異常就會崩潰

ComponentName cn = new ComponentName(com.test, com.test.TargetActivity)    Intent i = new Intent()    i.setComponentName(cn)    i.putExtra(key, new CustomSeriable())    startActivity(i)    **public class DataSchema implements Serializable {**            public DataSchema() {                    super();            }    }

2.6.1 NullPointerException 異常導致的拒絕服務

源於程序沒有對getAction()等獲取到的數據進行空指針判斷,從而導致了空指針異常導致應用崩潰

風險代碼:

Intent i = new Intent();    if (i.getAction().equals(TestForNullPointerException)) {        Log.d(TAG, Test for Android Refuse Service Bug);    }

2.6.2 ClassCastException 異常導致的拒絕服務

源於程序沒有對getSerializableExtra()等獲取到的數據進行類型判斷而進行強制類型轉換,從而導致類型轉換異常導致拒絕服務漏洞

風險代碼:

Intent i = getIntent();    String test = (String) i.getSerializableExtra(serializable_key);    **IndexOutOfBoundsException 異常導致拒絕服務漏洞**

源於程序沒有對getIntegerArrayListExtra()等獲取到的數據數組元素大小判斷,導致數組訪問越界而造成拒絕服務漏洞

風險代碼:

Intent intent = getIntent();    ArrayList<Integer> intArray = intent.getIntegerArrayListExtra(user_id);    if (intArray != null) {        for (int i = 0; i < 10; i++) {            intArray.get(i);        }    }

2.6.3 ClassNotFoundException 異常導致的拒絕服務漏洞

Intent i = getIntent();    getSerializableExtra(key);

開發建議

  1. 將比不要導出的組建設置為不導出
  2. 在處理Intent數據時,進行捕獲異常,通過getXXXExtra()獲取的數據時進行以下判斷,以及用try catch方式捕獲所有異常,防止出現拒絕服務漏洞,包括:空指針異常、類型轉換異常、數組越界訪問異常、類未定義異常、其他異常
Try{        ....    xxx.getXXXExtra()    ....    }Catch Exception{    **   **  **// 為空即可**    }

2.7 合理定義android.intent.category.BROWSABLE

在AndroidManifest文件中定義了android.intent.category.BROWSABLE屬性的組件,可以通過瀏覽器喚起,這會導致遠程命令執行漏洞攻擊

開發建議

  1. APP中任何接收外部輸入數據的地方都是潛在的攻擊點,過濾檢查來自網頁的參數
  2. 不要通過網頁傳輸敏感信息,有的網站為了引導已經登錄的用戶到APP上使用,會使用腳本動態的生成URL Scheme的參數,其中包括了用戶名、密碼或者登錄態token等敏感信息,讓用戶打開APP直接就登錄了。惡意應用也可以註冊相同的URL Sechme來截取這些敏感信息。Android系統會讓用戶選擇使用哪個應用打開鏈接,但是如果用戶不注意,就會使用惡意應用打開,導致敏感信息泄露或者其他風險。

2.8 刪除Debug和Test信息

一些app在正式發佈前,為了方便調試app,都會在app里集成一些調試或測試界面。這些測試界面可能包含敏感的信息。

開發建議

在正式發佈前移除所有的測試組件

2.9 Intent不安全反射風險

通過Intent接收的Extra參數來構造反射對象會導致從不受信任的源加載類。攻擊者可以通過巧妙地構造達到加載其它類的目的

兩個關鍵函數,分別是:getIntent()和Class.forName(….)

public class SecondActivity extends Activity {            @Override                protected void onCreate(Bundle savedInstanceState) {                    super.onCreate(savedInstanceState);                    setContentView(R.layout.activity_second);                    Intent intent = getIntent();                    String className = intent.getStringExtra(className);                    String methodName = intent.getStringExtra(methodName);                    try {                            Class<?> clz = null;                            clz = Class.forName(className);                            Date object = (Date) clz.newInstance();                            Method method = clz.getMethod(methodName);                            Toast.makeText(getApplicationContext(), method.invoke(object, null) + ======, Toast.LENGTH_LONG).show();                    } catch (Exception e) {                            e.printStackTrace();                    }            }    }

逆向後對應的smali代碼如下:

  invoke-virtual {p0}, Lcom/bug/intent/reflection/SecondActivity;->getIntent()Landroid/content/Intent;    invoke-static {v0}, Ljava/lang/Class;->forName(Ljava/lang/String;)Ljava/lang/Class;  

開發建議

  1. 不要通過Intent接收的Extra傳播的反射函數
  2. 將接受反射的組件設置為非導出組件

三、webview組件安全

3.1 WebView遠程執行漏洞

和WebView遠程代碼執行相關的漏洞主要有CVE-2012-6336,CVE-2014-1939,CVE-2014-7224, 這些漏洞中最核心的漏洞是CVE-2012-6336,另外兩個CVE只是發現了幾個默認存在的接口。

Android API < 17之前版本存在遠程代碼執行安全漏洞,該漏洞源於程序沒有正確限制使用addJavaScriptInterface(CVE-2012-6636)方法,攻擊者可以通過Java反射利用該漏洞執行任意Java對象的方法,導致遠程代碼執行安全漏洞除。

開發建議

  1. API等於高於17的Android系統。出於安全考慮,為了防止Java層的函數被隨意調用,Google在2版本之後,規定允許被調用的函數必須以@JavascriptInterface進行註解。
  2. API等於高於17的Android系統。建議不要使用addJavascriptInterface接口,以免帶來不必要的安全隱患,如果一定要使用該接口:

  3. 如果使用https協議加載url,應用進行證書校驗防止訪問的頁面被篡改掛馬
  4. 如果使用http協議加載url,應進行白名單過濾、完整性校驗等防止訪問的頁面被篡改
  5. 如果加載本地html,應將html文件內置在apk中,以及進行對html頁面完整性的校驗

  6. 使用removeJavascriptInterface移除Android系統內部的默認內置接口:searchBoxJavaBridge_、accessibility、accessibilityTraversal

範圍:

CVE-2012-6636

Android API 16.0及之前的版本中存在安全漏洞,該漏洞源於程序沒有正確限制使用WebView.addJavascriptInterface方法。遠程攻擊者可通過使用Java Reflection API利用該漏洞執行任意Java對象的方法

Google Android <= 4.1.2 (API level 16) 受到此漏洞的影響。

CVE-2014-1939

java/android/webkit/BrowserFrame.java

使用addJavascriptInterface API並創建了SearchBoxImpl類的對象。攻擊者可通過訪問searchBoxJavaBridge_接口利用該漏洞執行任意Java代碼。

Google Android <= 4.3.1 受到此漏洞的影響

CVE-2014-7224

香港理工大學的研究人員發現當系統輔助功能中的任意一項服務被開啟後,所有由系統提供的WebView都會被加入兩個JS objects,分別為是accessibility和accessibilityTraversal。惡意攻擊者就可以使用accessibility和accessibilityTraversal這兩個Java Bridge來執行遠程攻擊代碼.

Google Android < 4.4 受到此漏洞的影響。

3.2 WebView潛在XSS攻擊

允許WebView執行JavaScript(setJavaScriptEnabled),有可能導致XSS攻擊。

開發建議

應盡量避免使用。如果一定要使用:

  1. API等於高高於17的Android系統。出於安全考慮,為了防止Java層的函數被隨意調用,Google在2版本之後,規定允許被調用的函數必須以@JavascriptInterface進行註解。
  2. API等於高高於17的Android系統。建議不要使用addJavascriptInterface接口,一面帶來不必要的安全隱患,如果一定要使用該接口:

  3. 如果使用https協議加載url,應用進行證書校驗防止訪問的頁面被篡改掛馬
  4. 如果使用http協議加載url,應進行白名單過濾、完整性校驗等防止訪問的頁面被篡改
  5. 如果加載本地html,應將html文件內置在apk中,以及進行對html頁面完整性的校驗

  6. 使用removeJavascriptInterface移除Android系統內部的默認內置接口:searchBoxJavaBridge_、accessibility、accessibilityTraversal

影響範圍

Android api <17

3.3 WebView File域同源策略繞過

應用程序一旦使用WebView並支持File域,就會受到該漏洞的攻擊。該漏洞源於:JavaScript的延時執行能夠繞過file協議的同源檢查,並能夠訪問受害應用的所有私有文件,即通過WebView對Javascript的延時執行和將當前Html文件刪除掉並軟連接指向其他文件就可以讀取到被符號鏈接所指的文件,然後通過JavaScript再次讀取HTML文件,即可獲取到被符號鏈接所指的文件。

大多數使用WebView的應用都會受到該漏洞的影響,惡意應用通過該漏洞,可在無特殊權限下盜取應用的任意私有文件,尤其是瀏覽器,可通過利用該漏洞,獲取到瀏覽器所保存的密碼、Cookie、收藏夾以及歷史記錄等敏感信息,從而造成敏感信息泄露。

開發建議

  1. 將不必要導出的組件設置為不導出

    如果應用的組件不必要導出,建議顯式設置所註冊組件的android:exported屬性為false;

  2. 如果需要導出組件,禁止使用File域

    如果應用的需要導出包含WebView的組件,建議禁止使用File域協議:

myWebView.getSettings. setAllowFileAccess(false);

  1. 如果需要使用File協議,禁止File協議調用JavaScript

    如果應用的WebView需要使用File域協議,建議禁止File域協議調用JavaScript:

myWebView.getSettings. setJavaScriptEnabled(false);

3.4 禁止webview密碼明文存儲

webview的保存密碼功能默認設置為true。Webview會明文保存網站上的密碼到本地私有文件databases/webview.db中。對於可以被root的系統環境或者配合其他漏洞(如webview的同源繞過漏洞),攻擊者可以獲取到用戶密碼。

image

開發建議

顯示設置webView.getSetting().setSavePassword(false)

3.5 主機名弱校驗漏洞

自定義HostnameVerifier類,卻不實現verify方法驗證域名,導致中間人攻擊漏洞。

開發建議

自定義HostnameVerifier類並實現verify方法驗證域名。

3.6 證書弱校驗漏洞

App在實現X509TrustManager時,默認覆蓋google默認的證書檢查機制方法:checkClientTrusted、checkServerTrusted和getAcceptedIssuers,會導致中間人攻擊漏洞。

開發建議

如果自己創建X509Certificate,則在覆蓋checkClientTrusted、checkServerTrusted和getAcceptedIssuers後要進行校驗。

3.7 中間人攻擊漏洞

App調用setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER),信任所有主機名,會導致中間人攻擊。

開發建議

查找所有設置了ALLOW_ALL_HOSTNAME_VERIFIER字段屬性的方法路徑;對信任的主機嚴格認證

3.8 WebView不校驗證書漏洞

Android WebView組件加載網頁發生證書認證錯誤時,會調用WebViewClient類的onReceivedSslError方法,如果該方法實現調用了handler.proceed()來忽略該證書錯誤,則會受到中間人攻擊的威脅,可能導致隱私泄露。

自定義實現的WebViewClient類在onReceivedSslError是否調用proceed()方法。

開發建議

當發生證書認證錯誤時,採用默認的處理方法handler.cancel(),停止加載問題頁面當發生證書認證錯誤時,採用默認的處理方法handler.cancel(),停止加載問題頁面

3.9 WebView組件系統隱藏接口未移除

android webview組件包含3個隱藏的系統接口:searchBoxJavaBridge_,accessibilityTraversal以及accessibility,惡意程序可以利用它們實現遠程代碼執行。

風險代碼:

const-string v3, searchBoxJavaBridge_    invoke-virtual {v1, v3}, Landroid/webkit/WebView;->removeJavascriptInterface(Ljava/lang/String;)V    const-string v3, accessibility    invoke-virtual {v1, v3}, Landroid/webkit/WebView;->removeJavascriptInterface(Ljava/lang/String;)V    const-string v3, accessibilityTraversal    invoke-virtual {v1, v3}, Landroid/webkit/WebView;->removeJavascriptInterface(Ljava/lang/String;)V

開發建議

使用了WebView,那麼使用WebView.removeJavascriptInterface(String name) API,顯示的移除searchBoxJavaBridge_、accessibility、accessibilityTraversal這三個接口

影響範圍

4.0~4.4(不包含)

四、sqlite安全

4.1 SQLite sql注入漏洞

SQLite做為android平台的數據庫,對於數據庫查詢,如果開發者採用字符串鏈接方式構造sql語句,就會產生sql注入。

開發建議

  1. provider不需要導出,請將export屬性設置為false
  2. 若導出僅為內部通信使用,則設置protectionLevel=signature
  3. 不直接使用傳入的查詢語句用於projection和selection,使用由query綁定的參數selectionArgs
  4. 完備的SQL注入語句檢測邏輯

4.2 Databases任意讀寫漏洞

APP在使用openOrCreateDatabase創建數據庫時,將數據庫設置了全局的可讀權限,攻擊者惡意讀取數據庫內容,獲取敏感信息。在設置數據庫屬性時如果設置全局可寫,攻擊者可能會篡改、偽造內容,可以能會進行詐騙等行為,造成用戶財產損失。

開發建議

  1. 用MODE_PRIVATE模式創建數據庫
  2. 使用sqlcipher等工具加密數據庫
  3. 避免在數據庫中存儲明文和敏感信息

網絡通信安全

5.1 SSL不安全組件

SSLCertificateSocketFactory#getInsecure方法無法執行SSL驗證檢查,使得網絡通信遭受中間人攻擊。

開發建議

移除SSLCertificateSocketFactory#getInsecure方法。

5.2 HttpHost安全

HttpHost target = new HttpHost(uri.getHost(), uri.getPort(), HttpHost.DEFAULT_SCHEME_NAME);

HttpHost.DEFAULT_SCHEME_NAME默認是http,不安全。

開發建議

改成使用https

5.3 HttpURLConnection漏洞

在Android 2.2版本之前,HttpURLConnection一直存在着一些令人厭煩的bug。比如說對一個可讀的InputStream調用close()方法時,就有可能會導致連接池失效了。

開發建議

判斷Android版本,並設置http.keepAlive為false。

private void disableConnectionReuseIfNecessary() {            // Work around pre-Froyo bugs in HTTP connection reuse.            if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {                    System.setProperty(http.keepAlive, false);            }    }

影響範圍

2.2版本之前

六、弱加密風險檢測

6.1 禁止使用弱加密算法

安全性要求高的應用程序必須避免使用不安全的或者強度弱的加密算法,現代計算機的計算能力使得攻擊者通過暴力破解可以攻破強度弱的算法。例如,數據加密標準算法DES(密鑰默認是56位長度、算法半公開、迭代次數少)是極度不安全的,使用類似EFF(Electronic Frontier Foundaton)Deep Crack的計算機在一天內可以暴力破解由DES加密的消息。

使用DES弱加密算法,樣例

風險代碼:

  SecretKeySpec key = new SecretKeySpec(rawKeyData, DES);    Cipher cipher = Cipher.getInstance(DES/ECB/PKCS5Padding);    cipher.init(Cipher.DECRYPT_MODE, key);  

開發建議

建議使用安全性更高的AES加密算法

規範 6.2 不安全的密鑰長度風險

在使用RSA加密時,密鑰長度小於512bit,小於512bit的密鑰很容易被破解,計算出密鑰。

風險代碼:

public static KeyPair getRSAKey() throws NoSuchAlgorithmException {            KeyPairGenerator keyGen = KeyPairGenerator.getInstance(RSA);            keyGen.initialize(512);            KeyPair key = keyGen.generateKeyPair();            return key;          }

開發建議

使用RSA加密時,建議密鑰長度大於1024bit

6.3 AES/DES弱加密風險(ECB)

AES的ECB加密模式容易遭到字典攻擊,安全性不夠。

風險代碼:

SecretKeySpec key = new SecretKeySpec(keyBytes, AES);    **Cipher cipher = Cipher.getInstance(AES/ECB/PKCS7Padding, BC);**    cipher.init(Cipher.ENCRYPT_MODE, key);  

開發建議

避免使用ECB模式,建議使用CBC。

6.4 IVParameterSpec不安全初始化向量

使用IVParameterSpec函數,如果使用了固定的初始化向量,那麼密碼文本可預測性高得多,容易受到字典攻擊等。

風險代碼:

byte[] iv = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };    IvParameterSpec ips = new IvParameterSpec(iv)

開發建議

IVParameterSpec初始化時,不使用常量vector。

6.5 RSA中不使用Padding風險

使用RSA公鑰時通常會綁定一個padding,原因是為了防止一些依賴於no padding時對RSA算法的攻擊。

風險代碼:

Cipher rsa = null;    try {      rsa = javax.crypto.Cipher.getInstance(RSA/NONE/NoPadding);    }catch (java.security.NoSuchAlgorithmException e) {}    catch (javax.crypto.NoSuchPaddingException e) {}    SecretKeySpec key = new SecretKeySpec(rawKeyData, RSA);    Cipher cipher = Cipher.getInstance(RSA/NONE/NoPadding);    cipher.init(Cipher.DECRYPT_MODE, key);  

開發建議

建議使用Padding模式。

6.6 KeyStore弱密碼風險

keytool是一個Java數據證書的管理工具,Keytool將密鑰(key,私鑰和公鑰配對)和證書(certificates)存在一個稱為keystore的文件中,並通過密碼保護keystore中的密鑰。如果密碼設置過於簡單,例如:123456、android等,則會導致keystore文件的私鑰泄露,從而導致一系列的信息泄露風險。

開發建議

提高keystore保護密碼的強度

七、數據安全

7.1 剪貼板敏感信息泄露風險

由於Android剪貼板的內容向任何權限的app開放,很容易就被嗅探泄密。同一部手機中安裝的其他app,甚至是一些權限不高的app,都可以通過剪貼板功能獲取剪貼板中的敏感信息。

風險代碼:

clipBtn = (Button) findViewById(R.id.btn_clip);            clipBtn.setOnClickListener(new OnClickListener() {                @Override                public void onClick(View v) {                    ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);                    ClipData clip1 = ClipData.newPlainText(label,password=123456);                    clipboard.setPrimaryClip(clip1);                }            });

開發建議

避免使用剪貼板敏文存儲敏感信息或進行加密

7.2 密鑰硬編碼風險

在代碼中禁止硬編碼私鑰等敏感信息,攻擊者反編譯代碼,即可拿到。

7.3 Intent敏感數據泄露

APP創建Intent傳遞數據到其他Activity,如果創建的Activity不是在同一個Task中打開,就很可能被其他的Activity劫持讀取到Intent內容,跨Task的Activity通過Intent傳遞敏感信息是不安全的。

開發建議

盡量避免使用包含FLAG_ACTIVITY_NEW_TASK標誌的Intent來傳遞敏感信息。

7.4 PendingIntent誤用風險

使用pendingIntent時候,如果使用了一個空Intent,會導致惡意用戶劫持Intent的內容。禁止使用空intent去構造pendingIntent。

開發建議

禁止使用空intent去構造pendingIntent。

7.5 數據或程序(DEX、SO)加載、刪除檢查

程序在加載外部dex、so文件是否判斷文件來源、是否存放可信區域;程序刪除文件是否可篡改文件路勁

  1. 是否加載公共區域程序,如sdcard、/data/local/tmp/、應用自創建但其他應用有讀寫權限的目錄上
  2. 是否從網絡下載,檢測方法包括:閱讀代碼、監聽網路請求、見識存儲區域文件讀寫、查看安裝包
  3. 升級包是否存在公共區域存儲。

7.6 文件全局讀寫漏洞

在使用getDir、getSharedPreferences(SharedPreference)或openFileOutput時,如果設置了全局的可讀權限,攻擊者惡意讀取文件內容,獲取敏感信息。在設置文件屬性時如果設置全局可寫,攻擊者可能會篡改、偽造內容,可能會進行詐騙等行為,造成用戶財產損失。其中getSharedPreferences如果設置全局寫權限,則當攻擊app跟被攻擊app具有相同的Android:sharedUserId屬性時和簽名時,攻擊app則可以訪問到內部存儲文件進行寫入操作。

開發建議

  1. 使用MODE_PRIVATE模式創建內部存儲文件
  2. 加密存儲敏感數據
  3. 避免在文件中存儲明文敏感信息
  4. 避免濫用Android:sharedUserId屬性

如果兩個appAndroid:sharedUserId屬性相同,切使用的簽名也相同,則這兩個app可以互相訪問內部存儲文件數據

7.7 日誌泄露風險

在APP的開發過程中,為了方便調試,通常會使用log函數輸出一些關鍵流程的信息,這些信息中通常會包含敏感內容,如執行流程、明文的用戶名密碼等,這會讓攻擊者更加容易的了解APP內部結構方便破解和攻擊,甚至直接獲取到有價值的敏感信息。

開發建議

禁止打印敏感信息

八、其他風險

8.1 謹慎使用高風險函數

在程序需要執行系統命令等函數,需要謹慎使用,嚴格控制命令來源,防止黑客替換命令攻擊。

風險代碼:

Example Java code:      Runtime rr = Runtime.getRuntime();      Process p = rr.exec(ls -al);    Example Bytecode code:      const-string v2, ls -al      invoke-virtual {v1, v2}, Ljava/lang/Runtime;->exec(Ljava/lang/String;)Ljava/lang/Process;

開發建議

嚴格按照要求使用

8.2 Fragment注入漏洞(CVE-2013-6271)

在api level 小於19的app,所有繼承了PreferenceActivity類的activity並將該類置為exported的應用都受到Fragment注入漏洞的威脅。

Google在Android 4.4 KitKat 裏面修正了該問題,引入了PreferenceActivity.isValidFragment函數,要求用戶重寫該函數驗證Fragment來源正確性。

開發建議

  1. 當Android api >=19時,要覆蓋每一個PreferenceActivity類下的isValidFragment方法以避免異常拋出;
  2. 當Android api < 19時,如果在PreferenceActivity內沒有引用任何fragment,建議覆蓋isValidFragment並返回false

影響範圍

小於Android 4.4(API level 19)

8.3 SQLite數據庫日誌泄露漏洞(CVE-2011-3901)

Android SQLite數據庫journal文件可被所有應用程序讀取,所有目錄對應程序數據庫目錄擁有執行權限,意味着應用程序數據目錄全局訪問,/data/data//databases目錄以[rwxrwx–x]權限創建,可導致全局讀寫。數據庫目錄下創建的journal文件以[-rw-r–r–]權限創建,可被所有app讀取。

開發建議

升級到Android4.0.1以上版本或者使用SQLCipher或其他庫加密數據庫和日誌信息。

影響範圍

Android2.3.7版本存在該漏洞,其他版本可能也受到影響,4.0.1不受影響

8.4 隨機數生成漏洞

SecureRandom的使用不當會導致生成的隨機數可被預測,該漏洞存在於Android系統隨機生成數字串安全密鑰的環節中。該漏洞的生成原因是對SecureRandom類的不正確使用方式導致生成的隨機數不隨機。

風險代碼:

SecureRandom secureRandom = new SecureRandom();            byte[] b = new byte[] { (byte) 1 };            secureRandom.setSeed(b);            // Prior to Android 4.2, the next line would always return the same number!            Log.v(wgc,-------------------------------);            Log.v(wgc,Test1: + secureRandom.nextInt());            SecureRandom secureRandom2 = new SecureRandom(new byte[] { (byte) 1 });            Log.v(wgc,Test2: + secureRandom2.nextInt());            SecureRandom secureRandom3 = new SecureRandom();            secureRandom3.setSeed(10L);            Log.v(wgc,Test3: + secureRandom3.nextInt())            SecureRandom secureRandom4 = new SecureRandom();            secureRandom4.nextBytes(b);            secureRandom4.setSeed(10L);            Log.v(wgc,Test4: + secureRandom4.nextInt());            SecureRandom secureRandom5 = new SecureRandom();            Log.v(wgc,Test5: + secureRandom4.nextInt());

開發建議

  1. 不要使用自定義隨機源代替系統默認隨機源(推薦)除非有特殊需求,在使用SecureRandom類時,不要調用以下函數:SecureRandom類下SecureRandom(byte[]seed)、setSeed(long seed)和setSeed(byte[]seed)方法。
  2. 在調用setSeed方法前先調用任意nextXXX方法。具體做法是調用setSeed方法前先調用一次SecureRandom#nextBytes(byte[]bytes)方法,可以避免默認隨機源被替代,詳細見參考資料。

影響範圍

Android 4.2之前,Android API 17以後SecureRandom的默認實現方式從Cipher.RSA換到了OpenSSL。SecureRandom新的實現方式不能將自己的seed替換掉系統的seed。

8.5 發佈版本需加固

發佈的軟件,應對app進行加固,防止攻擊者獲取app代碼、業務邏輯、API接口等,對業務和公司聲譽造成一定影響,防止app被破解二次打包,導致損失。

開發建議 APP加固


內容編輯:湯青松

更新時間:2019-09-03