spring-security(十五) Password编码

前言:
  在实际应用中,如果我们直接把密码以明文形式存储在数据库中存在一定的安全隐患。所以最好以某中方式将密码编码后再存储下来,用户登录时将用户输入的密码也按照相同的编码方式编码后和数据库中存储的密码相比较,即可以完成验证,也保证了密码等敏感信息的安全性。
1.在spring security中主要用PasswordEncoder对密码进行编码,因为历史版本的缘故,spring security中存在两个PasswordEncoder接口,一个存放在org.springframework.security.authentication.encoding包下面,只是为了和遗留系统兼容,已经不推荐使用,另一个放在org.springframework.security.crypto.password包下面,是重新设计的一套编码实现,新开发的应用应该采用这个包下的编码类。spring 给我们提供的认证实现类DaoAuthenticationProvider这两套密码编码方式都支持。
实际应用中不要选择普通的哈希函数如MD5、SHA,即便是追加了salted的版本也不要选,因为这种普通的哈希函数计算速度很快,这样攻击者就可以在很短时间内执行成百上千次的攻击。spring提供的org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder类是一个不错的选择,因为Bcrypt故意设计的计算速度很慢,就是为了应对密码攻击。记住在生产环境里,即便我们的数据库很安全也不要考虑把密码存储成明文形式。
2.那么什么是哈希呢
对密码进行哈希处理并不是spring security特有的概念,而是安全系统的一个通用概念。哈希算法是个单向函数,对输入的数据(如密码)进行计算,输出一个固定长度的数据(哈希码),例如对password字符进行MD5哈希后得到如下结果
5f4dcc3b5aa765d61d8327deb882cf99

哈希算法是单向的有两个意思,一是根据计算后的哈希码很难得到原始的输入数据(基本上是不可能的),二是只要输入的数据一样得到的哈希码都是一样的。正是这两个特性使得这个算法非常适合用来存储认证用户的密码信息,这样即便是存储用户信息的数据库被破解了,也不能用里面的信息登录我们的系统。
3.在哈希算法中加入Salt
单纯利用hash对密码进行编码有一个潜在的问题,因为现在有很多的黑客网站直接有哈希码和原始数据的对应结果,例如我们把5f4dcc3b5aa765d61d8327deb882cf99放在百度、google上搜素,我们很快就知道原始数据是password。而在实际应用中,用户都倾向与选择很相似的密码。因而当黑客想要攻击我们的网站时,他可以建立一个常见密码对应的哈希码的字典表,从而通过哈希码找到原始的密码值。为了应对这个攻击,我们可以选择高强度的密码策略,如最少位数限制,密码组合中至少有特殊字符、数字和字符等组成,另一种就是在计算哈希码时利用一个salt,作为对密码哈希时的附加值。理想情况下这个salt值越随机越好,加入salt后,攻击者想要破解原始密码就需要为每一个salt创建一个字典表,使破解的难度大大加大。spring推荐用的Bcrypt算法会自动的为我们生成一个随机的salt,并以特定的格式存储在计算后的哈希码中。
4.哈希和认证
当认证提供者(例如DaoAuthenticationProvider)需要验证用户提交的密码是否正确时,如果存储的用户密码经过了哈希处理,那么用户提交的密码必须经过相同的哈希算法处理,这个需要应用的开发者自己保证,因为spring security并不关系用户信息是如何存入数据库的。并且这个两个算法必须严格一致,假如你知道用户信息存入时用的是MD5算法,因而你在spring security中用Md5PasswordEncoder来编码,有时候还是会有问题,比如数据库存入时用了Base 64来做MD5编码,而Md5PasswordEncoder却用了默认的十六进制编码这样还是不能正确认证,所以在系统正式启用之前一定要哈希算法的一致并能正常认证成功。spring security推荐我们在两个地方都统一采用bcrypt,这样可以避免不必要的麻烦。

猜你喜欢

转载自fengyilin.iteye.com/blog/2411079