数据加密的几种方式

对称加密算法(AES,DES,3DES)
对称加密指的是加密和解密时,使用的是同一秘钥,其中最优秀的对称加密算法是AES。
不过对称加密也有不好的地方,即对秘钥的保存问题。非对称加密算法(RSA,ECC)
非对称加密指的是加密和解密的双方使用不同的秘钥,通过非对称加密算法生成一对秘钥
一个公钥,一个私钥,公钥可对外暴露,私钥只对自己可见,任何想向我发信息的人,通过公钥对数据加密
我收到后,使用私钥对密文进行解密。最优秀的非对称加密算法是RSA。单向Hash算法
单向Hash算法也叫散列算法,单向指的是经过加密后的hash值并不能反向推算出明文,即不可逆
目前对数据库的敏感信息的加密大多数使用这种方式MD5/SHA-1加密
通过对明文密码字段进行MD5加密,将计算出的16字节hash值保存在数据库中,但这种方式并不安全,因为单向hash算法有两个特点,
1,从同一个密码进行单向哈希,得到的总是唯一确定的hash值
2,计算速度快。随着技术进步,一秒钟能够完成数十亿次单向哈希计算
攻击者可以将所有密码的常见组合进行单向哈希,使用hash值作为key,密码作为value,组成查询表
拿到你的数据库中的hash值在表中查询,就能找出对应的明文密码了。SHA2(SHA256,SHA512)
也是和MD5差不多,只不过生成的hash字节长度更大而已,还是可以通过查询表,或者更高效的彩虹表
找到对应的明文密码SHA2+盐
这是一种有效能避免查询表或彩虹表攻击的方式之一,盐指的是随机的字符串,在每一个用户的明文后
加上随机生成的盐,再对该字符串进行哈希计算,将计算后的hash值保存在数据库中,
这种方式也叫加盐,随机字符串盐也有要求- 使用CSPRNG算法生成盐,而不是普通的随机数算法。
CSPRNG是加密安全的,这意味着用它产生的随机数更加随机,且不可预测。 - 盐不能太短
如果盐很短,那意味着密码+盐组成的字符串的长度和取值空间都有限。
黑客完全可以为密码+盐的所有组合建立彩虹表。 - 盐不能重复使用
如果所有用户的密码都使用同一个盐进行加密。那么不管盐有多复杂、多大的长度,
黑客都可以很容易的使用这个固定盐重新建立彩虹表,破解你的所有用户的密码。
但这种方式现在也不适用了,因为为了验证用户的明文是否正确,通常会在表中设置一个salt
的字段用于存放盐,这就会导致一个问题,如果数据库被脱库,意味着明文+盐的hash值,和盐
一起被泄露,攻击者还是可以以此建立彩虹表,依靠如今显卡恐怖的并行计算能力,依然能找出明文- 使用CSPRNG算法生成盐,而不是普通的随机数算法。
Password Hash(PBKDF2、BCRYPT、SCRYPT,Argon2)
也叫密码哈希,专业加密密码的hash算法,这类加密算法有个共同的特点,算法中都有个因子,
用于指明计算密码摘要所需要的资源和时间,也就是计算强度。计算强度越大,
攻击者建立彩虹表越困难,以至于不可继续。
其中最优秀的当属Argon2算法,在2015年7月,Argon2算法被NIST认定为最好的密码hash算法。
PasswordEncoder接口的使用
PasswordEncoder是Spring Security提供的密码加密方式的接口定义,其实现类如下图:
使用BCryptPasswordEncoder加密
导入Spring Security依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
注册BCryptPasswordEncoder组件
@Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); }
加密解密
//对password字段加密保存在数据库中 user.setPassword(passwordEncoder.encode(user.getPassword())); userServiceImpl.save(user); //通过前端传递过来的id获取数据库中对象 User userDataBase = userServiceImpl.getById(user.getId()); boolean matches = passwordEncoder.matches(user.getPassword(),userDataBase.getPassword()); /* PasswordEncoder接口的encode方法将明文通过哈希计算成密文, 其中使用了加盐和慢哈希的方式增加攻击者破解难度 PasswordEncoder接口的matches方法,第一个参数是用户传递的密码明文,第二个参数是数据库 存储的hash值,两者进行比对,如果比对成功说明用户密码正确。 */
使用Argon2PasswordEncoder加密
除了Security,导入Argon2所需的依赖
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.64</version> </dependency>
注册Argon2PasswordEncoder组件
@Bean public PasswordEncoder passwordEncoder(){ return new Argon2PasswordEncoder(); }
加密解密同BCryptPasswordEncoder