Android應用開發allowBackup敏感資訊洩露的一點反思
1 背景
其實這篇文章可能有些小題大作,但回過頭想想還是很有必要的,有點陰溝裡翻船的感覺。相信大家都知道Android API Level 8開始提供了為應用程式備份和恢復資料的功能,此功能的開關可以通過應用程式中AndroidManifest.xml檔案的allowBackup屬性值進行配置,預設是True,所以使用者可以對我們應用程式進行資料備份。相信很多人都和我一樣一直當作耳邊風過了一下Android這個特性,然後就一直沒再打理了。然而舊事重提的故事是下面這樣開始的:
前不久突然收到了一個Bug反饋,來自國內著名的白帽子組織烏雲平臺,關於這個組織就不作介紹了,相信大家一定知道問題的嚴重性,關於修復這個Bug是很快的事情,但是修復完這個Bug以後不得不讓我進入思考(就像之前處理SQL注入一樣),所以寫出此文記錄。
其實allowBackup的風險原理主要是允許通過adb backup對開啟USB除錯的裝置進行資料備份,一旦得到備份檔案之後那就不好說了,譬如邪惡的人可以再通過adb restore將你的資料恢復到自己的裝置上,然後就完全在自己的裝置上以你的名義去玩弄App;或者通過程式碼分析出備份檔案中你登陸App的一些賬戶密碼等核心資訊。總之,Google當初設計的核心肯定是為了方便備份資料考慮的,但是大家自己開發的應用似乎忽略了手機丟失或者被他人撿到的問題,譬如通訊錄或者名片、支付類等App如果一旦出現此類問題後果還是很嚴重的,所以有必要重視一下。
2 例項還原
為了驗證該小問題可能帶來的重大敏感資訊洩露問題,我們下面選幾個代表App進行測試,這樣就可以直觀的讓你感受到洩露的一點危機。
特別宣告: 本文例項中涉及的應用只為驗證,且本問題一般不會造成太大風險,故煩請大家保持學習心態而不要肆意汙衊應用開發者;當然我也已經通過烏雲漏洞平臺對下面涉及到的應用進行了漏洞提交,相信這些應用新的迭代版本中很快就會解決掉的。
《簡書》Android 1.9.7版本測試
結論: 會存在帳號被盜取問題。
驗證: 裝置A上登陸帳號密碼後如下:
然後在該裝置上執行如下命令將資料備份到電腦上:
XXX@ThinkPad:~/workspace/myself/temp$ adb backup -f back.ab -noapk com.jianshu.haruki
Now unlock your device and confirm the backup operation.
此時換一臺裝置B安裝此應用,但是不登陸任何帳號密碼,執行如下命令:
XXX@ThinkPad:~/workspace/myself/temp$ adb restore back.ab
Now unlock your device and confirm the restore operation.
可以看見,裝置B沒有進行帳號密碼登陸,只是通過恢復A裝置的備份資料就成功登陸了A裝置的資訊。
《Sina微博》Android 5.1.0版本測試
按照上面的類似流程測試微薄發現在裝置B上面恢復裝置A的資料無效,裝置B依舊顯示如下:
也就是說Sina微博考慮的很周全,已經修復了此類潛在的洩露風險,備份資料恢復無效,依舊需要重新登陸才可以,給一個贊。
《薄荷》Android 5.4.5.1版本測試
這個應用依據上面類似操作後你會發現完全可以在裝置B上不用登陸帳號,只用恢復別人的備份帳號資訊即可進入別人帳號介面,如下:
上面為裝置B上截圖情況,直接可以在裝置B上操作裝置A的帳號。
3 反思與總結
看了上面兩部分的敘述以後你可能也會意識到這個問題潛在的嚴重性,Google的初心是好的,但是一旦被別有用心的人瞄上了這個突破點問題就嚴重了。譬如再高階一點,別有用心的人專門寫一段程式碼去執行資料備份上傳到自己的雲端伺服器,然後解析這些備份資料,小則個人資訊洩露,大則哈哈,你懂的。
既然這樣肯定你也會關心解決方案吧,具體解決比較容易,如下:
方案1:
直接在你的Android清單檔案中設定android:allowBackup=”false”即可,如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test.disallowbackup"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="10"/>
<application
android:allowBackup="false"
android:label="@string/app_name">
<activity android:name="LoginActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
方案2:
不在你的Android清單檔案中設定android:allowBackup=”false”,允許執行備份,但是在你應用啟動頁進行邏輯判斷是否進行重新登陸等,譬如檢視裝置唯一識別裝置編號和備份前是否一致,不一致則直接跳轉登陸頁面的同時清空當前應用資料及快取。
好了,個人愚見,不足說服力,只是因為專案被烏雲反饋而寫的一點總結而已,目前我們採用了類似新浪微博的方案1做法。