一、为什么要加密

首先抛出问题,通过明文发送的数据(如HTTP协议),攻击者可以很轻松的窥探到,并且可以随意修改里面的内容(这其实就是中间人攻击),这时如何保证你和对方发送的数据不被他人知晓和篡改?

二、概念

加密,是以某种特殊的算法改变原有的信息数据,对于可逆加密,可以使得未授权的用户即使获得了已加密的信息,任因不知解密的方法,无法了解信息的内容 。加密是保证通信安全的重要手段,加密首先分两大类:可逆加密与不可逆加密,如果加密后的内容可还原,则为可逆加密,否则为不可逆加密。

三、不可逆加密

加密后的数据不可还原的一种加密算法。 特点:直接对明文进行加密,加密后的密文不可逆向还原成明文,相同的明文,加密后的密文一定是相同的,不用的明文,几乎不可能加密成相同的密文,并且无论明文多长,加密后的密文都是定长的。常用的加密算法有SHA等(MD5严格来说并不算加密算法,但它的特点和不可逆加密一样)。因其不可逆的特性,所以只适用于无需解密的场景,如只需要进行比较的场景。例如校验密码和验签,只需比较,无需解密

以用户登录为例,首先会将用户注册时填写的密码进行不可逆加密存储,当用户登录需要判断密码是否输入正确时,只需要将输入的明文密码,以同样的方式进行不可逆加密,然后和存储的密码密文比较是否相等即可,这样就避免了明文存储密码,即便数据泄露,也没有人知道密码是什么。

但如果直接对密码进行不可逆加密存储还是不安全,以这个解密网站 https://www.cmd5.com/default.aspx 为例,虽然别人无法通过密文逆向解密成明文,但是可以用一种非常简单粗暴的方式做“解密”,那就是穷举字符组合,然后存储各种字符组合和它的密文,只要穷举的字符组合够多,那么一样可以通过密文,查到与之对应的明文。所以为了防止这种暴力破解,我们一般都会在加密前对明文密码加点“料”后再加密,这个“料”也就是一段随机字符串,我们把这段随机字符串称之为“盐(salt)”。

加盐后的密码比对流程:加密前将“盐”拼接在明文密码后面(也可以放在其他位置),然后再进行加密运算和存储(需要存储密码密文和盐),当需要比较时,又在明文密码后面拼接相同的“盐”,然后再进行加密运算和存储的密码密文比较是否相等。在加了“盐”之后,我们的密码长度将会变得更长,破解难度也会呈几何式增长,就算被破解,得到的也只是加了“盐”的密码,还需要从中剔除“盐”

四、可逆加密

加密后的数据可还原的一种加密算法,可逆加密包括对称加密和非对称加密,可逆加密在加密和解密时都会用到密钥(密钥可以理解为秘密的钥匙,有了这个钥匙就可以解开加密的数据,本质上就是一段字符串),如果加密和解密使用相同的密钥,就是对称加密,加密和解密使用不同的密钥就是非对称加密

4.1、对称加密

所谓对称,就是加密和解密使用相同的密钥,这是最早应用的一种加密算法, 又称传统加密算法 ,优点是算法公开、计算量小、加密速度快、加密效率高 。常用的对称加密算法:

1、DES(Data Encryption Standard):数据加密标准,速度较快,适用于加密大量数据的场合;

2、3DES(Triple DES):是基于DES,对一块数据用三个不同的密钥进行三次加密,强度更高;

3、AES(Advanced Encryption Standard):高级加密标准,是下一代的加密算法标准,速度快,安全级别高,支持128、192、256、512位密钥的加密;

因为加密和解密使用相同的密钥,密钥的保密工作就非常重要,只要拥有密钥的任何一个人泄露密钥,那么整个加密体系就被破解了。

4.2、非对称加密

加密与解密使用不同的密钥,这两个密钥一个称为公钥,一个称为私钥。用公钥加密的内容,只有使用私钥才能解密,而使用私钥加密的内容也只有使用公钥才能解开,大家可以通过这个网站http://web.chacuo.net/netrsakeypair 感受一下加解密过程 。从名字就可以看出来,公钥是公开的,可以多人拥有,私钥是私有不公开的,只有一人拥有私钥。所以正常情况下都是使用公钥加密,私钥解密,而不会使用私钥直接加密内容,因为私钥加密的内容是大家都能看到的(如果公钥公开的话),所以私钥不直接对内容加密,而是加密内容摘要,用于验签。常见的非对称加密有RSA、DSA、 ECDSA,现在一般使用的都是RSA

五、选择合适的加密方式

对称加密适用于与少数、特定,可信的一些“人”进行加密,不适用于陌生的场景。例如WEB服务器和浏览器之间的通信,肯定不可能采用对称加密,因为对称加密的核心就是密钥,所以需要确保所有拥有密钥的人都不会泄露密钥,而如果你随时都可能和一个新加入的浏览器进行通信,这时你把你的密钥告诉它吗?你都不知道对方的身份,就把密钥告诉它,那么你的加密体系也就被瞬间破解,而不告诉它又无法进行加密通信,所以不适合。

非对称加密天生就适用于与多数、陌生的“人”进行加密,但缺点就是加密和解密的效率没有对称加密高,实际运用中,很多场景都是将两者结合使用,先使用非对称加密通信,协商出一个对称加密密钥,往后的通信就用这个密钥进行对称加密通信,这样就将两者优点结合起来了,例如HTTPS

六、非对称加密通信过程

请先记住攻击者拥有的能力:能够查看和篡改通信过程中的数据。这对思考通信过程是否有漏洞很重要

在互有对方公钥的前提下  ,现在A和B要进行通信,他们互相知道对方的公钥,这时A要发送数据给B,首先A用B的公钥对数据加密然后发送给B,这时攻击者看到的数据是加密后的数据,因为他没有B的私钥,所以无法知晓A发送给B的明文数据是什么,这时可以保证A发送的数据不被其他人知晓,虽然攻击者不知道发送的内容是什么,但是攻击者却可以利用B的公钥,同样加密一段数据,然后篡改A发送的数据(此处假设A、B的公钥都是公开的),例如A要发送一句“明天去北京路吃饭”给B,先用B的公钥加密,然后发送,这时攻击者将“你是SB”这样的内容,同样用B的公钥进行加密,生成密文,然后替换A发送的密文,B收到数据后,用自己的私钥解密,因为攻击者也是用B的公钥加密数据的,所以顺利解开,这时A的“明天去北京路吃饭”就变成了"你是SB",然后就友尽了。

攻击者此时的篡改和知道明文的篡改很不一样,因为无法解密内容,所以只能用一个“全新”的数据去篡改,无法做到对数据的局部修改,但这依然不够安全,所以此时数据接受方就需要对发送方的身份进行认证。

6.1、加签与验签

B如何确保接收到的数据是来之于A并且没有被篡改呢?B现在唯一持有A的身份标识就是A的公钥,如果能用A的公钥解密的内容一定是来自于A,因为他人不可能用A的私钥来加密数据。

我想的加签于验签:A先用自己的私钥加密一段随机字符串,生成签名(此处是一个不严谨的签名),然后再和明文内容一起,用B的公钥加密后发送给B,B收到后首先用自己的私钥解密内容,然后取出里面的签名,看看能不能用A的公钥解密,如果可以,那么就可以确认这个内容来自于A。我觉得这个过程应该是安全的,因为数据是用公钥加密的,其他人不可能替换里面的部分内容,比如只替换明文内容而不替换签名,而接收方如果能用对方公钥解开签名,那么就说明这个内容一定来自于对方(不知道有没有可能不同私钥加密的内容也有可能被同一个公钥解密)。然而真实的签名校验却比这个严谨得多

真实的加签与验签:A先将明文内容进行HASH算法(例如SHA1)加密(不可逆),生成摘要,然后再用自己的私钥对这个摘要进行加密,生成一个签名,然后再和明文内容一起用B的公钥加密发送。B收到后先用自己的私钥解密内容,取出里面的签名和明文内容,然后用A的公钥解密签名,获得内容摘要,然后再将明文内容同样进行HASH加密,然后和摘要进行比对,如果一致,说明签名和内容是一致的,没有被篡改过的,如果不一致说明签名和内容不匹配,内容就是被篡改过的,此时就可以拒绝响应。这里并不是对随机字符串加密,而是让整个内容参与了加密,更加严谨,即使内容和签名是明文发送的,也可以防止内容不被篡改,真正做到了签名防篡改。

**为什么签名不是直接对明文内容进行私钥加密呢?**直接对明文内容进行私钥加密也可以,但明文内容往往是很长的,那么签名同样也会很长,不利于比较,也大大增加了传输的数据量,所以可以利用不可逆加密的特点,将很长的明文,加密成定长的摘要,这样传输的数据量小了,接收方进行比较的效率也高了。

总结一下,签名(signature)就是使用私钥加密的,用于接收方校验身份的的字符串,一般情况就是:私钥加密的,整个明文内容的摘要。私钥加密,确保内容不被篡改,公钥加密,确保内容不被窥探,两者共同保证了通信的安全性(针对双向对称加密通信)

有了公钥加密,加签与验签,现在的通信可以做到内容不被他人查看和篡改,但是任然可以做到截获内容后整体重复发送,而这已经不属于安全范畴了,需要在应用层面做重复请求校验。但公钥如何安全的给到对方是一很大的个问题,如果给公钥的过程中,遭到中间人攻击,一方的公钥换成了攻击者的公钥,那么另一方发送的数据就会遭到破解,而这个问题也是HTTPS会去解决的问题

七、HTTPS

HTTPS (全称:Hyper Text Transfer Protocol over SecureSocket Layer),是以安全为目标的 HTTP 通道 , 是在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性, 解决HTTP协议明文传输数据不安全的问题。其实HTTPS就是在HTTP协议下加了SSL层,而SSL协议的基础就是非对称加密

7.1、浏览器怎么获取服务器公钥

HTTP协议是明文的,站在一台服务器的角度,他会和很多的浏览器(还有其他客户端)进行通信,而且随时可能有新的浏览器加入,这时要对通信内容进行加密,肯定不可能直接使用对称加密,只能是非对称加密。而使用非对称加密就要用到公钥,客户端需要获取服务端的公钥是很正常的,因为服务端公钥只有一份,但服务端不可能去获取客户端公钥,因为客户端很多,每个客户端都有自己的公钥,如果要获取客户端公钥,那么服务端将会存储大量的客户端公钥,而且客户端告诉服务端公钥的这个过程也是得不到安全保证的。所以在HTTPS的通信过程中,只有客户端去获取服务端公钥,服务端不会获取客户端公钥。

那么问题1:服务端没有客户端公钥,服务端发送给客户端的数据如何保证安全性呢?

解决方案就是客户端获取到服务端公钥后,客户端生成一个随机密钥,然后将密钥加密发送给服务端,后面的通信就使用这个密钥进行对称加密通信(具体步骤下面会讲)。就算某些场景,服务端持有客户端公钥,一般也不会直接使用非对称加密进行通信,因为加/解密效率没有对称加密效率高,所以一般是先协商出一个对称加密密钥,往后的通信就使用这个密钥进行对称加密通信

问题2:客户端获取服务端公钥的过程怎么保证安全性呢(攻击者可以用自己的公钥替换服务端发送给你的公钥)?

其实要么手动确认,例如SSH,弹个提示框,说这是xx的公钥指纹(就是公钥的摘要信息,通过MD5、SHA等生成,便于比较公钥),确认连接吗。但这很明显不适用于HTTPS,不可能让用户在浏览器输入一个URL后再手动确认一下公钥,而且用户也不知道你的公钥是什么。

解决方案就是浏览器和操作系统内置一些安全可靠的第三方机构(证书颁发机构,CA)的证书,他们的证书被称为根证书。证书最核心内容就是它的公钥,即浏览器/操作系统内置一些CA机构的公钥,网站首先将自己的网站域名公钥等信息提交到CA,CA审核确认后,就将网站域名、公钥、有效期等信息进行SHA哈希加密,生成摘要,然后再用自己的私钥对摘要进行加密,生成签名,然后再将网站信息和签名放在一起,这就是证书,生成证书的过程其实和生成签名的过程类似,只是最后少了一步公钥加密,因为证书的内容本来就是要公开的,只要不被篡改就行了,所以不需要加密。 总结一下证书内容:证书=公钥+申请者与颁发者信息+签名 (指纹)

这是浏览器内置的CA机构证书

聊聊加密与HTTPS_HTTPS

一个网站的证书会有这些信息

聊聊加密与HTTPS_HTTPS_02

7.2、HTTPS通信流程

1、浏览器将自己支持的加密算法发送给服务器,包括非对称算法、对称算法、hash算法等

2、服务器收到请求后,和自己支持的加密算法对比,选出双方都支持的加密的算法,并和自己的证书一起,返回给浏览器

3、浏览器收到证书后,用内置的对应的CA机构的公钥,按照证书指定的签名算法解密签名(也叫指纹),获取CA机构对证书计算的hash值,然后再将证书内容中除签名外的内容,按照证书指定的签名hash算法进行hash运算,然后再将这个hash值和解密得到的的hash值进行比对,如果一致,则说明证书可信,然后还会校验证书有效期等

4、确认证书有效,获取到服务器公钥后,浏览器生成一串随机数,用作对称加密的密钥,并对前面通信的所有内容进行hash运算,取得摘要,然后再用随机数对摘要进行对称加密,获取签名(不知道叫签名是否合适),然后再将随机数密钥和签名一起,用服务器公钥加密后发送给服务器

5、服务器接收到以后先用私钥解密,获取到签名和随机密钥,然后用随机密钥解进行对称加密运算解密签名,获取摘要,然后再将之前所有通信内容进行hash运算,得到另一个摘要,然后再比较两个摘要是否相等,确认相等后,浏览器再将之前所有通信内容的摘要,用收到的密钥进行加密后发送给浏览器

6、浏览器再用自己本地的随机密钥解密内容,和之前发送的通信内容hash摘要进行比对,如果一致,则握手过程结束,以上任意一步出现问题都将导致握手失败,往后浏览器和服务器的通信都使用随机密钥进行对称加密通信

这里的https通信流程只是一个大概的过程,通信的完整细节肯定比这个复杂很多

7.3、疑惑解答

1、为什么要使用对称加密?

因为对称加密效率高,且服务端不知道客户端身份,无法进行双向非对称加密

2、为什么是客户端生成随机密钥?

因为只有客服端持有服务端公钥,所以可以保证客户端发送给服务端的信息不被他人查看到,如果是服务端生成密钥,因为不持有客户端的公钥,所以只有用私钥加密,又因为公钥是公开的,所以所有人都可以知道服务端发送的内容。所以不可能在服务端生成对称加密密钥

3、为什么客户端发送密钥给服务端后,服务端要用密钥加密发送一次信息?

因为第4步,客户端发送密钥给服务端的过程并不安全,攻击者完全可以用自己的密钥替换客户端发送的密钥,也可以把签名给换了(因为前面通信的内容是明文的,所以攻击者也可以获取整个通信内容,所以我觉得叫签名不太合适),如果被替换,且服务端不使用密钥加密一段内容给客户端校验,那么就会出现服务端用攻击者的密钥加密数据,这样服务端发送的内容将被攻击者知晓,又因为客服端使用的是自己的密钥,无法解开服务端发送的数据,所以会很快导致通信失败,所以被攻击者能知晓的信息很有限,可能就一两次发送的内容,但这也不够安全,所以需要服务端收到密钥后,用密钥加密一段内容交由客服端校验服务端收到的密钥是不是自己发送的密钥,那么加密什么内容比较好呢?加密之前整个通信内容吧,双方都知道,且可以校验之前通信的内容没有被篡改过

其他

如文章有误,欢迎指正,也欢迎评论讨论