密码加密的前世今生

如果直接将用户填写的明文密码(原始密码)存储到数据库中,当出现数据库泄密,用户的账号安全就无法保障!所以,需要将明文密码进行加密,在数据库中,实际存储的会是密文(加密后的结果),即使数据库泄密,被看到也只是密文,如果无法通过密文还原出原文(原始密码),则不会影响账号安全。

比如,大名鼎鼎的优快云就曾经出现过,数据库泄漏导致明文密码泄漏的安全事故:
https://blog.youkuaiyun.com/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);
}

关于消息摘要算法,有几个特点:

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

  • 使用固定的算法,无视消息的长度,摘要的长度固定;

  • 使用固定的算法,消息不同时,摘要几乎不会相同。

例如:

消息摘要
123202cb962ac59075b964b07152d234b70
123456e10adc3949ba59abbe56e057f20f883e
1234567890e807f1fcf82d132f9bb018ca6738a19f

因为消息的长度是没有限制的,所以,消息的种类可以是无限种!但是,摘要的长度是固定的,所以,摘要的种类就是有限的!综合来看,理论上来说,可以有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)的条件~

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值