給密碼加鹽是什么東西?

1. 用戶的密碼如何保存在數(shù)據(jù)庫中

假設(shè)小明的賬號是 ikun 密碼是 jinitaimei
那么我們可以設(shè)計(jì)一張表, 來保存賬號密碼

CREATE TABLE account (
    username varchar(30),
    password varchar(100)
);

那么我們存入數(shù)據(jù)庫之后, 就是這樣的

小明賬號存在數(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è)人的密碼好像完全不同

數(shù)據(jù)庫

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ā)布

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容