在 spring Security 文檔中有這么一句話: "鹽值的原理非常簡單,就是先把密碼和鹽值指定的內容合並在一起,再使用md5對合並后的內容進行演算,這樣一來,就算密碼是一個很常見的字符串,再加上用戶名,最后算出來的md5值就沒那么容易猜出來了。因為攻擊者不知道鹽值的值,也很難反算出密碼原文。"
問題如何理解這句話: "先把密碼和鹽值指定的內容合並在一起,再使用md5對合並后的內容進行演算". 例如, 在 applicationContext-security.xml 文件中的配置如下:
<authentication-provider user-service-ref="userDetailsService"> <password-encoder hash="md5"> <!-- 將每個用戶的username作為鹽值 --> <salt-source user-property="username"/> </password-encoder> </authentication-provider>
假設用戶名是 Tom, 密碼為 123456, 那么在數據庫中存放的值應該是什么?
通過查看 Spring Security 的 org.springframework.security.providers.encoding.BasePasswordEncoder 類可知 Spring Security 通過如下方式來匹配在數據庫中已經被鹽值加密的密碼:
protected String mergePasswordAndSalt(String password, Object salt, boolean strict) { if (password == null) { password = ""; } if (strict && (salt != null)) { if ((salt.toString().lastIndexOf("{") != -1) || (salt.toString().lastIndexOf("}") != -1)) { throw new IllegalArgumentException("Cannot use { or } in salt.toString()"); } } if ((salt == null) || "".equals(salt)) { return password; } else { return password + "{" + salt.toString() + "}"; } }
即通過 password + "{" + salt.toString() + "}" 中方式把 "密碼和鹽值指定的內容合並在一起". 所以對於用戶名是 Tom, 密碼為 123456 的用戶在數據庫中存放的密碼應該為對 "123456{Tom}" md5 驗算后的值: 610c492873b994f96f93e342a56bcd68
