安全登入
在Andorid登入過程中有些資訊會很常用:
使用者名和密碼
裝置資訊,如DeviceID和AndroidID
網絡資訊,如IP位址
為了下一次登入友善,登入過程中會記住使用者名,這意味着使用者名将儲存在裝置檔案系統的某個位置。
使用者驗證的最佳實踐:
- 不要緩存密碼
- 限定最短的密碼長度
- 驗證Email位址
- 多步驗證
- 服務端和用戶端都進行驗證
不要緩存密碼
不要儲存或緩存使用者名,尤其是密碼,因為手機上的資訊總有風險被解密,即使對密碼進行加密,但如果密鑰儲存在apk中,那麼密碼和未加密是一樣的。
限定最短的密碼長度
少于6位的密碼将很容易被爆力破解。
驗證Email位址
因為你以後很可能需要用到,可通過正規表達式,也可在注冊過程中發送Email,通過Email中的連結驗證,最好兩種方式結合使用。
多步驗證
拿到裝置ID、IP位址以及地理位置資訊或短信發送額外PIN碼到手機上來作為額外的驗證資訊。
如果要儲存使用者隐私資訊,應該使用非對稱加密。這就需要伺服器(私鑰儲存在伺服器上)來對資料進行解密,進而增加一次用戶端服務端的互動,這種做法才能保證使用者資料的安全。
驗證流程的補充資訊
AndroidID是一個64位的數字或者是裝置第一次啟動的時候随機生成的UUID,在裝置的正常使用中應保持一緻。
DeviceID,隻支援WIFI的裝置在telephony硬體上根本沒有DeviceID,恢複出廠設定後DeviceID不會發生變化。擷取DeviceID需要 READ_PHONE_STATE 權限。
加密使用者密碼
在使用者第一次登入的時候要輸入使用者名和密碼,使用Keyczar非對稱加密密碼,公鑰放在用戶端,私鑰儲存在伺服器上。
保持登入狀态
要為應用選擇一個合适的session逾時時間,财務或健康相關的,使用者在幾分鐘内沒有操作就應該讓session過期,如果是遊戲應用session可以維持數天。
網絡通信
第三方API提供商使用API key來作為一個簡單的校驗,為避免API key被人破解濫用,需要把它隐藏起來避免被人找到。
加密方案
對稱加密
使用同一個key對資料進行加密和解密。
非對稱加密
使用公鑰和私鑰在用戶端和服務端之間傳輸資料。
中間人攻擊示例
使用Cydia Impactor 來 root手機步驟
- 確定打開開發者選項
- 開啟usb調試
- 打開Cydia Impactor應用,點選開始按鈕
- 在指令行輸入adb shell,再輸入su,如果看到#符号說明root成功
在root掉的手機上安裝ProxyDroid,用它來把通信轉發到計算機上,然後再計算機上安裝Charlse Proxy來檢視網絡通信。
使用Charlse Proxy建立出自簽名的證書。
當使用HTTPS連接配接發送請求,如果沒有正确處理證書相關的内容(忽略了SSL相關的錯誤),就會看到未加密的通信,代碼正常工作HTTPS會請求失敗,顯示 SSL證書被拒絕了(no peer certificate) 的錯誤資訊。
小結:關鍵思想是任何的個人資訊都應該把這些資料加密,盡最大可能把客戶資料儲存在伺服器而不是手機上,如果必須用儲存在手機上,如API key,非對稱加密可以確定資料安全。
Android資料庫
應用的資料庫檔案在/data/data/packagename/databases目錄下。
備份應用的資料庫
使用指令備份資料庫
adb backup packagename
備份是定制檔案頭的tar檔案,需下載下傳Android Backup Extrator把它轉換成tar格式,轉換備份的backup.ab檔案
java -jar abe.jar unpack backup.ab backup.tar
使用tar -xvf或者Windows上的7zip解壓tar檔案,就可以看到裡面的資料庫了。
阻止備份
在 manifest 檔案中設定 android:allowBackup="true" 。這可以禁止adb backup備份資料庫,連系統備份也不行。但是root了的手機可以通路到資料庫,運作 chmod 777 <檔案名> 來完全放開檔案權限後,可以使用adb pull 把資料庫從手機上拉取下來。
SQLCipher
SQLCipher 是和SQLite3一起使用的一個開源庫,可用來加密資料庫中的資料,用它在openOrCreateDatabase時需要一個密碼參數。
隐藏密鑰
- 每一次都請求密鑰
密鑰儲存在使用者的腦袋裡,而不是手機中。
- 在 Shared Preferences 中隐藏密鑰
有兩種不同的做法:在使用者第一次打開應用的時候要求輸入密鑰,然後儲存在Shared Preferences檔案中。另一種是在應用第一次打開的時候直接加載指定使用者名和密碼。Android會從 resources/xml 目錄下加載資料,并把它儲存到Shared Preferences檔案中。
adb shell cat /data/data/packagename/shared_prefs/* 可以檢視Shared Preferences檔案。
- 在代碼中隐藏密鑰
使用裝置相關的來為單獨的裝置生成一個key,比如device_id,android_id,或者任何跟特定的手機相關的屬性,如Build.ID,Build.MODEL。把這些資訊組合起來為單獨的手機生成單獨的密鑰。僅僅比不同的裝置上使用相同的密鑰稍微安全一點點。
- 在NDK中隐藏密鑰
C++不能被反編譯,隻能反彙編。
使用NDK時,在代碼中使用一個十六進制類型的文本作為密鑰,在十六進制編輯器裡密鑰就不會以明文顯示出來了。還可以使用裝置資訊或應用資訊的字元串在NDK中生成唯一的應用密鑰。
- 使用Web Service保護密鑰
最安全的辦法是把存儲密鑰或者說使用算法生成密鑰的方法放到遠端,然後通過Web Service來通路密鑰。缺點是在裝置打開資料庫的時候需要聯網,這對于終端使用者可能不可接受。
SQL注入
沒有SQL注入保護的登入語句
Cursor cursor = db.rawQuery("select * from login where USERNAME = '" + name + "' and PASSWORD = '" + password + "';", null);
很容易被注入,如:
select * from login where USERNAME = '' OR 1==1 --' and PASSWORD = 'test'
可使用正規表達式檢查輸入的内容,和使用SQL prepared statements。如用prepared statements來保護代碼:
Cursor cursor = db.rawQuery("select * from login where USERNAME = ? and PASSWORD = ?;", new String[]{name, password});
裝置安全
adb備份
root 過的手機通過修改檔案權限,使用adb pull 可導出檔案。
adb backup 應用的/data/data目錄下的所有檔案都以跟Unix tar類似的格式被備份到電腦上。
可以設定android:allowBackup="false" 關閉掉應用備份。
日志
開發過程中通常會添加一些調試資訊,可能有http請求和伺服器通信的資訊。要避免調試日志資訊被打包到生産版本中。
Proguard混淆工具可以用來移除上線應用的所有日志資訊。在 proguard-rules.pro 檔案中配置
-assumenosideeffects class android.util.Log {
<method>;
}