10+個Android 安全設計風險實務個案討論

10+個Android 安全設計風險實務個案討論

設計一個安全的 android App相對來說是比較困難的。

怎麼說呢? 因為Mobile App安裝在手機端,

使用者或是駭客可以用各式各樣的方式將 App反向工程、進行各種非預期的操作與輸入行維。

因此,設計一個安全的手機成是相對有一定的難度。

這篇文章主要舉幾個筆者在進行Android評審時常遇到的個案,

藉由這些個案實例說明設計一個安全Android App要注意的事項。

 

1. AndroidManifest.xml 設定三個原則

  • 1.  Do not specify taskAffinity
  • 2.  Do not specify launchMode
  • 3.  Explicitly set the exported attribute to false.

為什麼呢? 簡單來說,Android 個個程式間的溝通,如果沒有適當的安全設定,

敏感性的訊息有可能會經由這些溝通管道被其他惡意程式取得。

另外,上線前記得將 debuggable 移除。

//危險的範例設定
<application
. . .
android:debuggable="true"
. . . >
. . .
</application>

 

allowBackup  的設定會導致用戶可以使用 adb backup 對於整個資料庫讀取(無須 root),間接造成資料外洩。

//危險的範例設定
<application
. . .
android:allowBackup="true"
. . . >
. . .
</application>

 

2. Set FLAG_ACTIVITY_NEW_TASK

盡量不要在 startActivity 改變啟動模式。

// 有害的程式
Intent intent = new Intent(this, RISKY_ACTIVITY.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

Broadcasts

廣播的訊息避免其他應用程式也能收到。另外,無須額外設定 “intent-filter”

建議的設定:

<receiver
. . .
android:exported=“false”
. . . >
. . .
</receiver>

3. Content Providers

雖然可以透過 FLAG_GRANT_READ_URI_PERMISSION 設定

讓其他應用程式也可以有暫時對於 intent的讀取權限,但是盡量避免。

Intent intent = new Intent();
. . .
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setData(REQUEST_URI);
. . .

4. Services

Services 應該設定為避免其他應用程式讀取,減少非預期的結果。

//建議的設定
<service
. . .
android:exported="false">
. . .
</service>

5. 檔案儲存在公共目錄或是 SD Card

對於檔案在公共目錄的儲存或是外部記憶卡盡量避免。

如果真的要儲存,不要儲存敏感性資訊,例如帳號、密碼、信用卡等。

[pastacode lang=”markup” message=”” highlight=”” provider=”manual”]

// 危險程式
openFileOutput("/sdcard/data/vulnerability.txt", Context.MODE_PRIVATE);

[/pastacode]

6. 建立檔案時的權限設定

檔案的建立應該設定為 “MODE_PRIVATE”

// 危險的程式碼,因為設定為 "MODE_WORLD_WRITABLE"造成其他App也能讀取這個檔案。
// 因為危險性的關係,API level 17之後就不再支援
openFileOutput("vulnerability.txt", Context.MODE_WORLD_WRITABLE);

 

Log機制

如果該 app可以取得 Read_log的權限,那麼就可以任意讀取其他 App 的log。因此要確保 App 的 log沒有輸出敏感性資訊。

Android 4.0(API15) 之前的版本是有這樣的風險。Android 4.1(API16) 後,就算app取得這樣的 Read_logs權限也無法讀取其他app 的 log.

AndroidManifest.xml<uses-permission android:name=”android.permission.READ_LOGS”/>

 

避免在 release 版本的 app中加入額外的訊息輸出。

//危險程式
// 避免敏感性資料的輸出
// 建議使用 Android 提供的android.util.Log,避免使用System.out/err
if (...) {
	System.out.print(". . .");  //In release code
}

7. 去除”Log.d()/v()”

開發過程中所輸出的 log 都要去除。

//危險的程式碼
if (...) {
	// Remove the following code from release build
	Log.d("<Vulnerability>", "...");
}

一般來說 Log 提供 error, Warning, Info。開發過程我們使用 debug 或是 Verbose,上線後必須要移除。

// 避免將敏感性資料輸出至 LogLog.e(LOG_TAG, “Not sensitive information (ERROR)”);
Log.w(LOG_TAG, “Not sensitive information (WARN)”);
Log.i(LOG_TAG, “Not sensitive information (INFO)”);
// 避免將敏感性資料輸出至 Log
// 上線時這些 log需要移除
Log.d(LOG_TAG, “sensitive information (DEBUG)”);
Log.v(LOG_TAG, “sensitive information (VERBOSE)”);

註:ADT 21 之後的版本可以設定 BuildConfig.DEBUG

 

另外可以考慮使用 “ProGuard”,這個工具會將程式碼變得更難閱讀。

即使駭客做反向工程,看到的程式碼是不容易閱讀的。

 

8. WebView JavaScript 執行

原則上盡量避免 JavaScript 的執行,除非該網頁JavaScript的來源是可信任。

// 危險的程式設定setJavaScriptEnabled(true)
WebView webViewObj; 
. . . 
// It is risky when accessing untrusted servers or files stored in public folders. 
webViewObj.getSettings().setJavaScriptEnabled(true);

避免任意載入JavaScript

[pastacode lang=”markup” message=”” highlight=”” provider=”manual”]

// 危險的程式範例
class LocalObject {
	. . .
}
. . .
WebView webViewObj;
. . .
// insert an injectedObject object of LocalObject class into webViewObj
webViewObj.addJavascriptInterface(new LocalObject (),"injectedObject");

[/pastacode]

9. 使用舊版危險的函數 searchBoxJavaBridge_

Android 4.2 版本之前,這個物件有可能會被誤用來遠端執行 JavaScript

// 危險的程式範例
WebView webViewObj;
. . .
webViewObj .removeJavascriptInterface(“searchBoxJavaBridge_”);
. . .

10.快取的清除

對於瀏覽過的敏感性資訊網頁,建議可以清除快取。

//快取清除範例
WebView webViewObj;
. . . 
webViewObj. clearCache(true);
. . .

11.  SQL Injection

輸入的驗證與查詢參數的處理是很重要的。

下列程式由於對參數沒有特別的處理與驗證,因此會導致 SQL Injection

//危險的程式範例
Void query(String strParam) {
	final String s1 = "select * from ";
	String command = s1 + strParam;
	if (command != null) {
		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		db.execSQL(command);
	}
}

 

12. 密碼Remember 設定

當App 有提供密碼Remember 時,建議還是需要與遠端網站伺服器進行驗證。

否則,當手機遺失,或是密碼資訊儲存在本機端時,該驗證資訊就很容易被駭客誤用。

 

利用 Flag_secure 的設定降低畫面擷取的攻擊方式

// 建議的程式碼
Window win = getWindow();
win.addFlags(WindowManager.LayoutParams.FLAG_SECURE);

13. 密碼欄位的輸入設定

<EditText
	. . . 
	android:inputType="textPassword"
	android:password="true"
	. . . >
	. . .
</EditText>

 

14. HTTPS 傳輸

使用 HTTPS避免使用 HTTP

另外,資訊參數的傳遞盡量避免使用 URL

http:/victim.com/loginname=abc&timestamp=10002

 

15. 驗證 SSL Server正確

不要使用 “ALLOW_ALL_HOSTNAME_VERIFIER” ,

因為這會跳過  SSL Server 的驗證。

// 危險程式碼範例
SSLSocketFactory sf;
... 
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

16. 驗證 App Issuer

由於 Android App 可容易受到修改,因此必須適當的驗證App的發佈來源

17. 避免 Click Fraud

惡意程式可能會利用 Toast的特性誘導使用者點擊,

或是讓使用者誤以為這是原本應用程式的一部分。

因此可以透過這個設定,讓應用程式執行時,不會出現其他應用程式的 Toast

<TextView
. . .
android:filterTouchesWhenObscured="true"
. . . />

18. 是否可以備份還原資料

預設值為 True.

如果沒有設定為 false,駭客可以利用 adb 將應用程式的資料拷貝。

<application
. . .    
android:allowBackup="false"
. . . >
. . .
</application>

 

19. Intent 的輸入值檢查

Android 透過 Intent相互傳遞資訊,

程式使用getExtra(), getBundleExtra(), getCharExtra(), etc.

必須檢查回傳值、是否為 NULL、是否合法

// 安全的程式碼範例
Bundle bundle = intent.getBundleExtra("key");
if (bundle == null) {
    //return or other error handling
}

20. 關於定位隱私的問題

如果要在 WebView使用定位,通常需要下列權限。

由於”位置”資訊也是個人隱私的一部分,所以當需要下列權限時,必須取得使用者同意。

  • android.permission.ACCESS_FINE_LOCATION
  • android.permission.ACCESS_COARSE_LOCATION
  • android.permission.INTERNET
  • WebSettings#setGeolocationEnabled(true);

由於許多的 app 並沒有提醒使用者要需要取得定位資訊,因此駭客可以製造一個網站,

誘導使用者瀏覽該網站就可以取得使用者的位置資訊。

21 壓縮檔案炸彈

http://www.unforgettable.dk/

駭客可以透過壓縮檔案炸彈讓手機應用程式癱瘓。因此基本要做到的防護措施為

1. 確定該來源 ZIP是預期要解壓縮的檔案

2. 解壓縮前計算檔案大小,範例程式如下:

[pastacode lang=”java” message=”” highlight=”” provider=”manual”]

public final void unzip(String filename) throws java.io.IOException{
FileInputStream fis = new FileInputStream(filename);
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fis));
ZipEntry entry; int entries = 0; int total = 0;
try {
while ((entry = zis.getNextEntry()) != null) {
System.out.println("Extracting: " + entry);
int count;
byte data[] = new byte[BUFFER];
// output a file AFTER verifying filenams and resulting file size
String name = validateFilename(entry.getName(), ".");
FileOutputStream fos = new FileOutputStream(name);
BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER);
while (total <= TOOBIG && (count = zis.read(data, 0, BUFFER)) != -1) {
dest.write(data, 0, count);
total += count;
}
dest.flush();
dest.close();
zis.closeEntry();
entries++;
if (entries > TOOMANY) {
throw new IllegalStateException("Too many files to unzip.");
}
if (total > TOOBIG) {
throw new IllegalStateException("File being unzipped is too big.");
}
}
} finally { zis.close(); } }

[/pastacode]

 

 

30+. 權限設定

權限有很多。過多與過少都不好。需要用到在設定即可。以下是比較需要注意的權限。

android.permission.INTERNET
Allows an application to open network sockets.
android.permission.READ_LOGS
Allows an application to read the low-level system log files. Log entries can contain the user’s private information.
android.permission.ACCESS_COARSE_LOCATION
Allows an application to access coarse (such as, Cell-ID, Wi-Fi) locations.
android.permission.CAMERA
Allows an application to access the camera device.
android.permission.ACCESS_FINE_LOCATION
Allows an application to access fine (such as, GPS) locations.
android.permission.CHANGE_WIFI_STATE
Allows an application to change the Wi-Fi connectivity state.
android.permission.WRITE_SETTINGS
Allows an application to read or write system settings.
android.permission.MOUNT_UNMOUNT_FILESYSTEMS
Allows an application to mount and unmount file systems for removable storage.
android.permission.READ_SMS
Allows an application to read SMS messages.
android.permission.PROCESS_OUTGOING_CALLS
Allows an application to monitor, modify, or abort outgoing calls.
android.permission.RECEIVE_SMS
Allows an application to monitor incoming SMS messages, to record or perform processing on them.
android.permission.ACCESS_FINE_LOCATION
Allows an application to access fine (such as, GPS) locations.
android.permission.RECEIVE_BOOT_COMPLETED
Allows an application to receive ACTION_BOOT_COMPLETED that is broadcast after the system finishes booting.
android.permission.ACCESS_NETWORK_STATE
Allows an application to access information about networks.
android.permission.READ_PHONE_STATE
Allows read-only access to the phone state.
android.permission.WRITE_EXTERNAL_STORAGE
Allows an application to write to external storage.
android.permission.ACCESS_WIFI_STATE
Allows an application to access information about Wi-Fi networks.
android.permission.GET_ACCOUNTS
Allows an application to access the list of accounts in the Accounts Service.
android.permission.KILL_BACKGROUND_PROCESSES
Allows an application to kill processes running in the background.
android.permission.MODIFY_AUDIO_SETTINGS
Allows an application to modify global audio settings.
android.permission.BROADCAST_STICKY
Allows an application to broadcast sticky intents. These are broadcasts about whose data is held by the system after being finished, so that clients can quickly retrieve that data without having to wait for the next broadcast.
android.permission.VIBRATE
Allows an application to access the vibrator.
android.permission.RECEIVE_BOOT_COMPLETED
Allows an application to receive ACTION_BOOT_COMPLETED that is broadcast after the system finishes booting.
android.permission.BATTERY_STATS
Allows an application to collect battery statistics.
android.permission.READ_PHONE_STATE
Allows read-only access to the phone state.
android.permission.WRITE_EXTERNAL_STORAGE
Allows an application to write to external storage.
android.permission.GET_ACCOUNTS
Allows an application to access the list of accounts in the Accounts Service.
android.permission.WAKE_LOCK
Allows an application to use PowerManager WakeLocks to keep the processor from sleeping or the screen from dimming.
android.permission.INTERNET
Allows an application to open network sockets.
android.permission.SYSTEM_ALERT_WINDOW
Allows an application to open windows on top of all other applications.

android.permission.ACCESS_WIFI_STATE

Allows an application to access information about Wi-Fi networks.
android.permission.WAKE_LOCK
Allows an application to use PowerManager WakeLocks to keep the processor from sleeping or the screen from dimming.
android.permission.ACCESS_NETWORK_STATE
Allows an application to access information about networks.
android.permission.READ_EXTERNAL_STORAGE
Allows an application to read from external storage.
android.permission.READ_PHONE_STATE
Allows read-only access to the phone state.
android.permission.WRITE_EXTERNAL_STORAGE
Allows an application to write to external storage.

Leave a Reply

Your email address will not be published. Required fields are marked *