一、引言
在我们设计网站时,会涉及到用户密码安全存储的这个点。通常我们不会直接将用户的密码存储在数据库中,而是通过一种“加密”的算法将加密后的密码存储在数据库中,当用户登录时,对用户输入的密码进行加密后与数据库进行比对,如果正确则放行登录。
二、相关技术
(一)加密算法与消息摘要算法
加密与解密通常是一起出现的词语,有加密就有解密,所以,加密算法有与之对应的解密方法(密钥啥的),通常,我们在消息传输的时候才使用加密技术。
那么,我们今天的主题“用户密码的加密存储”难道不是用加密算法吗?是的不用,我们使用的是消息摘要算法。
(二)消息摘要算法
与加密算法可以解密不同,消息摘要算法只需要将数据加密为一个极难破解的16进制数,而且,它不可逆,也就是说,你获得一个消息摘要算法算出来的数据,是无法通过计算逆向得到原来的消息的,只有一种方法获得原来的消息,那就是穷举,不断穷举数据加密后比对目标数据,可这种方式的成本太高,举个例子来说,md5消息摘要算法,它能计算返回一个128位二进制数据,也就是32位长度的字符串(16进制数),如果只考虑数字破解,32位对应10的32次方种数字组合,可以粗略的认为穷举破解的概率是10的32次方分之1。
需要知道的一点:相同的数据通过相同的消息摘要算法计算得到的值必定相同。
三、设计
消息摘要算法固然好,但是,现如今也有人通过穷举存储的方式,存储了大量的数据,作为一个网站一个接口,供人反向查询,但即便如此,也只能存储不到10万亿个数据,也就是不到8位数字密码字符的随机组合结合个数,所以为了防止用户的密码过于简单可以通过这些网站反向查询原密码,我们可以人为的为用户密码加上一些随机字符串达到一个难以破译的长度,在本文中,我们使用java的UUID工具生成随机的36位随机字符串(我们称作“盐”,如炒菜加盐),拼接上用户设置的密码,通过消息摘要算法循环多次计算,获得一个完全不可能破译的数据,存之入数据库中,同时也将盐存储到数据库中,当用于登录时,通过用户输入的密码和此用户对应的盐进行计算,将结果与数据库中密码字段的数据进行比对,如果正确,则认为该用户输入的密码是正确的的。
获取UUID随机36位长度字符串
String salt = UUID.randomUUID().toString();
一个随机的UUID展示
fd6e071b-577f-487a-85f8-931105e2da19
设计加密算法
public String getMd5Password(String password,String salt) { //加密规则: //使用salt+password + salt 作为原文 //使用消息摘要算法循环加密三次 System.out.println("明文:"+password); String md5Password = salt + password + salt; for(int i =0;i<3;i++){ md5Password = DigestUtils.md5Hex(md5Password); } System.out.println("密文:"+md5Password); return md5Password; }
四、效果演示
明文:caiwei 密文:a3ecaf67935028c8ad213add8cb2c219