密碼加密的前世今生

如果直接將用戶填寫的明文密碼(原始密碼)存儲到數據庫中,當出現數據庫泄密,用戶的賬號安全就無法保障!所以,需要將明文密碼進行加密,在數據庫中,實際存儲的會是密文(加密後的結果),即使數據庫泄密,被看到也只是密文,如果無法通過密文還原出原文(原始密碼),則不會影響賬號安全。

比如,大名鼎鼎的CSDN就曾經出現過,數據庫泄漏導致明文密碼泄漏的安全事故:
https://blog.csdn.net/jnqqls/article/details/7099911

假設,某用戶的原始密碼是1234,假設使用非常簡單的規則:“將每位數字增加1”,就可以得到2345,最終,會將2345存儲到數據庫中,即使出現數據庫泄密,別人能看到的也只是2345,如果這個規則設計得更加複雜,無法將2345這種密文還原成1234這種原文,至少能保障用戶賬號安全(不被他人登錄等)。

當使用了這樣的加密處理後,並不影響程序的正常使用,例如,用戶註冊時進行了以上的加密處理,在後續登錄時,用戶依然提交1234這種原始密碼,在驗證登錄時,程序會對1234使用相同的規則進行運算,得到2345,然後,再與數據庫中記錄的2345進行對比即可。

在處理加密時,加密規則越複雜越好,或者說,根據密文還原出原文的難度越大越好!一般來說,都應該使用成熟的算法,而不需要自行設計算法!

在實現密碼加密時,不要使用任何加密算法,因爲所有加密算法在設計時就已經決定了它是可逆向運算的,也就是說“所有的加密算法都可以解密”!加密算法的主要應用領域只是“保障傳輸過程的安全”,並不保證“存儲數據的安全”。

推薦使用消息摘要算法對密碼進行加密並存儲,因爲所有的消息摘要算法都是不可逆向運算的。消息摘要算法不是加密算法!!!消息摘要算法不是加密算法!!!
消息摘要算法不是加密算法!!! 重要的事情說三遍,度娘還是很嚴謹的:
在這裏插入圖片描述

常用的消息摘要算法有MD(Message Digest)系列和SHA(Secure Hash Argorithm)家族算法,例如MD2、MD4、MD5、SHA-1、SHA-256、SHA-384、SHA-512等。

Java語言本身就可以支持各種算法進行運算,原生API的使用相對麻煩,Spring框架默認就提供了MD5運算的API:

@Test
public void md5() {
    String password = "123456";
    String digest = DigestUtils.md5DigestAsHex(password.getBytes());
    System.err.println(digest);
}

關於消息摘要算法,有幾個特點:

  • 使用固定的算法,消息相同時,摘要必然相同;

  • 使用固定的算法,無視消息的長度,摘要的長度固定;

  • 使用固定的算法,消息不同時,摘要幾乎不會相同。

例如:

消息 摘要
123 202cb962ac59075b964b07152d234b70
123456 e10adc3949ba59abbe56e057f20f883e
1234567890 e807f1fcf82d132f9bb018ca6738a19f

因爲消息的長度是沒有限制的,所以,消息的種類可以是無限種!但是,摘要的長度是固定的,所以,摘要的種類就是有限的!綜合來看,理論上來說,可以有N個不同的消息對應相同的摘要!如果找到2個完全不同的消息,運算得到的摘要卻完全相同,則稱之爲發生了“碰撞”!

但是,雖然存在碰撞概率,但是,概率卻不一定高,以MD5爲例,摘要的長度固定爲32位,其本質是32個十六進制數,如果還原成二進制數,將是一個128位長度的二進制數,所以,MD5算法是128位算法。理論上來說,發生碰撞的概率是3.40282E+38分之一。

同時,在實際應用中,如果是使用消息摘要算法對密碼進行“加密”時,用戶提交的原始密碼其實是有限的種類(允許使用的只有數字、字母、符號,且通常會限制長度),就不存在上述的“無限對應有限”的現象,在“有限對應有限”的應用場景中,發生碰撞的概率將更低,甚至根本就不存在!這樣來看,使用消息摘要算法用於“密碼加密”的數據處理是安全有效的!

關於消息摘要的破解,首先,學術上的“破解”指的是“研究某種消息摘要算法的碰撞概率”,並不是討論所謂的“逆向運算”,只要是消息摘要算法,都是不可以被逆向運算的!

另外,在網絡上,還有一些網站提供了“在線破解”,其實,這些網站是在數據庫中收錄了大量消息與摘要的對應結果,當網友嘗試破解時,這些網站是“通過網友提供的摘要查詢對應的原文”,並不是真正意義的“破解”!由於這些網站收錄的消息與摘要的對應結果是有限的,所以,相當複雜的密碼都不會被這些網站破解!
比如這個網站:
https://www.cmd5.com/
在這裏插入圖片描述
號稱90萬億條數據,好像很唬人:

其實不過7位密碼的水平!

在實際設計項目時,爲了最大化保障用戶密碼的安全,應該:

  • 要求用戶使用安全強度更高的密碼;
  • 對密碼進行循環加密;
  • 對密碼進行“加鹽”處理;
  • 選取位數更長的摘要算法;
  • 綜合以上做法。

附:關於MySQL中的char與varchar

在MySQL中,varcharchar都是可以存儲字符串的類型,並且,在設計數據表時,必須明確的指定長度!

varchar變長的,假設某字段設計爲varchar(10),當存入的是"java"字符串時,實際存入4個字符,則實際佔用也是4個字符的空間大小;

char定長的,假設某字段設計爲char(10),當存入的是"java"字符串時,將要存入的4個字符比設計的varchar(10)中指定的數量要少,則會補充6個空格,以達到10個字符,則實際佔用也是10個字符的空間大小;

所以,如果要存入的字符串的長度不固定,應該使用varchar類型,只有長度固定的情況下才使用char

在MySQL處理varchar類型時,默認情況下,還會使用額外的1個字節記錄“實際存入的字符數量”,也就是說,將"java"存入到varchar(10)的字段中,MySQL還會使用額外的1個字節空間記下4這個數量值,後續,當讀取這個值時,MySQL會先讀取這個4,然後再開始獲取字段中的數據;char類型就不存在這個問題,因爲使用char類型存儲的字符串的長度一定是固定的(即使不固定,也會添加空格,使得該字段的所有字符串的長度都與字段的設計值保持一致)。

當然,在處理varchar類型時,由於默認情況下只使用1個字節記錄“實際存入的字符數量”,所以,在這種情況下能夠存入的字符數量最多是255個(1個字節能表示的最大正數),當需要存入更多數據時,MySQL會自動擴容,使用2個字節記錄“實際存入的字符數量”,能夠表示的最大正數就是65535,並且,不會再擴容,所以,使用varchar最多存儲65535個字符!

所以,綜合來看,其實varchar類型的數據將佔用更多的存儲空間(需要使用額外的字節作記錄),同時,查詢效率偏低,所以,雖然使用char能夠存儲的數據換成使用varchar也都能正常存儲和使用,但是,在能夠使用char的應用場景,應該優先使用char

比如經過md5加密後的密碼的長度就是固定32位,符合用char(32)的條件~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章