关于密码的那些事儿

前端开发

Posted by Michelle on March 29, 2019

关于密码的那些事儿

序言

现在的各种网站和App都有登录注册or交易这种安全级别高的模块,如何保证用户的密码等隐私安全是很重要的部分。这篇文章介绍了web中关于密码的一些基础科普,包括以下几个部分:

1. md5
	1. 什么是md5
	2. 如何破解md5
	3. 如何防范黑客攻击
2. HTTPS和SSL
3. web前端加密

md5

######1.什么是md5

MD5消息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。

MD5由MD4、MD3、MD2改进而来,主要增强算法复杂度和不可逆性。

目前,MD5算法因其普遍、稳定、快速的特点,仍广泛应用于普通数据的错误检查领域。例如在一些BitTorrent下载中,软件将通过计算MD5检验下载到的文件片段的完整性。

简单来说,md5是一个加密算法,我们可以把它看做一个函数,举个例子:

MD5("The quick brown fox jumps over the lazy dog")
= 9e107d9d372bb6826bd81d3542a419d6

即使在原文中作一个小变化(比如用c替换d)其散列也会发生巨大的变化:

MD5("The quick brown fox jumps over the lazy cog")
= 1055d3e698d289f2af8663725127bd4b

那么有一个小问题: 一般认为任何一个字符串都有一个对应的md5加密串,md5的组成为32位十六进制数字,共有16^32 = 3.4 * 10^38 种可能,事实上有可数无穷多个字符串可以被md5加密,那么md5会存在不够用的问题吗? 实际上自然会有重复,但是md5的容量相当大,根据md5不可逆,很难反撸原串,所以在大多数使用情形下没有太大问题。

2.如何破解md5

以前的做法都是将所有可能出现的原文都分别算出md5值存储起来,用户可以用md5值索引可能的原文。但是md5的值太多了,所以这样会造成数据库太大,是一种资源浪费。

上述的笨办法是建立描述“明文->密文”对应关系的一个大型数据库,破解时通过密文直接反查明文。现在要介绍的是彩虹表,彩虹表弥补了这样的不足,通过“以空间换时间”的“双向交易”来达到两者之间的平衡。

彩虹表的前身是“预计算的哈希链集”,以大量的随机明文作为起节点,通过计算得出哈希链并将起节点终节点进行储存,即可得到一张哈希链集。(计算过程略,感兴趣的同学可以自行google)

每一条哈希链代表了一组属性相同的明文,每一个明文都可以通过起节点计算得到,计算次数不大于链表长度,所以我们只需要保存其特征值(起节点和终节点),压缩空间为原来的1/k,达到了时间和空间的平衡。

3.如何防范黑客攻击

现在的主要方式是“加盐”(salt),通过改变哈希函数H ,提高破解难度。另一种方法是提高H函数的计算难度,比如将H定义为1000次md5之后的结果,生成彩虹表的时间会大大增加,也会提高破解难度。

通俗点来说,彩虹表也是一种字典,不过是利用哈希链,只保存首尾节点,中间值通过哈希函数推算,因此节省了空间。

2.https和ssl简介

上面介绍了md5相关的知识,作为前端该如何实践呢?拿登陆模块举例,在前端进行加密是否有必要呢?

现在的登陆或者支付这种涉及安全性的模块,都会使用https,因为http的明文传输不安全。

有一个常见的误区是:网站用了前端md5加密后就可以不用https了。这种说法错误的原因是:黑客在拿到你的md5值后依然可以伪造请求,由于他知道md5是在前端加密,所以并不需要利用彩虹表等技术推出原串,直接向服务器发送md5值就可以登录成功,所以这个md5值和明文没有大的差别。除了明文可以用来进行社会学攻击,因为大多数人的网站用的都是一个密码,简直是被一锅端了。

https相当于http的安全版,它向http下加入了ssl(安全套接层),主要目的有两个:

1.保证信息安全传输,创建安全连接,发送数据
2.确认网站的真实身份

HTTP是不安全的,且攻击者通过监听和中间人攻击等手段,可以获取网站帐户和敏感信息等。HTTPS被设计为可防止前述攻击,被认为是安全的。

SSL是一种安全协议,目的是为互联网通信,提供安全及数据完整性保障,目前已成为互联网上保密通讯的工业标准。

SSL包含记录层(Record Layer)和传输层,记录层协议确定传输层数据的封装格式。传输层安全协议使用X.509认证,之后利用非对称加密演算来对通信方做身份认证,之后交换对称密钥作为会谈密钥(Session key)。这个会谈密钥是用来将通信两方交换的数据做加密,保证两个应用间通信的保密性和可靠性,使客户与服务器应用之间的通信不被攻击者窃听。

结论就是:对于密码等安全级别高的模块,使用https非常非常非常重要!!

3.web前端加密

在写这个问题之前发现有一些争议,一部分人认为前端加密是无用的,因为

1.有了https所以能够保证安全,不需要给系统加入额外的复杂性。
2.如上一段所说,用的如果是http,那么加不加密都能被黑客攻击,那为什么要加密呢?

我个人观点是前端加密,后端安全性防范,https缺一不可。

1.对于上面第一点,即使用了https,前端也需要加密,因为这样可以保证后端的日志等不会记录明文密码;还有保证后端内存中不存在明文密码(如dump),防止内鬼嘛。关于复杂性的问题,前端散列一般会采用较为“低功耗”的弱加密实现,而不会使用 RSA 等方法(有人使用短密钥的 RSA 依然是不安全的)。

2.对于上面第二点,如果用的是http,链路被监听时,可以直接拿明文密码,用户其他网站的密码很可能全部被暴露了。

有一种有效实践是发送用户密码+时间戳的md5值。这样可以有效避免被监听。攻击人拿到的加密后密码也很快失效,这里还有防止 replay 攻击(请求被重新发出一次即可能通过验证的问题)也解决了。

所以我们现在给出的可行实践是:

1.客户端提交 md5(password) 密码,服务端数据库通过md5(salt+md5(password)) 的规则存储密码,该 salt 仅存储在服务端,且在每次存储密码时都随机生成。这样即使被拖库,制作字典的成本也非常高。
2.密码被 md5() 提交到服务端之后,可通过 md5(salt + form['password']) 与数据库密码比对。此方法可以在避免明文存储密码的前提下,实现密码加密提交与验证。

这篇文章就到此结束了,如有疏忽的地方请指教~

资料来源: 维基百科RSA加密算法 维基百科md5 知乎:如何保证用户登录时提交密码已经加密?