看了JWT的加密过程,开始对HTTPS的加密过程感兴趣了,所以顺便也一起详细了解一下
比如如何防止篡改,之前听说过中间人攻击,就是截取了HTTP请求,然后对你发送的数据进行篡改后,再次发给服务端,那服务端就要解决一个问题,我怎么知道这个数据被篡改了呢?
HTTP请求原先是明文传输的,所以请求如果被劫持,信息则全泄漏了,且可能被篡改信息,而服务端和客户端双方都没有察觉,所以需要对信息进行加密
如果通信双方都各自持有同一个密钥,且没有其他人知道,双方的通信安全就可以被保证
但是需要保证该密钥只有双方知道,其他人并不知道,因为服务端和客户端之间传输过程是可能被劫持的,被劫持后就可以通过该密钥来解开双方传输的任何内容
所以得保证传输过程安全,而这个就是我们想做的,那去掉传输这一步怎么样?
第一个想法是像服务端一样,一开始就保存好了,但是想要浏览器像服务端一样保存着所有HTTPS网站的密钥是不可能的
那这时候就需要非对称密钥
即使用一个私钥和一个公钥,私钥存储于服务端,公钥的话则由服务端生成并传输给客户端,公钥加密的只能由私钥来进行解析,而私钥加密的只能由公钥进行解析,这就可以保证前面说的,客户端用公钥加密后传输给服务端,而服务端来进行解析,可以保证客户端传输的只能由服务端来解析,保证数据安全,但是由于服务端传输给客户端的数据可以用公钥进行解析,那这条路线上的数据就不一定安全了,如果拿到了第一个明文传输的公钥,则可以对服务端传输的数据进行解析,所以在一定程度上也不安全
那一组公钥私钥可以满足单线路上的传输安全,那两组的话是不是就可以保证双向安全了呢?
其实是可以的,但是非对称加密的计算十分耗费时间,HTTPS就没有采取这种方法
HTTPS采取的是非对称加密+对称加密,减少了非对称加密的次数
过程:
服务器拥有用于非对称加密的公钥A,私钥A' 浏览器向服务端请求,服务器将公钥A明文传输给浏览器 浏览器随机生成一个用于对称加密的密钥X,用公钥A加密后传给服务器 这样用公钥A加密后只能由A'进行解密,所以保证这个对称加密的密钥X的传输安全 服务器拿到加密后的X,用私钥A'进行解密得到密钥X 这时就保证了双方都拥有密钥X,且别人无法得知,就可以安全地传输信息了
HTTPS基本就是采用了这种方法,但还是有漏洞
这时候又需要详细了解中间人攻击
了,它仍可以拿到你传输的数据,只不过没有密钥无法解密而已
但是要记住,我们有一步是明文传输的,即第一步将公钥明文传输给浏览器,这时候先进行中间人劫持把公钥明文拿到,那想想如果你拿到了能干什么呢?
首先不能让这个公钥正常传输给浏览器,否则后面对称加密后我也没有任何办法去解密了,那我能不能 偷偷用把这个公钥换成我自己的,把公钥A换成我生成的公钥B,然后我有自己的私钥B'可以解密 那这时候的步骤就是这样 1.服务器生成公钥A,私钥A',传输公钥A给浏览器 2.中间人劫持,将公钥A改为公钥B 3.浏览器拿到公钥B,用公钥B加密生成的对称加密的密钥X传给服务器 4.中间人劫持后用私钥B'解密得到密钥X,再用公钥A加密后传给服务器 5.这时服务器拿到的还是公钥A加密后的X,然后用私钥A'解密得到对称加密的密钥X
这样的步骤下来,双方都没发现异常,但是对称加密的密钥X已经被中间人拿到了,那它也可以参与解密cs之间传输的数据了,那发生这个情况的原因是浏览器无法确认收到的公钥是否是该服务器发送的
,该公钥也无法进行加密,否则又需要进行解密,就成套娃了
那这时候就要引入一个新的概念,数字证书
网站在使用HTTPS前,需要向CA机构申请一份数字证书,证书里包括持有者信息,公钥信息等,服务器把证书传输给浏览器,浏览器从证书里获取公钥即可
证书在这里就是身份证,证明一个公钥对应的是该网站,那如何防止这个证书被篡改,就是签名
所解决的问题
数字签名的制作过程
明文和数字签名共同组成了数字证书,然后将数字证书颁发给网站,即服务端
浏览器拿到服务端发来的数字证书后,需要验证数字证书是否被篡改
浏览器验证过程:
数字签名就是对明文hash后再私钥加密后得到的值,为什么要用hash,直接加密不可以吗?
主要是性能问题,非对称加密效率差,证书信息一般较长,而hash后得到的是固定长度的信息,加 解密就更快了,而且还有安全上的问题
那如何保证安全?
首先中间人攻击仍然能拿到第一个,不过这时拿到的是一个数字证书,如果篡改了明文,由于没有私钥,无法对篡改后的值进行加密后签名,所以浏览器拿到的会发现原文和签名解密值不一致。
而且攻击者无法整体替换证书,因为浏览器可以比对证书的域名以及请求域名,如果不同则说明被篡改了
其实总结起来,前面的一大堆非对称加密步骤是为了后面的对称加密,数据传输的加解密还是通过对称加密进行的,而数字证书是为了解决非对称加密的公钥的可信问题
每次进行HTTPS请求时在SSL/TLS层不需要每次都传输密钥
服务器会为每个浏览器维护一个sessionid,在TLS握手阶段传给浏览器,浏览器生成好密钥传给服务器,服务器将密钥存到相应的sessionid,之后每次请求都携带sessionid,服务器根据sessionid找到密钥进行加解密,就不需要每次都重新制作、传输密钥
先到这里吧,后面可能会研究一下TLS的握手机制
本文作者:Malyue
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!