前言
之前項目中,登錄模塊發送登錄請求基本上都是明文傳輸用戶名、密碼,這樣如果系統的請求被惡意抓取,用戶的信息就會泄漏無疑,毫無安全可言,那麼有什麼辦法可以提高安全性呢?
- js加密
在js中加密用戶的密碼,使之在傳輸過程中程加密狀態,這樣,即使在被惡意攔截了請求,獲取了用戶名密碼後,別人並不會知道密碼,因此完成加密! - RSA加密算法
RSA加密算法是一種非對稱加密算法。在公開密鑰加密和電子商業中RSA被廣泛使用。RSA是1977年由羅納德·李維斯特(Ron Rivest)、阿迪·薩莫爾(Adi Shamir)和倫納德·阿德曼(Leonard Adleman)一起提出的。當時他們三人都在麻省理工學院工作。RSA就是他們三人姓氏開頭字母拼在一起組成的。
到目前爲止,世界上還沒有任何可靠的攻擊RSA算法的方式。只要其鑰匙的長度足夠長,用RSA加密的信息實際上是不能被解破的。
2009年12月12日,編號爲RSA-768(768 bits, 232 digits)數也被成功分解。這一事件威脅了現通行的1024-bit密鑰的安全性,普遍認爲用戶應儘快升級到2048-bit或以上。
瞭解更多關於RSA
調查
在尋找保密方法的時候,曾經查看過很多知名網站的登錄,大部分都是用戶名不管,密碼加密即可,所以我們採用同樣的方式。
- 美團登錄
- 阿里雲登錄
- 新浪登錄
新浪可能是用戶名也加密了,但是在請求中發現了
pwencode: rsa2
rsakv: 1330428213
基本可以初步判斷新浪在登錄上也是用了RSA加密
- 京東
在京東請求中發現了pubKey字段,京東可能也是使用了非對稱加密。
簡單原理
在使用RSA加密手段之前,我們需要了解RSA加密大概的流程,這樣有助於幫助我們更好的使用此加密手段。
- 首先,系統跟根據一定的規則生成一對祕鑰,
- 我們可以選擇一個祕鑰去公開它,另外一個一定要嚴格保密,通常公開的祕鑰我們稱之爲公鑰,留下的祕鑰稱之爲私鑰。
- 我們可以對外開放一個可以獲取公鑰的接口,用於外部程序來獲取公鑰,外部應用通過此公鑰來加密數據,這些加密後的數據只能通過私鑰才能解開,相對的,私鑰加密的數據需要公鑰來解密,即使別人獲取了你的公鑰、’密文,只要私鑰不泄露,只要祕鑰位數足夠長,是解不開的。
代碼
頁面處理
在頁面上使用rsa加密非常簡單,我們只需要在頁面寫下如下代碼,即可完成加密功能
var encrypt=new JSEncrypt();
encrypt.setPublicKey(public_key);
var rsa_password = encrypt.encrypt($('#password').val());
這樣,密碼就加密完成了。
後臺處理
package rsalogin.util;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public class RSAUtil {
//生成祕鑰對
public static KeyPair getKeyPair() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
return keyPair;
}
//獲取公鑰(Base64編碼)
public static String getPublicKey(KeyPair keyPair){
PublicKey publicKey = keyPair.getPublic();
byte[] bytes = publicKey.getEncoded();
return byte2Base64(bytes);
}
//獲取私鑰(Base64編碼)
public static String getPrivateKey(KeyPair keyPair){
PrivateKey privateKey = keyPair.getPrivate();
byte[] bytes = privateKey.getEncoded();
return byte2Base64(bytes);
}
//將Base64編碼後的公鑰轉換成PublicKey對象
public static PublicKey string2PublicKey(String pubStr) throws Exception{
byte[] keyBytes = base642Byte(pubStr);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
}
//將Base64編碼後的私鑰轉換成PrivateKey對象
public static PrivateKey string2PrivateKey(String priStr) throws Exception{
byte[] keyBytes = base642Byte(priStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
}
//公鑰加密
public static byte[] publicEncrypt(byte[] content, PublicKey publicKey) throws Exception{
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] bytes = cipher.doFinal(content);
return bytes;
}
//私鑰解密
public static byte[] privateDecrypt(byte[] content, PrivateKey privateKey) throws Exception{
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] bytes = cipher.doFinal(content);
return bytes;
}
//字節數組轉Base64編碼
public static String byte2Base64(byte[] bytes){
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(bytes);
}
//Base64編碼轉字節數組
public static byte[] base642Byte(String base64Key) throws IOException{
BASE64Decoder decoder = new BASE64Decoder();
return decoder.decodeBuffer(base64Key);
}
}
Demo
主要代碼如上所示,如果需要示例可以訪問碼雲來查看我寫的一個例子。
示例
如果發現錯誤或者其它問題請留言指正,謝謝!
- 此Demo採用了Springboot 2.0.4開發,模擬了登錄加密的流程。
- 採用了定時刷新祕鑰對策略,有助於私鑰定期刷新。
頁面所用的加密js的GitHub地址如下頁面加密js GitHub地址