中间人攻击
在 http 数据提交给 TCP 层之后,会经过用户电脑、路由器、运营商、服务器,这中间每一个环节,都不是安全的
一句话就是:在 http 传输过程中容易被中间人窃取、伪造、篡改,这种攻击方式称为中间人攻击
。
那怎么让数据可以更安全的传输呢?
就是使用 https ,利用 https 安全层对数据进行加解密操作,以保证数据安全。
关于 https性能优化、版本、优缺点、SSL/TLS、握手(RSA、TLS1.2、TLS1.3)三个版本及优化等等,文章太长这里就不展开了,可以看我另一篇文章有详细介绍
那么 https 是如何对数据加解密的呢?这要先说一下它的算法
对称加密算法
就是加密和解密使用同一个密钥。如AES、DES
。加解密过程:
- 浏览器给服务器并发送一个随机数
client-random
和加密套件
(一个支持的加密方法列表) - 服务器生成给浏览器返回另一个随机数
server-random
和加密套件
- 两边分别返回确认消息。然后两者用加密方法将两个随机数混合生成密钥,这就是通信双上加解密的密钥
有了密钥之后就可以对数据进行加密传输了
问题是client-random
和server-random
都是明文的,双方如何安全的传递两个随机数和加密方法呢?直接传给客户端,那过程中就很可能被窃取,中间人还是能解密拿到数据,往下看
不对称加密算法
就是一对密钥,有公钥
(public key)和私钥
(private key),其中一个密钥加密后的数据,只能用另一个密钥进行解密。如RSA
、ECDHE
。加解密过程:
- 浏览器给服务器发送
加密套件
- 服务器选好支持的
加密方法
和公钥
(明文) 传给浏览器 - 两边分别返回确认消息。然后浏览器用公钥对数据进行加密,这个密钥只能用
私钥
解密
这是不是看上去很完美了
其实还存在很严重的问题
- 使用公钥反推出私钥是非常困难,但不是做不到,随着计算机运算能力提高,非对称密钥
至少要2048位才能保证安全性
,这就导致加解密速度慢,效率太低 - 无法保证服务器发送给浏览器的数据安全。因为浏览器可以用公钥来加密,而浏览器就只能用私钥加密,公钥是明文传输的,中间人可以获取到,这样服务器端的数据安全就得不到保证了
所以!
混合加密
TLS实际用的是两种算法的混合加密
。通过 非对称加密算法 交换 对称加密算法 的密钥,交换完成后,再使用对称加密进行加解密传输数据。这样就保证了会话的机密性。过程如下
- 浏览器给服务器发送一个随机数
client-random
、对称和非对称加密套件
- 服务器把另一个随机数
server-random
、加密套件
、公钥
传给浏览器 - 浏览器又生成另一个随机数
pre-random
,并用公钥对pre-random
加密后传给服务器 - 服务器再用私钥解密,得到
pre-random
,并返回确认消息 - 这样浏览器和服务器都有三个随机数了,然后各自将三个随机数用加密方法混合生成最终的对称密钥
然后开始数据加密传输
这样即便被截持,中间人没有私钥就拿不到pre-random
,就无法生成最终密钥
这样就安全了吗?
emmmm……还没
因为问题又来了,如果一开始DNS就被中间人劫持
,那么请求被中间人截获,中间人把他自己的服务器公钥给了浏览器,浏览器收到公钥就把信息发给中间人了,中间人解密拿到数据,并干了一些见不得人的勾当之后,再请求实际服务器,拿到服务器公钥,再把加密处理过后的数据发给服务器
这样不知不觉间信息就被人窃取了,所以在结合对称和非对称加密的基础上,还需要服务器向浏览器证明身份,那怎么证明呢?
所以数字证书
来了,往下看
如何保证数据是否被篡改?
数字证书(数字签名)
它可以帮我们验证服务器身份
,而且数字证书里包含了公钥,而数字证书需要向有权威的认证机构(CA)
获取授权给服务器。
相比之前就变成了
- 服务器不直接返回公钥给浏览器,而是返回数字证书,而公钥就在数字证书中
- 浏览器这边多了一步证书验证,验证成功才能继续后续流程
那么如何申请数字证书呢?
- 首先,服务器准备一套
公钥
和私钥
,私钥留着自己用 - 服务器将公钥和站点等信息提交给CA认证,这个是
要钱
的 - CA
验证
服务器提供的信息 - 审核通过后签发认证的数字证书,包含了
公钥
、CA信息
、有效时间
、证书序列
等这些都是明文的,还有一个CA生成的签名
CA的签名过程
- CA也有一套
公钥
和私钥
- CA使用摘要算法计算服务器提交的明文信息并得出
信息摘要
- 然后CA再用它的私钥和特定的算法对信息摘要加密,生成
签名
- 把
签名
、服务器公钥
等信息打包放入数字证书
,并返回给服务器 - 服务器配置好证书,以后浏览器连接服务器,都先把证书发给客户端验证
摘要算法:主要用于保证信息的完整性。常见的MD5算法、散列函数、hash函数都属于这类算法,其特点就是
单向性
、无法反推原文
浏览器如何验证数字证书
- 浏览器连接服务器,都先把证书发给客户端验证
- 使用CA公钥和声明的签名算法对CA中的签名进行解密,得到服务器的
摘要内容
和服务器公钥 - 再用摘要算法对证书里的服务器公钥生成摘要,再把这个摘要和上一步得到的摘要
对比
- 然后将两个信息摘要对比,如果是一致的,就说明证书是合法的,即证明了服务器自己,否则就是非法的
证书认证又分为单向认证
和双向认证
单向认证:服务器发送证书,客户端验证证书
双向认证:服务器和客户端分别提供证书给对方,并互相验证对方的证书
不过大多数https服务器都是单向认证,如果服务器需要验证客户端的身份,一般通过用户名、密码、手机验证码等之类的凭证来验证。只有更高级别的要求的系统,比如大额网银转账等,就会提供双向认证的场景,来确保对客户身份提供认证性
另外在申请和使用证书的过程中,需要注意
- 申请数字证书是不需要提供私钥的,要确保私钥永远只能由服务器掌握
- 数字证书最核心的是CA使用它的私钥生成的数字签名
- 内置CA对应的证书称为根证书,根证书是最权威的机构,它们自己为自己签名,这称为
自签名证书
有了这些之后就安全了吗?
emmmmm…..没有
虽然不是绝对安全,但是现行架构下最安全的解决文案了,大大增加了中间人的攻击成本