1. 用戶的密碼如何保存在數(shù)據(jù)庫中
假設(shè)小明的賬號是 ikun 密碼是 jinitaimei
那么我們可以設(shè)計(jì)一張表, 來保存賬號密碼
CREATE TABLE account (
username varchar(30),
password varchar(100)
);
那么我們存入數(shù)據(jù)庫之后, 就是這樣的

可惜系統(tǒng)太拉了, 數(shù)據(jù)庫被入侵了,
小黑子把雞腳偷走了, 這一下好了, 小黑子能拿小明的賬號登錄系統(tǒng)了
2. 怎么防止數(shù)據(jù)庫中的密碼被別人獲取呢
為了防止上面的情況, 我們需要把數(shù)據(jù)加密后再存入數(shù)據(jù)庫
這里我們就通過對稱加密手段, 把小明的密碼加密
public static void main(String[] args) throws Exception {
String password = "jinitaimei";
System.out.println(encrypt(password));
}

- 經(jīng)過一番計(jì)算
jinitaimei就變成了qdPxlb+qci6riQRvnm/k3A==
3. 密碼還是泄露了
好了, 現(xiàn)在密碼經(jīng)過加密, 小黑子拿到了一串沒有意義的字符串, 也沒有秘鑰反推不出來真正的密碼
你以為你的密碼就安全了?
這時(shí)小黑子發(fā)現(xiàn), 好幾個(gè)人密碼加密后的密文都是一模一樣的

恰巧小黑子通過撞庫等手段 知道了 james 的密碼就是 jinitaimei
這下好了! 小黑子一下就知道了, 密文是 qdPxlb+qci6riQRvnm/k3A== 的用戶, 密碼實(shí)際就是jinitaimei
ikun 的秘密又不保了
4. 同樣的密碼, 不同的密文
看來要解決密碼相同 導(dǎo)致密文相同 的問題,
我們需要一種辦法:
- 同樣的密碼能加密成不同的密文
如何能起到這種效果呢?
那就是:
- 加鹽
5. 在加密的時(shí)候加鹽
假設(shè)我們的鹽是一個(gè)隨機(jī)的4位數(shù)數(shù)字
然后我們只要把原來的密碼與4位數(shù)字拼接起來, 再進(jìn)行加密, 就能得到加鹽后的密文
我們來試試加密看看效果
public static void main(String[] args) throws Exception {
String password = "jinitaimei";
for (int i = 0; i < 4; i++) {
String passwordWithSalt = password + RandomUtil.randomInt(1000, 9999);
System.out.println(encrypt(passwordWithSalt));
}
}

直接拉出數(shù)據(jù)庫里的數(shù)據(jù)來看, 這四個(gè)人的密碼好像完全不同

6. 解密
數(shù)據(jù)庫里的password字段, 小黑子已經(jīng)無法通過比對的方式知道了
我們來將密文解密看看
public static void main(String[] args) throws Exception {
List<String> miwenList = List.of(
"NrCwWnOZmbXlgi1ZwJJPBA==",
"XEXwpBk/95aTViwJQKQvZQ==",
"XUrfbLcHcCFBKz5wEwLjGA==",
"9hwtmzoNe64/IdX9IkfU4A=="
);
for (String miwen : miwenList) {
System.out.println(decrypt(miwen));
}
}
解密后的字符串:

現(xiàn)在我們只要將這些字符串的最后4位刪除, 就能得到真正的password了 jinitaimei !
下面展示一下對稱加解密的代碼以供參考,
這個(gè)加解密設(shè)計(jì)比較粗糙主要是為了展示加鹽操作
- 加密
private static String encrypt(String content) throws Exception {
String aesKey = "27d1cfcc412340d2";//秘鑰
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
SecretKeySpec skeySpec = new SecretKeySpec(aesKey.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
IvParameterSpec iv = new IvParameterSpec(aesKey.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(content.getBytes("UTF-8"));
return Base64.getEncoder().encodeToString(encrypted);
}
- 解密
private static String decrypt(String miwen) throws Exception {
String aesKey = "27d1cfcc412340d2";//秘鑰
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
SecretKeySpec skeySpec = new SecretKeySpec(aesKey.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
IvParameterSpec iv = new IvParameterSpec(aesKey.getBytes());
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] encrypted1 = Base64.getDecoder().decode(miwen);
byte[] original = cipher.doFinal(encrypted1);
return new String(original, "UTF-8");
}
本文由mdnice多平臺(tái)發(fā)布