詳解基于Android App 安全登錄認證解決方案
近幾年移動互聯(lián)網(wǎng)的高速發(fā)展,智能手機的使用用戶呈現(xiàn)爆炸性增長,手機終端上的App 種類繁多,大多數(shù)App 都需要與后臺系統(tǒng)進行交互,交互的第一步需要進行登錄認證,過于簡單的認證方式可能被破解從而造成用戶信息的泄露甚至威脅著用戶的財產(chǎn)安全。為此基于Android 系統(tǒng),對比現(xiàn)有幾種常見的App 登錄認證方式,并提出一種采用RSA 非對稱加密和加入Token 時效機制的登錄認證解決方案。在登錄驗證階段采用RSA 非對稱加密方式,App 端對服務器端返回的Token 信息加上時間戳,將處理后的Token 信息保存到本地,后面的每次請求都攜帶該Token 從而實現(xiàn)免登錄的登錄狀態(tài)的保持。
1. 登錄認證方式
1.1 Web登錄認證方式
目前常見的Web認證的方式主要有三種:
(1)HTTP Basic Auth。 這種方式就是每次請求服務器時都攜帶用戶名和密碼,優(yōu)點是使用非常簡單,缺點也非常明顯,因為每次都需要攜帶用戶名和密碼,很有可能造成密碼被截獲。
(2)OAuth。一種開放的授權(quán)標準,允許第三方應用訪問用戶在某一個服務商服務器上存儲的私密數(shù)據(jù),其處理流程先是第三方應用通過App Key和App secret換取OAuth_Token進行授權(quán)(此時顏色有可能需要輸入用戶名和密碼),授權(quán)完成后服務商頁面會跳轉(zhuǎn)到第三方應用同時返回Access Token,此后第三方應用就可以通過這個Access Token去服務商服務器中訪問相應數(shù)據(jù)。
(3)Cookie Auth。Cookie認證機制就是瀏覽器在發(fā)起一次登錄認證請求時,服務端驗證通過后將會在產(chǎn)生一段Cookie信息并返回給瀏覽器,瀏覽器會將其保存到本地,以后的每次請求都會使用該 Cookie信息而不再進行登錄驗證。
1.2 App登錄認證方式
由于App客戶端無法處理Cookie信息,因此App登錄認證無法使用Web認證方式中的Cookie認證方式,為了登錄狀態(tài)的保持,一般會模擬Cookie認證方式,即在App端發(fā)起登錄認證請求后,得到服務端驗證成功的確認之后,App端一般會保存一些狀態(tài)信息在本地,后面每次請求都是攜帶該狀態(tài)信息,根據(jù)狀態(tài)信息的不同,可以分為如下兩種:
(1) 保存用戶信息表中的某個唯一標識。App端發(fā)起登錄請求,服務器端在驗證成功之后一般會將該登錄用戶的信息返回給客戶端,客戶端此時可以將用戶信息中的某個唯一標識字段給保存下來,如使用SharedPreference進行保存,后面每次發(fā)起網(wǎng)絡請求時,先判斷本地是否存在該字段,如果不存在說明用戶沒有進行登錄認證,跳轉(zhuǎn)到登錄頁;如果存在,則直接將這個字段攜帶進請求信息中,從而實現(xiàn)登錄保持狀態(tài)。這種方式優(yōu)點是比較簡單,缺點就是如果保存的字段容易被別人截獲,缺乏安全性。
(2)保存Token信息。App中非常常用的一種登錄認證方式,他的實現(xiàn)過程是,由App端發(fā)起登錄請求,服務器端在驗證成功后生成一份Token信息保存到用戶表中并設置一定的時效,同時將此Token返回給App端,App端將此Token保存到本地,以后的每次發(fā)起請求都是用該Token。與前面一種方式相比,避免了用戶表中信息的泄露,相對更加安全。其流程圖如下:
這種方式相對于第一種來說更加安全,但還是存在著明顯的安全漏洞,需要進行優(yōu)化。本文將以這種方案為基礎(chǔ),提出一種更加安全的基于Android平臺的App登錄解決方案。這里我們把現(xiàn)有的這種方案成為Token認證機制,本文提出的方案成為改進的Token認證機制。
2. 改進的Token認證機制詳細設計
上述Token認證機制也是存在著一些明顯的安全漏洞,本文提出的改進的Token認證機制就是基于對原來Token認證機制中安全漏洞的優(yōu)化。對于登錄認證機制,我們可以把它分為登錄驗證,狀態(tài)保持和登出三個階段,改進的Token認證機制主要是在登錄驗證和狀態(tài)保持階段進行優(yōu)化。
2.1 登錄驗證優(yōu)化
登錄驗證階段是指App客戶端向服務器端發(fā)起登錄認證請求,并攜帶用戶名和密碼,服務器端收到請求后獲取用戶名和密碼,并向數(shù)據(jù)庫進行查詢驗證的階段。由于這一階段需要密碼的傳輸,很多情況下可能都是明文或者簡單的MD5加密后直接傳輸,一旦被黑客截獲可能造成密碼的泄露風險。因此這一階段的優(yōu)化就是加強密碼加密功能,這里我們采用RSA非對稱加密方式。
RSA是一種非對稱加密,它是對稱加密的一種加強版,使用對稱加密的服務器端和客戶端都使用同一種加密規(guī)則,因此在服務器端生成加密密鑰之后需要傳遞給客戶端,客戶端也需要保存這個密鑰,而傳遞密鑰的過程和保存密鑰在客戶端后都有可能發(fā)生密鑰的截獲造成安全漏洞。而非對稱加密方式會在服務器端生成兩套密鑰,生成的公鑰是公開的并傳給客戶端,私鑰保存在服務器端,客戶端用公鑰加密信息后傳遞到服務器端,服務器端再用私鑰進行解密,因此只要私鑰不泄露,通信就是安全的。
由上面的分析可以知道,要使用RSA加密方式先要讓服務器生成公鑰和私鑰,并將公鑰返回給客戶端,因此,在圖1 的登錄驗證階段需要額外進行一次請求獲取公鑰(這個過程只需要一次,只要獲得了公鑰以后登錄認證就不再需要該過程),其流程如圖2所示。
根據(jù)上面的分析, 可以看到這一階段最核心的是服務器端公鑰和密鑰的生成過程以及利用公鑰加密和利用私鑰解密的過程。其核心代碼如下:
/** * 初始化密鑰 * * @return * @throws Exception */ public static Map<String, Object> initKey() throws Exception { KeyPairGenerator keyPairGen = KeyPairGenerator .getInstance(KEY_ALGORITHM); keyPairGen.initialize(1024); KeyPair keyPair = keyPairGen.generateKeyPair(); // 公鑰 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 私鑰 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); Map<String, Object> keyMap = new HashMap<String, Object>(2); keyMap.put(PUBLIC_KEY, publicKey); keyMap.put(PRIVATE_KEY, privateKey); return keyMap; }
/** * 取得公鑰 * * @param keyMap * @return * @throws Exception */ public static String getPublicKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PUBLIC_KEY); return encryptBASE64(key.getEncoded()); }
/** * 取得私鑰 * * @param keyMap * @return * @throws Exception */ public static String getPrivateKey(Map<String, Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PRIVATE_KEY); return encryptBASE64(key.getEncoded()); }
/** * 加密<br> * 用公鑰加密 * * @param data * @param key * @return * @throws Exception */ public static byte[] encryptByPublicKey(byte[] data, String key) throws Exception { // 對公鑰解密 byte[] keyBytes = decryptBASE64(key); // 取得公鑰 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key publicKey = keyFactory.generatePublic(x509KeySpec); // 對數(shù)據(jù)加密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, publicKey); return cipher.doFinal(data); }
/** * 解密<br> * 用私鑰解密 * * @param data * @param key * @return * @throws Exception */ public static byte[] decryptByPrivateKey(byte[] data, String key) throws Exception { // 對密鑰解密 byte[] keyBytes = decryptBASE64(key); // 取得私鑰 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec); // 對數(shù)據(jù)解密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, privateKey); return cipher.doFinal(data); }
2.2 狀態(tài)保持優(yōu)化
App 客戶端在上一步登錄驗證階段會得到服務器返回的Token 信息,并將該Token 保存到本地,以后的每次請求都直接攜帶該Token 而不是再次使用用戶名和密碼進行驗證,這一階段稱為狀態(tài)保持或登錄保持階段。前面介紹的Token 認證機制中的Token 會一直保存在App 客戶端本地直至用戶主動點擊退出按鈕,如果該Token 被截獲,截獲者同樣可以使用該Token直接訪問服務器中的敏感數(shù)據(jù)。針對Token 這一長時間保存的特點,我們的優(yōu)化就是為這個Token 設置一個生效時效,具體來說就是在從服務器獲得該Token后,在保存的時候在Token 后加上一個當前的時間戳,后面每次發(fā)起網(wǎng)絡請求時,先取出該Token 后面的時間戳判斷有沒有超過生效時間,如果沒有則將處理后的Token 放入到請求信息中,如果超時了,則重新進行登錄認證過程。這種優(yōu)化過程是以犧牲了一點用戶體驗為代價。其流程圖如下:
本文章詳細探討了常見的Web 登錄認證方式和App登錄認證方式, 對現(xiàn)在比較常用的App 登錄認證方式Token 認證機制的安全漏洞進行了討論,在這個基礎(chǔ)上提出了改進的Token 認證登錄機制, 通過采用RSA 非對稱加密優(yōu)化登錄驗證階段, 使用Token 時效機制優(yōu)化狀態(tài)保持階段, 該優(yōu)化方案在實際生產(chǎn)中得到了檢驗。同時,該方案還有進一步優(yōu)化的空間,例如在優(yōu)化狀態(tài)保持階段時采用的是Token 時效機制, 但這樣犧牲了App 的使用體驗, 因此在以后的研究中可以針對這一階段做進一步的優(yōu)化過程。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
代碼從windows下visual studio到andriod平臺遷移實現(xiàn)步驟
這篇文章主要介紹了代碼從windows下visual studio到andriod平臺遷移的修改記錄的相關(guān)資料,需要的朋友可以參考下2017-01-01Android TabHost選項卡標簽圖標始終不出現(xiàn)的解決方法
這篇文章主要介紹了Android TabHost選項卡標簽圖標始終不出現(xiàn)的解決方法,涉及Android界面布局相關(guān)屬性與狀態(tài)設置操作技巧,需要的朋友可以參考下2019-03-03Android6.0動態(tài)申請權(quán)限所遇到的問題小結(jié)
這篇文章給大家介紹了Android6.0動態(tài)申請權(quán)限所遇到的問題,在沒給大家介紹這下問題之前,先給大家說下基本定義和基本使用方式,本文給大家介紹的非常詳細,具有參考借鑒價值,對android 6.0 動態(tài)權(quán)限遇到問題感興趣的朋友一起看看吧2016-11-11Android編程之Activity中onDestroy()調(diào)用分析
這篇文章主要介紹了Android編程之Activity中onDestroy()調(diào)用方法,針對onDestroy引起的內(nèi)存泄露及解決方法進行了分析,并給出了解決方案,需要的朋友可以參考下2015-12-12Android使用setCustomTitle()方法自定義對話框標題
Android有自帶的對話框標題,但是不太美觀,如果要給彈出的對話框設置一個自定義的標題,使用AlertDialog.Builder的setCustomTitle()方法非常方便,接下來通過本文給大家介紹Android使用setCustomTitle()方法自定義對話框標題,感興趣的朋友一起學習吧2016-02-02