您好,登錄后才能下訂單哦!
近幾年移動互聯網的高速發展,智能手機的使用用戶呈現爆炸性增長,手機終端上的App 種類繁多,大多數App 都需要與后臺系統進行交互,交互的第一步需要進行登錄認證,過于簡單的認證方式可能被破解從而造成用戶信息的泄露甚至威脅著用戶的財產安全。為此基于Android 系統,對比現有幾種常見的App 登錄認證方式,并提出一種采用RSA 非對稱加密和加入Token 時效機制的登錄認證解決方案。在登錄驗證階段采用RSA 非對稱加密方式,App 端對服務器端返回的Token 信息加上時間戳,將處理后的Token 信息保存到本地,后面的每次請求都攜帶該Token 從而實現免登錄的登錄狀態的保持。
1. 登錄認證方式
1.1 Web登錄認證方式
目前常見的Web認證的方式主要有三種:
(1)HTTP Basic Auth。 這種方式就是每次請求服務器時都攜帶用戶名和密碼,優點是使用非常簡單,缺點也非常明顯,因為每次都需要攜帶用戶名和密碼,很有可能造成密碼被截獲。
(2)OAuth。一種開放的授權標準,允許第三方應用訪問用戶在某一個服務商服務器上存儲的私密數據,其處理流程先是第三方應用通過App Key和App secret換取OAuth_Token進行授權(此時顏色有可能需要輸入用戶名和密碼),授權完成后服務商頁面會跳轉到第三方應用同時返回Access Token,此后第三方應用就可以通過這個Access Token去服務商服務器中訪問相應數據。
(3)Cookie Auth。Cookie認證機制就是瀏覽器在發起一次登錄認證請求時,服務端驗證通過后將會在產生一段Cookie信息并返回給瀏覽器,瀏覽器會將其保存到本地,以后的每次請求都會使用該 Cookie信息而不再進行登錄驗證。
1.2 App登錄認證方式
由于App客戶端無法處理Cookie信息,因此App登錄認證無法使用Web認證方式中的Cookie認證方式,為了登錄狀態的保持,一般會模擬Cookie認證方式,即在App端發起登錄認證請求后,得到服務端驗證成功的確認之后,App端一般會保存一些狀態信息在本地,后面每次請求都是攜帶該狀態信息,根據狀態信息的不同,可以分為如下兩種:
(1) 保存用戶信息表中的某個唯一標識。App端發起登錄請求,服務器端在驗證成功之后一般會將該登錄用戶的信息返回給客戶端,客戶端此時可以將用戶信息中的某個唯一標識字段給保存下來,如使用SharedPreference進行保存,后面每次發起網絡請求時,先判斷本地是否存在該字段,如果不存在說明用戶沒有進行登錄認證,跳轉到登錄頁;如果存在,則直接將這個字段攜帶進請求信息中,從而實現登錄保持狀態。這種方式優點是比較簡單,缺點就是如果保存的字段容易被別人截獲,缺乏安全性。
(2)保存Token信息。App中非常常用的一種登錄認證方式,他的實現過程是,由App端發起登錄請求,服務器端在驗證成功后生成一份Token信息保存到用戶表中并設置一定的時效,同時將此Token返回給App端,App端將此Token保存到本地,以后的每次發起請求都是用該Token。與前面一種方式相比,避免了用戶表中信息的泄露,相對更加安全。其流程圖如下:
這種方式相對于第一種來說更加安全,但還是存在著明顯的安全漏洞,需要進行優化。本文將以這種方案為基礎,提出一種更加安全的基于Android平臺的App登錄解決方案。這里我們把現有的這種方案成為Token認證機制,本文提出的方案成為改進的Token認證機制。
2. 改進的Token認證機制詳細設計
上述Token認證機制也是存在著一些明顯的安全漏洞,本文提出的改進的Token認證機制就是基于對原來Token認證機制中安全漏洞的優化。對于登錄認證機制,我們可以把它分為登錄驗證,狀態保持和登出三個階段,改進的Token認證機制主要是在登錄驗證和狀態保持階段進行優化。
2.1 登錄驗證優化
登錄驗證階段是指App客戶端向服務器端發起登錄認證請求,并攜帶用戶名和密碼,服務器端收到請求后獲取用戶名和密碼,并向數據庫進行查詢驗證的階段。由于這一階段需要密碼的傳輸,很多情況下可能都是明文或者簡單的MD5加密后直接傳輸,一旦被黑客截獲可能造成密碼的泄露風險。因此這一階段的優化就是加強密碼加密功能,這里我們采用RSA非對稱加密方式。
RSA是一種非對稱加密,它是對稱加密的一種加強版,使用對稱加密的服務器端和客戶端都使用同一種加密規則,因此在服務器端生成加密密鑰之后需要傳遞給客戶端,客戶端也需要保存這個密鑰,而傳遞密鑰的過程和保存密鑰在客戶端后都有可能發生密鑰的截獲造成安全漏洞。而非對稱加密方式會在服務器端生成兩套密鑰,生成的公鑰是公開的并傳給客戶端,私鑰保存在服務器端,客戶端用公鑰加密信息后傳遞到服務器端,服務器端再用私鑰進行解密,因此只要私鑰不泄露,通信就是安全的。
由上面的分析可以知道,要使用RSA加密方式先要讓服務器生成公鑰和私鑰,并將公鑰返回給客戶端,因此,在圖1 的登錄驗證階段需要額外進行一次請求獲取公鑰(這個過程只需要一次,只要獲得了公鑰以后登錄認證就不再需要該過程),其流程如圖2所示。
根據上面的分析, 可以看到這一階段最核心的是服務器端公鑰和密鑰的生成過程以及利用公鑰加密和利用私鑰解密的過程。其核心代碼如下:
/** * 初始化密鑰 * * @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); // 對數據加密 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); // 對數據解密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, privateKey); return cipher.doFinal(data); }
2.2 狀態保持優化
App 客戶端在上一步登錄驗證階段會得到服務器返回的Token 信息,并將該Token 保存到本地,以后的每次請求都直接攜帶該Token 而不是再次使用用戶名和密碼進行驗證,這一階段稱為狀態保持或登錄保持階段。前面介紹的Token 認證機制中的Token 會一直保存在App 客戶端本地直至用戶主動點擊退出按鈕,如果該Token 被截獲,截獲者同樣可以使用該Token直接訪問服務器中的敏感數據。針對Token 這一長時間保存的特點,我們的優化就是為這個Token 設置一個生效時效,具體來說就是在從服務器獲得該Token后,在保存的時候在Token 后加上一個當前的時間戳,后面每次發起網絡請求時,先取出該Token 后面的時間戳判斷有沒有超過生效時間,如果沒有則將處理后的Token 放入到請求信息中,如果超時了,則重新進行登錄認證過程。這種優化過程是以犧牲了一點用戶體驗為代價。其流程圖如下:
本文章詳細探討了常見的Web 登錄認證方式和App登錄認證方式, 對現在比較常用的App 登錄認證方式Token 認證機制的安全漏洞進行了討論,在這個基礎上提出了改進的Token 認證登錄機制, 通過采用RSA 非對稱加密優化登錄驗證階段, 使用Token 時效機制優化狀態保持階段, 該優化方案在實際生產中得到了檢驗。同時,該方案還有進一步優化的空間,例如在優化狀態保持階段時采用的是Token 時效機制, 但這樣犧牲了App 的使用體驗, 因此在以后的研究中可以針對這一階段做進一步的優化過程。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。