之前的文章讲golang webSocket编程的文章中提到过Http协议的概念,通过之前的了解我们也知道Http协议其实就是基于传输层的TCP协议和网络层的IP协议实现的一个协议,所以他拥有TCP/IP的所有特性。也正是因为它使用TCP/IP协议,导致它会有以下问题:
- 通信使用明文,通信内容有可能会被窃听
- 不验证通信方的身份,有可能遭遇伪装
- 通信内容可能遭到篡改
1. HTTP存在的风险
1.1 通信明文内容有可能会被窃听
由于HTTP本身不具有加密功能,所以无法做到对HTTP协议通信的请求和相应内容进行加密,即HTTP报文只能使用明文方式发送。按照TCP/IP协议族的工作机制,通信的内容在所有的通信线路上都有可能遭到窥视。
所谓互联网,是有连通到全世界的网络组成的。无论世界哪个角落的服务器和客户端通信时,在此通信线路上的某些网络设备、光缆、计算机等都不可能是个人的私有物,所以不排除某个环节中遭到恶意窥视的行为。
即使已经加密处理的通信,也会被窥视到通信内容,这点和未加密的通信是相同的。只是说如果通信经过加密,就有可能让人无法破解原文信息的含义,但是加密处理后的报文信息本身还是会被看到。
窃听相同段上的通信并非难事,只需要收集在互联网上流动的数据包(帧)就行了。对于收集来的数据包的解析工作,可以交给那些抓包(Packet Capture、wireshark)或嗅探器(Sniffer)工具。
1.2 不验证通信方的身份,可能遭遇伪装
HTTP协议中的请求和响应不会对通信方进行确认,也就是说存在“服务器是否就是发送请求中URI真正指定的主机,返回的相应是否真的返回到实际提出请求的客户端”等类似的问题。会存在以下隐患:
- 无法确定请求发送至目标的web服务器是否是按照真实意图返回响应的那台服务器,有可能是已伪装的web服务器。
- 无法确定响应返回到的客户端是否是按照真实意图接收响应的那个客户端,有可能是已伪装的客户端。
1.3 通信内容可能遭到篡改
上面讲到HTTP报文是在网络中裸奔的,有可能回被窃听,并且通信双方也无法确认对方的身份。那么如果请求的服务器是伪装的服务器或者报文传输过程中被中间节点篡改,客户端也无法感知到。
比如,从某个web网站下载内容,客户端是无法确认下载的文件和服务器上存放的文件是否一致的。文件传输途中有可能已经被篡改为其他内容。即使内容已经被改变,客户端浏览器也无法感知到。
虽然有使用HTTP协议确定报文完整性的方法,但事实上并不方便、可靠。其中常用的是MD5和SHA-1等散列值校验方法,以及用来确认文件的数字签名方法。但是这些方法只能保证HTTP报文是完整的,并无法保证报文是正确的。比如用户想从某网站下载一张“秋香”的图片,但是在传输过程中,内容被整体修改为“如花”,并且数字签名也重新生成了,那么当报文到达客户端浏览器时,浏览器依然会认为报文是完整的,报文是否正确只能由本人确认。
为了有效防止HTTP协议以上这些弊端,有必要使用HTTPS。其实HTTPS说白了就是HTTP + 加密 + 身份认证 + 报文正确性保障。
2. HTTPS协议
2.1 基础概念
HTTPS,即超文本传输安全协议(HyperText Transfer Protocol Secure,也被称为HTTP over TLS、HTTP over SSL或HTTP Secure)是一种通过计算机网络进行安全通信的传输协议。HTTPS经由HTTP进行通信,但利用SSL/TLS来加密数据包。HTTPS开发的主要目的,是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。这个协议由网景公司(Netscape)在1994年首次提出,随后扩展到互联网上。
HTTPS的主要作用是在不安全的网络上创建一个安全信道,并可在使用适当的加密包和服务器证书可被验证且可被信任时,对窃听和中间人攻击提供合理的防护。
2.2 HTTP到HTTPS的演化过程
2.2.1 对称加密
HTTP最大的问题在于报文的裸奔,如果可以把通信报文进行加密,那么问题是不是就解决了?所以人们想到一个办法:对传输的信息加密。而加密算法中最方便的就是对称加密算法(加密和解密时使用相同的密钥)。如下图所示:
这种方式属于对称加密,双方持有相同的密钥,再第三方不知道加密密钥的前提下信息可以安全传输,但此种方式的缺点是:
- 不同的客户端、服务器数量庞大,所以双方都需要维护大量的密钥,维护成本很高
- 因每个客户端、服务器的安全级别不同,密钥极易泄露
- 密钥传递也是通过Http明文传递的,很有可能被窥探,使用密钥加密的信息仍然可以被窥探、篡改
2.2.2 非对称加密
使用对称加密算法的问题在于,客户端、服务端都需要维护密钥,并且加密的密钥不能保证得到安全传输,那有没有一种办法可以去掉加密的密钥,并且仍然可以达到加密的效果。答案是存在的,就是非对称加密,而非对称加密一个典型的算法就是RSA算法。
非对称加密算法不像之前的算法那样,双方必须协商一个保密的密钥,而是有一对儿钥匙, 一个是保密的,称为私钥,另外一个是公开的,称为公钥。用私钥加密的数据,只有对应的公钥才能解密,用公钥加密的数据,只有对应的私钥才能解密。
有了非对称加密这两个特性, 当客户端给服务端发消息的时候, 就可以先用服务端的公钥去加密(服务端的公钥是公开的,所有人都知道), 等到消息被服务端收到后, 就可以用自己的私钥去解密(只有服务端才能解开,私钥是保密的 )
这个方式看起来是非常安全的,但是其实也存在问题:
- 客户端获取服务端的公钥是通过Http获取的,存在被第三方篡改的可能,一旦客户端拿到非服务端的公钥,那么之后的通信就都不是安全的了(这个问题后面再解释)
- 非对称加密算法相比于对称加密,速度非常慢,很影响通信效率
2.2.3 对称加密 + 非对称加密
回到最初的问题,最开始想用一个密钥来加密通信,那个对称加密算法是非常快的,但是苦于密钥无法安全传输, 现在使用了非对称加密算法,但是非对称加密算法又效率又非常低。那么是否可以将上述两种算法结合一下, 分两步走:
- 服务端生成一个对称加密算法的密钥, 用非对称加密算法的方式安全发给客户端
- 服务端客户端随后就不用非对称加密算法了, 只用这个密钥,利用对称加密算法来通信
这样既解决了对称加密算法密钥无法安全传输,又解决了非对称加密算法效率低下的问题。看起来很完美,但是仍然是存在问题的,就是之前讲非对称加密的问题1,我们来分析一下。
假如,服务端给客户端发送公钥的时候, 有个中间人,截取了服务端的公钥, 然后把自己的公钥发给客户端,冒充服务端,客户端发的消息就是用中间人的公钥加密的,那中间人不就可以解密看到消息了?同时客户端还可以将自己篡改的消息使用真正服务端的公钥加密,发送给服务端。这个过程中,客户端服务端都是无法感知这个中间人的存在的。
现在看来,使用对称加密 + 非对称加密的方式,实可以解决单独使用对称加密或单独使用非对称加密的问题,但是仍有一个问题没法解决,那就是客户端无法保证自己收到的公钥来自真正的服务端。
2.2.4 对称加密 + 非对称加密 + 证书
使用对称加密 + 非对称加密的方式后,问题就在于怎么安全的分发公钥,即想办法声明公钥是来自真正的服务端,而不是别人冒充的。生活中,我们肯定知道公证处的概念,它提供的公正材料大家都信任,那么网络世界是否也可以建立一个这样具备公信力的认证中心,这个中心给服务端颁发一个证书,用于证明服务端的身份。而证书中除了包含服务端的基本信息之外,还包含一个最关键的内容:服务端的公钥。这样客户端就可以安全地拿到服务端的公钥了。然而理想很丰满,现实很骨感。证书怎么安全传输,如果证书传输过程中被篡改了怎么办?所以还需要一些额外的辅助验证措施,那就是数字签名。
简单来讲就是, 服务端可以把他的公钥和基本信息用一个Hash算法生成一个消息摘要, 这个Hash算法有个极好的特性,只要输入数据有一点点变化,那生成的消息摘要就会有巨变,这样就可以防止别人修改原始内容。
这种数字签名的方式,虽然第三方没办法改公钥,但是却可以把整个原始信息都替换了, 生成一个新的消息摘要, 这样客户端还是辨别不出来。为了解决这个问题,那就只能借助公证处再帮忙对消息摘要做个加密,如下:
让有公信力的认证中心(简称CA)用它的私钥对消息摘要加密,形成签名,然后原始信息和数据签名合并, 形成一个全新的东西,叫做“数字证书”。这样即使第三方替换原始信息,也因为不知道CA的私钥,而无法伪造证书。
当服务端把他的证书发给客户端的时候, 客户端就用同样的Hash算法, 再次生成消息摘要,然后用CA的公钥对数字签名解密, 得到CA创建的消息摘要, 两者一比,就知道有没有人篡改了!如果没人篡改, 客户端就可以安全的拿到服务端的公钥,有了公钥, 客户端就可以使用这个公钥加密一个随机数(随机数就是之后对称加密的密钥)发给服务端,之后双方就通过这个随机数使用对称加密通信。
到这,看似解决了问题,但是仔细一想,如果在客户端在获取CA公钥时,CA公钥被替换,第三方伪装成CA,这样后续的操作还是不安全的。完全就是鸡生蛋、蛋生鸡的问题,如果要跳出这个怪圈,就必须信任CA,并通过安全的方式获取他们的公钥。
这些CA本身也有证书来证明自己的身份,并且CA的信用是像树一样分级的,高层的CA可以证明底层CA的可靠性,而操作系统/浏览器中会内置一些顶层的CA的证书,相当于你自动信任了他们。所以可以认为客户端可以安全的拿到CA的公钥,那么也就不存在第三方伪装成CA的情况了。
我们再回顾一下之前的一个概念,HTTPS = HTTP + 加密 + 身份认证 + 报文正确性保障。
- HTTP:HTTPS其实就是安全的HTTP,传输层使用的TCP协议,网络层使用的IP协议。因为使用TCP协议,所以建立连接也需要进行TCP的三次握手、断开连接也需要四次挥手。与HTTP不同的是,因为HTTPS要保证报文安全传输,就是上面讲的使用对称加密 + 非对称加密结合的方式,所以可以进行报文传输的前提除了TCP的三次握手之外,还需要已经交换了对称加密的密钥,这个交换对称加密密钥的过程就是SSL握手,所以HTTPS连接 = TCP连接 + SSL连接,这就是为什么HTTPS比HTTP要慢的原因之一。
- 加密:HTTPS是安全的报文传输协议,所谓安全,就是使用对称加密方式对报文进行了加密。
- 身份认证:上面讲到,HTTPS可以进行报文传输的前提是TCP连接 + SSL连接,其实SSL连接就可以理解为客户端和服务端建立了安全的传输通道,其实就是双方安全地交换了之后报文对称加密的密钥。这个过程设计客户端对证书的验证,证书验证通过,就可以说明服务端是整整访问的服务端,而非伪造的。
- 报文正确性保障:因为双方的通信是通过约定的安全密钥,使用对称加密算法加密的。所以不存在被篡改的可能。比如第三方即使抓取了报文,但是因为不知道密钥,也不能篡改报文信息。这样就能保证我们下载的“秋香”肯定是“秋香”,而不会被第三方恶意篡改为“如花”。
最后用一个简化的HTTPS流程图来总结一下HTTPS访问流程, 如果你理解了前面的原理,这张图就变得非常简单:
参考链接:
1. 《码农翻身》
2. 《图解HTTP》