1. HTTP 协议
在谈论 HTTPS 协议之前,先来回顾一下 HTTP 协议的概念。
1.1 HTTP 协议介绍
HTTP 协议是一种基于文本的传输协议,它位于 OSI 网络模型中的
应用层
。
HTTP 协议是通过客户端和服务器的请求应答来进行通讯,目前协议由之前的
RFC 2616
拆分成立六个单独的协议说明(RFC 7230、RFC 7231、RFC 7232、RFC 7233、RFC 7234、RFC 7235),通讯报文如下:
POST http://www.baidu.com HTTP/1.1
Host: www.baidu.com
Connection: keep-alive
Content-Length: 7
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36
wd=HTTP
HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Encoding: gzip
Content-Type: text/html;charset=utf-8
Date: Thu, 14 Feb 2019 07:23:49 GMT
Transfer-Encoding: chunked
...
1.2 HTTP 中间人攻击
HTTP 协议使用起来确实非常的方便,但是它存在一个致命的缺点:
不安全
。
我们知道 HTTP 协议中的报文都是以明文的方式进行传输,不做任何加密,这样会导致什么问题呢?下面来举个例子:
-
小明在 JAVA 贴吧发帖,内容为
我爱JAVA
:
-
被中间人进行攻击,内容修改为
我爱PHP
-
可以看到在 HTTP 传输过程中,中间人能看到并且修改 HTTP 通讯中所有的请求和响应内容,所以使用 HTTP 是非常的不安全的。
1.3 防止中间人攻击
这个时候可能就有人想到了,既然内容是明文那我使用
对称加密
的方式将报文加密这样中间人不就看不到明文了吗,于是如下改造:
-
双方约定加密方式
-
使用 AES 加密报文
这样看似中间人获取不到明文信息了,但其实在通讯过程中还是会以明文的方式暴露加密方式和秘钥,如果第一次通信被拦截到了,那么秘钥就会泄露给中间人,中间人仍然可以解密后续的通信:
那么对于这种情况,我们肯定就会考虑能不能将秘钥进行加密不让中间人看到呢?答案是有的,采用
非对称加密
,我们可以通过 RSA 算法来实现。
在约定加密方式的时候由服务器生成一对
公私钥
,服务器将
公钥
返回给客户端,客户端本地生成一串秘钥(
AES_KEY
)用于
对称加密
,并通过服务器发送的
公钥
进行加密得到(
AES_KEY_SECRET
),之后返回给服务端,服务端通过
私钥
将客户端发送的
AES_KEY_SECRET
进行解密得到
AEK_KEY
,最后客户端和服务器通过
AEK_KEY
进行报文的加密通讯,改造如下:
可以看到这种情况下中间人是窃取不到用于
AES加密
的秘钥,所以对于后续的通讯是肯定无法进行解密了,那么这样做就是绝对安全了吗?
所谓道高一尺魔高一丈,中间人为了对应这种加密方法又想出了一个新的破解方案,既然拿不到
AES_KEY
,那我就把自己模拟成一个客户端和服务器端的结合体,在
用户->中间人
的过程中中间人模拟服务器的行为,这样可以拿到用户请求的明文,在
中间人->服务器
的过程中中间人模拟客户端行为,这样可以拿到服务器响应的明文,以此来进行中间人攻击:
这一次通信再次被中间人截获,中间人自己也伪造了一对公私钥,并将公钥发送给用户以此来窃取客户端生成的
AES_KEY
,在拿到
AES_KEY
之后就能轻松的进行解密了。
中间人这样为所欲为,就没有办法制裁下吗,当然有啊,接下来我们看看 HTTPS 是怎么解决通讯安全问题的。