web系統中常見的密碼加密方式

1 用戶密碼加密的必要性

        web系統中通常都會有登錄的功能,登錄功能的邏輯是這樣的:一個用戶擁有一個用戶名爲zhangsan,密碼爲123456的賬號,在登錄時,前端去調用後端的登錄接口,並傳入zhangsan與123456作爲參數;在後端代碼內容運行時,會根據zhangsan這一用戶名去查詢數據庫的用戶表,查詢出的內容會包含密碼,將這一個密碼與用戶所輸入的密碼做一個比對,如果相等才能繼續完成登錄功能。而在數據庫的用戶表中,我們通常可以看到密碼字段中存放的通常是一段我們看不懂的密文(比如以bcrypt加密的密文是這樣的——$2a$10$mWTEg1Byt3u/dAQl6GdJ5.UjVozRzCpxG4R64IvIvkwrJkwlfT5NG),也就是將真正的密碼進行了加密,這樣做的目的是爲了防止數據庫信息的泄露導致用戶密碼被盜用,加密後的字符串即使是被其他人所獲取到依然是不可能用的,因爲在登錄邏輯中後端對密碼進行判斷時會將用戶所輸入的密碼也進行加密後再與數據庫中存放的密文進行對比,通過這樣的方式,加強了系統的安全性。 

2 MD5

2.1 MD5信息摘要算法

        信息摘要算法的主要特徵是加密不需要密鑰,並且經過加密後的數據無法被解密,只有輸入相同的明文數據經過相同的信息摘要算法才能得到相同的密文。MD5信息摘要算法(英語:MD5 Message-Digest Algorithm),是一種被廣泛使用的密碼散列函數,可以產生出一個128位(16字節)的散列值(hash value),用於確保信息傳輸完整一致。MD5由美國密碼學家羅納德 李維斯特(Ronald Linn Rivest)設計,於1992年公開,用以取代MD4算法。

2.2 在mysql中使用MD5

        mysql數據庫中內置了MD5的函數,因此我們可以通過查詢dual查看明文經過MD5加密後的密文。比如在sql命令中輸入以下sql語句可以得到123456經過MD5加密後的結果。

SELECT MD5('123456') FROM dual;

結果爲:e10adc3949ba59abbe56e057f20f883e

2.3 MD5加鹽

        經過信息摘要算法加密後的數據是不能夠解密的,也就是說我們可以通過123456加密後得到e10adc3949ba59abbe56e057f20f883e字符串,但不能通過e10adc3949ba59abbe56e057f20f883e解密得到123456,而且對補一個字符串經過MD5加密後的字符串是相同的,那麼將123456通過MD5加密後永遠都能得到e10adc3949ba59abbe56e057f20f883e。由於這一個特性,我們可以創建數據庫,將密文與明文的信息寫入這一個數據庫,對於數據庫當中已有的數據,可以通過密文找到對應的明文。

        這樣,就有了MD5 + SALT的方式,也就是MD5加鹽,比如以下的例子就是以字符串‘55555’作爲鹽,在將123456通過MD5加密後,與作爲SALT的55555作拼接後再進行MD5加密,得到最終加密後的數據。

SELECT MD5(CONCAT(MD5('123456'), '55555')) FROM dual;

        在實際的web系統中,可能會以用戶名作爲鹽參與加密,又或者在用戶表中創建一個SALT字段,用一個隨機數作爲鹽,並將SALT值寫入數據表。

3 bcrypt

        bcrypt目前比較常用的密碼加密算法,也是Spring Security推薦的加密算法,它的特點是加密後的密文依然不可以解密,而且同一個字符串每一次通過bcrypt加密得到的結果都不一樣,比如我使用Spring Security所提供的的bcrypt的工具進行測試。以for循環的方式執行10次對123456的加密,得到的結果每次都不一樣,而且將10個不同的密文與內容爲123456的名爲進行校驗,得到的結果都是true。測試代碼如下。

import org.junit.Test;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

public class TestBCrypt {
    @Test
    public void testGenerateByBCrypt() {
        String password = "123456";
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        for(int i = 0; i < 10; i++) {
            // 得到加密後的字符串
            String encodePassword = bCryptPasswordEncoder.encode(password);
            System.out.println(encodePassword);
            // 將明文與加密後的密文作比對,返回爲true表示密文是由明文得到的
            System.out.println(bCryptPasswordEncoder.matches(password, encodePassword));
        }
    }
}

        打印結果如下。

$2a$10$t6CoTxlTuD5Z/Siod9Fx2OBBdBDHPwhstvjoz4VC5dh23niqrwC2e
true
$2a$10$ed4rhp76k5k3opUHonHS1OOB/Gh53uwl46h1pgn9Y653QBQH4xdKa
true
$2a$10$bc49GDLzKDzoPBm6g56IGOz741CzorBO98sa1impRd1WCMYIkcFWe
true
$2a$10$snaF9NlIXQ49qX9M3CNFMOHvv.jchvXRzCLWAgRwCFedSvwEdBVsO
true
$2a$10$C3pagIFlNd8vA2wDfZ6DauLKYXotgjCPy7eRv815FRNTDRu4cCiJ2
true
$2a$10$VPdphXIVDWIARiUxN9DZ.uqqkqQXAfC1A6FS3UgpwuY8QCuNUcqlW
true
$2a$10$zvZ.b6IulMEEpoHzvKOQ.OZXqJob8zRl.vrU6sk4VOPmSuC0yXIVe
true
$2a$10$OGxbOLVLV/abSKtm5a4O3OsWaCEb4Hkwp8XyBbhCLHY9J9e53pKn.
true
$2a$10$w7hLUssNzaeKYjiwprArn.1tcJYX/ERqsART1x8jynRHSL35XttGa
true
$2a$10$fu0EGMY3Jstf0Yb0lJTSieVoK92oKt33YubTgOZ0NONaJt9jjHcVq
true

 

發佈了45 篇原創文章 · 獲贊 42 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章