带你在网络世界里飞-https

前面的文章,说了互联网模型及协议,dns解析,http协议,编码等问题,这次咱开始捋https,你如果想让你的网页看起来很安全,同时又不想让地址栏左侧出现感叹号或问号啥的,那https你就很有必要了解一下了。。。

之前文章都习惯说说话题的历史,这个https就不说了,因为导致https产生的原因比历史更值得关注,而https是基于http协议的,因此还得从http协议说起。

到目前为止,我们已经了解到http协议有相当优秀和方便的一面,然而http协议并非只有好的一面,事物皆有两面性,其也有不足的一面,特别是在安全方面,比如以下几点:

1, 通信使用明文(不加密),内容可能被窃听

2,不验证通信双方的身份,可能遭遇伪装

3,无法证明报文的完整性,可能被篡改

上图可以反映出,在网络世界里,任何一个环节都可以遭到窃听,可能有人就要说,加密不就好了。。。其实没这么简单,http之所以没有加密,是因为按tcp/ip协议族的工作机制,通信内容在所有的通信线路上都可以遭到窥视。所谓互联网,是由能联通到全世界的网络组成的,无论世界哪个角落的服务器在和客户端通信时,在此通信线路上的某些网络设备,光缆,计算机等都不是个人的私有物,所以不排除某个环节中会遭到恶意窥视。即使是加密处理的通信,也能看到加密后的通信内容,只是增加了破解通信内容的难度而已。。。

而窃听也很简单,只要收集在互联网上流动的数据包就可以了,比如一些抓包工具。这里只说了http协议不安全,其实其他的很多未加密的传输协议也都是一样不安全,只因http是运用最广的协议之一,所以才基于此产生了https而已。但要务必注意,https并不是一种新协议(下面会详说)。。。

既然http有不少问题,那就逐个分析一下:

问题一:通信使用明文(不加密),内容可能被窃听

如何解决?

1,配合SSL和TLS将通信加密

2,利用加密算法对通信内容加密

由于http协议没有加密机制,但可以通过配合SSL(secure socket layer,安全套接层)或TLS(Transport layer security ,安全层传输协议 )组合使用。他们二者啥关系呢?我们这里先知道TLS是基于SSL发展起来的安全通信机制,更加可靠一些。用SSL或TLS建立安全通信线路后,就可以在这条线路上进行http通信了。如下图:

还有一种就是利用加密算法单独对通信内容进行加密,因为http协议本身没有加密机制,因此就对http协议传输的内容进行加密。在这种情况下,客户端需要对http报文进行加密后再发送,而服务器端同样需要解密才可以。在使用vue等框架时,一般都可以对发送ajax的请求做全局过滤处理,还可通过配置参数,来决定哪些请求加密。。。

问题二:不验证通信双方的身份,可能遭遇伪装

包括以下几种情况:

1,无法确定目标服务器就是返回响应的服务器

2,无法确定收到响应的客户端就是发出请求的客户端

3,无法确定请求来自何方,出自谁手

4,无法阻止海量请求,如Dos(denial of service)攻击

所谓Dos攻击:利用被攻陷的僵尸电脑,不停的向特定服务器发起请求,使目标服务器的网络或系统资源耗尽,使其服务终端或停止,导致正常用户无法访问。而DDos(distributed denial-of-service attack)分布式拒绝服务攻击,则是分布在网络上的多台僵尸电脑对目标服务器发起攻击。。。

如何解决?

答:证书。

在http协议通信时,由于不存在确认通信双方的处理步骤,任何人都可以发起请求。另外服务器也是接收到请求,不管是谁都会返回响应(黑名单除外)。但如果在通信之前,先去验证一下身份呢?如下:

虽然使用http协议无法确认通信方,但如果使用TLS或SSL则可以,TLS或SSL不仅提供通信加密处理,还使用证书确认通信双方。

证书是值得信赖的第三方机构颁发,用来证明服务器和客户端是实际存在的(这里只是说实际存在的,并不能保证是否合法)。另外伪造证书从技术角度来说异常困难,因此只要确认了通信双方持有的证书,即可间接的确认通信双方的身份。同理,客户端持有证书即可完成对个人身份的确认,也可用于web网站的认证环节。

问题三:无法证明报文的完整性,可能被篡改

如何解决?

1,用MD5,SHA等散列值校验。

2,确认文件的数字签名。

所谓完整性是说,接收到的数据,和服务器本来想返回来的数据不一致,比如经常下载应用安装包,安装后经常出现问题,这就是中间人攻击(MITM,man in the middle attack)。这是因为http协议,在请求或响应送出之后直到对方收到之前的时间内,即使请求和响应被篡改,也没有办法知道。(对于开源项目,这种情况更是可怕,但一般攻击的人也会考虑收益率才会下手)

因此为了保证数据的完整性,一般提供下载服务的web网站都会提供PGP(pretty good privacy 完美隐私)创建的数字签名以及MD5(message-digest algorithm 信息摘要算法),SHA算法生成的散列值。PGP是用来创建文件数字签名的基于各种加密算法的方式。MD5是由单向函数生成的散列值,但不管怎样,都需要用户把文件下载下来以后,自行验证文件签名和官网提供的是否一致。如下图Apache提供的文件下载校验:

PGP加密由一系列散列、数据压缩、对称密钥加密,以及公钥加密的算法组合而成。每个步骤支持几种算法,可以选择一个使用也可以组合使用。每个公钥均绑定唯一的用户名和/或者E-mail地址。具体的检验方法,是从官网下载提供的密钥,然后按照官网的提示进行操作即可,不过我没有操作过,各位自己搞吧,看好你们哦。。。

SHA-1(Secure Hash Algorithm 1,安全散列算法1)是一种密码散列函数,SHA-1可以生成一个被称为消息摘要的160位(20字节)散列值,散列值通常的呈现形式为40个十六进制数。1996年后被证实存在弱点,可以被加以破解,对于需要高度安全性的数据,专家一般建议改用其他算法,如SHA-3等。

MD5消息摘要算法(MD5 Message-Digest Algorithm),一种被广泛使用的单向密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。其原理是:将数据(如一段文字)运算变为另一固定长度值。但务必注意MD5不是加密算法,不能用作加密数据用途。。。2004年,证实MD5算法无法防止碰撞(collision),因此不适用于安全性认证,如SSL公开密钥认证或是数字签名等用途。

这里再说说数字签名,上面我们知道了md5,SHA散列算法等,其实数字签名是在这个基础上做的,比如我们想对一个文件A做数字签名,则我们需要先对文件A做MD5处理生成一个字符串,然后再用自己的RSA(下面有具体原理)私钥对这个字符串加密,加密后得到的字符串再添加到文件A里,然后这个文件A此刻就具有签名了。然后就可以发送给其他人了。。。

那具有数字签名的文件,别人拿到之后怎么校验呢?上面提到了用RSA私钥加密,因此与RSA私钥对应的公钥就可以公开了,别人再拿到这个公钥就可以先对数字签名解签(其实相当于解密),然后再验证MD5值是否一致即可。。。

可惜的是,这些方法也依然无法百分百确认结果正确,因为PGP,MD5,SHA本身可能被修改,用户是没有办法知道的。。。

为了有效防止这些弊端,就有必要使用https,TLS/SSL提供认证和加密处理,再配合完整性校验,这样一来就可以抵抗绝大多数的攻击了。

这便是:http+认证+加密+完整性校验=https

但具体说原理之前,咱还需要先了解一下加密的相关知识,常用的加密方法有很多种,这里主要说两种:对称加密的AES和非对称加密的RSA。

对称加密AES(AdvancedEncryptionStandard,高级加密标准),该加密算法使用同一个密钥的方式对数据进行加解密,是一种区块加密方法,所谓区块也叫分组加密,就是将明文分成多个等长的模块(block),使用确定的算法和密钥对每组分别加密解密,而AES的区块长度固定为128位,而密钥则可以是128,192或256位。

以这种方式加密数据时,首先需要将密钥发送给对方,但如何安全的发送密钥呢?在互联网上传输,则通信可能被监听,也就失去了加密的意义,如下图:

因此为了解决这个问题,RSA非对称加密就出场了。。。

RSA(三个发明者的名字首字母),一种非对称加密算法,而一个RSA算法的可靠性与对整数因式分解的难度成正比。现在为止,只有短的RSA秘钥才可能被强力破解,到目前为止,世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长,用RSA加密的信息实际上是不能被解破的。其实RSA之所以诞生,还源于人们认识到,加密和解密可以使用不同的规则,只要这两种规则之间存在某种对应关系即可,这样就避免了直接传递密钥。

RSA特点:

1,乙方生成两把密钥(公钥和私钥),公钥是公开的,任何人都可以获得,私钥则是乙方秘密存储。

2,甲方获取乙方的公钥,然后用它对信息加密

3,乙方拿到加密后的信息,用私钥解密

上面说了两种加密方式,而https则是采用混合加密,也就是对称加密和非对称加密两种。在交换秘钥环节使用非对称加密,之后建立通信交换报文数据阶段使用对称加密。之所以这样,是因为非对称算法复杂,处理速度要慢很多,因此若在通信阶段使用非对称加密,效率会很低。。。

但仍然有个问题,那就是如何证明RSA的公钥是货真价实的,比如正和某台服务器建立非对称加密的通信,如何证明收到的公钥就是原本预想的那台服务器发行的公钥呢?或许公钥在传输途中就已经被修改。。。

因此还必须有第三方机构,也就是数字证书认证机构CA(Certificate Authority)或其他相关机关颁发的公钥证书。数字证书认证机构处于客户端和服务器双方都可信赖的第三方机构的立场上。

具体申请证书的流程如下:

1,服务器运营人员向CA提出RSA公钥的申请,CA在判定申请者的身份后,会对公钥做数字签名(上面说过了数字签名),然后分配这个已签名的公钥,并将公钥放在公钥证书里。

2,服务器会将这份由CA颁发的公钥证书发给客户端,以进行非对称加密通信。

3,接到证书的客户端可使用CA的RSA公钥,对证书的数字签名进行验证,一旦验证通过,客户端便可确定两件事:一是CA的RSA公钥是来自真实有效的CA,二是服务器的RSA公钥是值得信赖的。

这里有点绕,咱需要知道,加密和签名是不同的,在RSA中,加密是公钥负责加密,私钥负责解密,而签名是私钥负责签名,公钥负责验证。

可能有人要问了,第三方机构的公钥怎么给客户啊?如何安全的转交确实很困难,因此多数浏览器开发商发布版本时,会事先在浏览器内部植入常用认证机关的公钥。

具体图解流程如下:

SSL机制中介入认证机构之所以可行,是因为建立在CA其信用绝对可靠的前提下,但也不能百分百保证认证机构不被攻击。。。还有使用开源程序如OpenSSl程序,自己给自己构建一个认证机构,并给自己服务器颁发证书,这种叫自认证机构,颁发的证书叫自签名证书,但很多浏览器厂商是不承认的,这些自认证机构颁发的证书,作用顶多也就是自我对外宣称:我是xxx的效果。

对于中级认证机构,不同浏览器厂商的表现不一致。。。

前面说了,https并非是应用层的一种新协议,只是http通信接口部分用了SSL(Secure Socket Layer)和 TLS(Transport Layer Security)协议而已。之前http直接和tcp通信,当使用SSL时,则演变为先和SSL通信,再由SSL和tcp通信了,因此所谓https,不过是身披SSL协议外壳的http,如下:

SSL是一个独立的协议,所以不光是http协议,其他运行在应用层的SMTP和Telnet等协议都可以配合SSL协议使用,可以说SSL是当今世界上应用最为广泛的网络安全技术。具体流程如下:

具体的SSL或TLS流程在文章底部,感兴趣的可以自行查看。。。

但使用SSL也会有一些问题,那就是效率会变慢,一种是通信慢,一种是由于加密大量消耗CPU及内存资源,导致处理速度变慢,如下:

和http相比,网络负载可能变慢2~100倍,除去和tcp连接,发送http请求,响应以外,还必须进行SSL通信,因此整体上处理通信量不可避免会增加。另外SSL还必须进行加密处理,在服务器和客户端都需要进行加解密运算,因此会消耗更多的硬件资源,导致负载增大。。。

可以尝试在终端输入以下代码查看具体SSL建立通信的耗时与TCP连接的耗时详情(后面的域名可以自己填写,最好测多次,然后取平均值):

因此对于非敏感信息的网站建议使用http通信,只有在包含个人信息等敏感数据时才使用https加密通信。。。

----------------SSL/TLS过程----------------

一:客户端发出请求(ClientHello)

首先,客户端(通常是浏览器)先向服务器发出加密通信的请求,这被叫做ClientHello请求。

在这一步,客户端主要向服务器提供以下信息。

(1) 支持的协议版本,比如TLS 1.0版。

(2) 一个客户端生成的随机数,稍后用于生成"对话密钥"。

(3) 支持的加密方法,比如RSA公钥加密。

(4) 支持的压缩方法。

这里需要注意的是,客户端发送的信息之中不包括服务器的域名。也就是说,理论上服务器只能包含一个网站,否则会分不清应该向客户端提供哪一个网站的数字证书。这就是为什么通常一台服务器只能有一张数字证书的原因。

对于虚拟主机的用户来说,这当然很不方便。2006年,TLS协议加入了一个Server Name Indication扩展,允许客户端向服务器提供它所请求的域名。

二:服务器回应(SeverHello)

服务器收到客户端请求后,向客户端发出回应,这叫做SeverHello。服务器的回应包含以下内容。

(1) 确认使用的加密通信协议版本,比如TLS 1.0版本。如果浏览器与服务器支持的版本不一致,服务器关闭加密通信。

(2) 一个服务器生成的随机数,稍后用于生成"对话密钥"。

(3) 确认使用的加密方法,比如RSA公钥加密。

(4) 服务器证书。

除了上面这些信息,如果服务器需要确认客户端的身份,就会再包含一项请求,要求客户端提供"客户端证书"。比如,金融机构往往只允许认证客户连入自己的网络,就会向正式客户提供USB密钥,里面就包含了一张客户端证书。

三:客户端回应

客户端收到服务器回应以后,首先验证服务器证书。如果证书不是可信机构颁布、或者证书中的域名与实际域名不一致、或者证书已经过期,就会向访问者显示一个警告,由其选择是否还要继续通信。

如果证书没有问题,客户端就会从证书中取出服务器的公钥。然后,向服务器发送下面三项信息。

(1) 一个随机数。该随机数用服务器公钥加密,防止被窃听。

(2) 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。

(3) 客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供服务器校验。

上面第一项的随机数,是整个握手阶段出现的第三个随机数,又称"pre-master key"。有了它以后,客户端和服务器就同时有了三个随机数,接着双方就用事先商定的加密方法,各自生成本次会话所用的同一把"会话密钥"。

至于为什么一定要用三个随机数,来生成"会话密钥",dog250解释得很好:

"不管是客户端还是服务器,都需要随机数,这样生成的密钥才不会每次都一样。由于SSL协议中证书是静态的,因此十分有必要引入一种随机因素来保证协商出来的密钥的随机性。

对于RSA密钥交换算法来说,pre-master-key本身就是一个随机数,再加上hello消息中的随机,三个随机数通过一个密钥导出器最终导出一个对称密钥。

pre master的存在在于SSL协议不信任每个主机都能产生完全随机的随机数,如果随机数不随机,那么pre master secret就有可能被猜出来,那么仅适用pre master secret作为密钥就不合适了,因此必须引入新的随机因素,那么客户端和服务器加上pre master secret三个随机数一同生成的密钥就不容易被猜出了,一个伪随机可能完全不随机,可是是三个伪随机就十分接近随机了,每增加一个自由度,随机性增加的可不是一。"

此外,如果前一步,服务器要求客户端证书,客户端会在这一步发送证书及相关信息。

4.4 服务器的最后回应

服务器收到客户端的第三个随机数pre-master key之后,计算生成本次会话所用的"会话密钥"。然后,向客户端最后发送下面信息。

(1)编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。

(2)服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供客户端校验。

完整的示意图可参考:

至此,整个握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的HTTP协议,只不过用"会话密钥"加密内容。

到现在为止,有关网络通信在纵向的知识就差不多了,下一篇再写一个关于网络诊断的文章,这个系列就差不多了。如果屏幕前的你能连续看到这里,你真的很厉害了。。。因为这里面确实有很多东西,虽然是我搜罗的,但很多我也需要仔细思考很久才会明白。。。

恭喜你,又对这个网络世界了解更多了一些

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180331G1IA3D00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

同媒体快讯

扫码关注云+社区

领取腾讯云代金券