https运行原理

jimmy 2018年06月03日 1,524次浏览

https运行原理

摘要

随着因特网的发展,http协议成为了互联网数据交互的主流协议,但是http协议是明文传输,难以保证数据的安全,因此https协议应用而生,https协议是http协议的加密版本,要了解https协议,就必须了解 ssl/tls,ssl/tls协议位于应用层和传输层之间。

tcpip

历史

HTTP/0.9(1991年)

http协议最早的版本是1991年推广的HTTP/0.9版本,那个版本只有一个非常简单的协议GET,没有报文头,GET是唯一允许的方法,响应内容必须是HTML

GET /index.html

<HTML>this from server</HTML>

HTTP/1.0 (1996年)

1.0版本相比0.9只支持GET,增加了POST,HEAD等。响应内容也不仅仅只有HTML,也增加了图片,视频,文本等。在request和response里面增加了报文头,并在respinse里面增加了status code状态码。另外还涉及了字符集,multi-part类型,授权,缓存,文本编码。

GET / HTTP/1.0
Host: kamranahmed.info
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5)
Accept: */*

HTTP/1.0 200 OK 
Content-Type: text/html
Content-Length: 2546
Expires: Thu, 05 Dec 1998 16:00:00 GMT
Last-Modified: Wed, 5 August 1996 15:55:28 GMT
Server: Apache 0.84

<HTML>this from server</HTML>

HTTP/1.1 (1999年)

1.1版本相比1.0版本主要改进有:

增加了新的method,有PUT, PATCH, OPTIONS, DELETE

head里面必填Host,在1.0不是必须的

在1.1版本http请求可以在tcp三次握手后多次使用,在1.0版本每次http传输需要新建tcp链接

Chunked Transfers,对于需要动态生成的内容,服务器在开始不知道长度是多少,没办法设置整个报文的Content-Length,服务器会在报文头里面增加Transfer-Encoding: chunked,并且在下面发送的每个chunk里面单独设置每个trunk报文的大小,当发送结束时,设置一个大小为0的trunk来通知客户端。

其他的特性还有:代理,缓存,Byte Ranges,Character sets,Client cookies,压缩,新的状态码 (http/1.1)

HTTP/2 (2015年)

http/2的目标是为了低延迟的传输,相比Http/1.1核心特性有

二进制传输,而不是文本

多路复用,在一个tcp链接上面支持多个异步http请求

使用HPACK技术压缩报文头

服务器推送技术,客户端一个请求,服务器客户多次响应

请求优先级功能,每个链接可以设置优先级

安全相关

ssl/tls协议历史

最初的ssl协议是有Netscape公司发明的。 1.0版本由于有安全漏洞没有发布。2.0发布于1995年2月,也有一些漏洞,迫使
Netscape在1996年发布了3.0版本。

1999年,在ssl3.0的基础上RFC 2246 发布了tls1.0,2006年发布了tls1.1,2008年发布了tls1.2 目前主流使用的就是tls1.2 2018年tls1.3草案发布

TLS握手

在tcp三次握手以后,tls将进行四次握手(只考虑单向认证), handshake messaging protocol 用于双方在真正传输加密数据之前协商加密密钥,定义了交换信息的格式和步骤。

握手过程 Basic TLS handshake(单向认证)

TLS单向认证,就是只有客户端认证服务端,需要四次握手,四次握手需要ssl协议交互4次,但是数据包会比四次多,因为一次握手的数据包如果超过了TCP层能够容纳的大小,就会被拆分为多个数据包发送,这里说的4次握手,还是把这多个数据包当错一次交互。从下面的抓包中,能够明确看出来。

ssl4

1 客户端发送ClientHello消息给服务端

内容包含了:支持的TLS协议版本,一个随机数(姑且叫做Random1),支持的加密算法和压缩算法,一个session id(用于后面客户端复用tls链接)

client hello

tls handshark protocal的值是22,Version 在第一次client hello里面填写的是TLS 1.0主要是为了保持兼容,客户端真正期望使用的版本号在下面的Clinet Hello里面值是0303表示TLS1.2 ,后面是随机数32字节,session id 32字节,后面是客户端支持的Cipher suites一共有55个: Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)

接着是客户端支持的压缩算法。

接着是扩展域,扩展域中有一个重要的是server name (Name Indication extension),如果服务器在同一个端口,支持多个域名使用不同证书来进行ssl握手,这个就是客户端告诉服务器使用哪个ssl证书用的。

扩展域中还有一个signature_algorithms来告诉服务器客户端支持的签名算法。

2 服务器响应一个ServerHello消息

内容包含:服务器选择的协议版本,一个随机数(姑且叫做Random2),从客户端的加密套件和压缩算法列表中选择的加密套件和压缩算法,一个session id.

server hello

从server hello报文中可以看出,最前面的版本号已经是TLS 1.2了。服务端生成的随机数5b13.....以及服务端选择的Cipher Suite是 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,后面是扩展域,其中server_name和客户端的一个意思,告诉对方使用的是哪个域名的证书。还有一个next_protocol_negotiation扩展域里面写的是Http/1.1告诉客户端本次ssl握手支持的后续协议是http/1.1

服务端发送Certificate消息给客户端

Certificate

服务器将证书发送给客户端,从截图中可以看出包含了2个证书,一个是自己域名的证书,一个是中间证书。由于使用的是lets encrypted签名的证书,中间证书不在客户端存在,所以在服务器上面配置证书的时候要选择fullchain文件,里面包含了用户证书和中间证书,这样浏览器才会信任。

服务端发送Server Key Exchange消息给客户端

ServerKeyExchange

DHE 和 DH_anon 加密套件会有这一步。里面包含了公钥,签名算法

服务端发送Server Hello Done消息给客户端

Server Hello Done

Server Hello Done 通知客户端 Server Hello 过程结束。

3 客户端发送Client Key Exchange , Change Cipher Spec , Finish消息给服务端
Client Key Exchange

client encrypt

这里包含了一个PreMasterSecret, PreMasterSecret是有服务器端公钥加密的
服务器和客户端使用Random1+Random2+PreMasterSecret 通过约定的算法生成后面的通信密钥。

4 服务端发送 Change Cipher Spec , Finish 消息给客户端,tls握手结束

加密套件 Cipher suite

Cipher suite包含四个部分,第一是密钥交换算法,第二是签名算法/验签算法,第三是摘要算法,第四是对称加密算法,一般写法是"密钥交换算法-签名算法-对称加密算法-摘要算法",下面是使用postman测试抓包到的加密套件一共54个,只展示最上面4个。
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)

TLS会话复用

TLS会话复用主要有两种方案:Session Identifier 和 Session Ticket。

Session Identifier 即会话标识符,一段随机数,服务器对每一次会话都保存下链接信息,类似于session。

客户端会记录上次链接的服务器ip端口,已经会话ID,在client hello 中带上session id
如果服务器端缓存中还有这个session id,则复用会话,如果这个session id在服务端不存在,则走正常握手流程

Session Ticket 是一种客户端保存会话信息的方法,类似于ticket。

总体来说就是在前面的会话结束后,服务器可以用自己的私钥加密一个随机数,发给客户端,客户端下次会话的时候,送上这个随机数,服务器认证成功后,就认为这是一个合法的tls会话,走简易流程。

非对称密钥交换

在非对称密钥交换算法出现以前,对称加密一个很大的问题就是不知道如何安全生成和保管密钥。非对称密钥交换过程主要就是为了解决这个问题,使得对称密钥的生成和使用更加安全。
密钥交换算法本身非常复杂,密钥交换过程涉及到随机数生成,模指数运算,空白补齐,加密,签名等操作。
常见的密钥交换算法有 RSA,ECDHE,DH,DHE 等算法。它们的特性如下:

RSA:算法实现简单,诞生于 1977 年,历史悠久,经过了长时间的破解测试,安全性高。缺点就是需要比较大的素数(目前常用的是 2048 位)来保证安全强度,很消耗 CPU 运算资源。RSA 是目前唯一一个既能用于密钥交换又能用于证书签名的算法。
DH:diffie-hellman 密钥交换算法,诞生时间比较早(1977 年),但是 1999 年才公开。缺点是比较消耗 CPU 性能。
ECDHE:使用椭圆曲线(ECC)的 DH 算法,优点是能用较小的素数(256 位)实现 RSA 相同的安全等级。缺点是算法实现复杂,用于密钥交换的历史不长,没有经过长时间的安全攻击测试。
ECDH:不支持 PFS,安全性低,同时无法实现 false start。
DHE:不支持 ECC。非常消耗性能。

对称内容加密

非对称密钥交换过程结束之后就得出了本次会话需要使用的对称密钥。对称加密又分为两种模式:流式加密和分组加密。流式加密现在常用的就是 RC4,不过 RC4 已经不再安全,微软也建议网站尽量不要使用 RC4 流式加密。
一种新的替代 RC4 的流式加密算法叫 ChaCha20,它是 google 推出的速度更快,更安全的加密算法。目前已经被 android 和 chrome 采用,也编译进了 google 的开源 openssl 分支---boring ssl,并且 nginx 1.7.4 也支持编译 boringssl。
分组加密以前常用的模式是 AES-CBC,但是 CBC 已经被证明容易遭受 BEAST 和 LUCKY13 攻击。目前建议使用的分组加密模式是 AES-GCM,不过它的缺点是计算量大,性能和电量消耗都比较高,不适用于移动电话和平板电脑。

数据完整性

这部分内容比较好理解,跟平时的 md5 签名类似,只不过安全要求要高很多。openssl 现在使用的完整性校验算法有两种:MD5 或者 SHA。由于 MD5 在实际应用中存在冲突的可能性比较大,所以尽量别采用 MD5 来验证内容一致性。SHA 也不能使用 SHA0 和 SHA1,中国山东大学的王小云教授在 2005 年就宣布破解了 SHA-1 完整版算法。
微软和 google 都已经宣布 16 年及 17 年之后不再支持 sha1 签名证书。

身份认证

身份认证主要涉及到 PKI 和数字证书。数字证书有两个作用:

1 身份授权。确保浏览器访问的网站是经过 CA 验证的可信任的网站。
2 分发公钥。每个数字证书都包含了注册者生成的公钥。在 SSL 握手时会通过 certificate 消息传输给客户端。

数字证书是如何验证网站身份的

1 证书申请者首先会生成一对密钥,包含公钥和密钥,然后把公钥及域名还有 CU 等资料制作成 CSR 格式的请求发送给 RA,RA 验证完这些内容之后(RA 会请独立的第三方机构和律师团队确认申请者的身份)再将 CSR 发送给 CA,CA 然后制作 X.509 格式的证书。

2 申请者拿到 CA 的证书并部署在网站服务器端,那浏览器发起握手接收到证书后,如何确认这个证书就是 CA 签发的呢?怎样避免第三方伪造这个证书?
答案就是数字签名(digital signature)。数字签名可以认为是一个证书的防伪标签,目前使用最广泛的 SHA-RSA 数字签名的制作和验证过程如下:

3 数字签名的签发。首先是使用哈希函数对证书数据哈希,生成消息摘要,然后使用 CA 自己的私钥对证书内容和消息摘要进行加密。
4 数字签名的校验。使用 CA 的公钥解密签名,然后使用相同的签名函数对证书内容进行签名并和服务端的数字签名里的签名内容进行比较,如果相同就认为校验成功。

这里有几点需要说明:

1 数字签名签发和校验使用的密钥对是 CA 自己的公私密钥,跟证书申请者提交的公钥没有关系。
2 数字签名的签发过程跟公钥加密的过程刚好相反,即是用私钥加密,公钥解密。
3 现在大的 CA 都会有证书链,证书链的好处一是安全,保持根 CA 的私钥离线使用。第二个好处是方便部署和撤销,即如何证书出现问题,只需要撤销相应级别的证书,根证书依然安全。
4 根 CA 证书都是自签名,即用自己的公钥和私钥完成了签名的制作和验证。而证书链上的证书签名都是使用上一级证书的密钥对完成签名和验证的。
5 怎样获取根 CA 和多级 CA 的密钥对?它们是否可信?当然可信,因为这些厂商跟浏览器和操作系统都有合作,它们的公钥都默认装到了浏览器或者操作系统环境里。比如 firefox 就自己维护了一个可信任的 CA 列表,而 chrome 和 IE 使用的是操作系统的 CA 列表。

HTTPS 使用成本

HTTPS 目前唯一的问题就是它还没有得到大规模应用,受到的关注和研究都比较少。至于使用成本和额外开销,完全不用太过担心。
一般来讲,使用 HTTPS 前大家可能会非常关注如下问题:

证书费用以及更新维护。

大家觉得申请证书很麻烦,证书也很贵,可是证书其实一点都不贵,便宜的一年几十块钱,最多也就几百。而且现在也有了免费的证书机构,比如著名的 mozilla 发起的免费证书项目:let’s encrypt就支持免费证书安装和自动更新。这个项目将于今年中旬投入正式使用。 数字证书的费用其实也不高,对于中小网站可以使用便宜甚至免费的数字证书服务(可能存在安全隐患),像著名的 verisign 公司的证书一般也就几千到几万块一年不等。当然如果公司对证书的需求比较大,定制性要求高,可以建立自己的 CA 站点,比如 google,能够随意签发 google 相关证书。

HTTPS 降低用户访问速度。

HTTPS 对速度会有一定程度的降低,但是只要经过合理优化和部署,HTTPS 对速度的影响完全可以接受。在很多场景下,HTTPS 速度完全不逊于 HTTP,如果使用 SPDY,HTTPS 的速度甚至还要比 HTTP 快。 大家现在使用百度 HTTPS 安全搜索,有感觉到慢吗?

HTTPS 消耗 CPU 资源

需要增加大量机器。前面介绍过非对称密钥交换,这是消耗 CPU 计算资源的大户,此外,对称加解密,也需要 CPU 的计算。 同样地,只要合理优化,HTTPS 的机器成本也不会明显增加。对于中小网站,完全不需要增加机器也能满足性能需求。

服务器配置

只介绍主流的nginx相关配置,下面是我服务器的相关配置,不一定最优,只是说明下配置方法。

    ssl on;

    #这里配置证书链
    ssl_certificate   /usr/local/nginx/conf/cert/izhong.me.fullchain.pem;
    
    #证书私钥
    ssl_certificate_key  /usr/local/nginx/conf/cert/izhong.me.privatekey.pem;

    #会话保持时间
    ssl_session_timeout 5m;

    #配置加密套件,这里配置的是服务器选择加密套件的顺序,nginx使用openssl库的加密套件,
可以通过openssl ciphers -v查询,我查询了一下我的服务器上面有95个,当客户端接入服务器开
始tls握手的时候,服务器从客户端支持的列表中(client hello中上送)和下面配置的列表中选择
前面一个,所以这里需要把你期望使用的加密套件配置在最前面,不期望使用的用!排除掉。
    ssl_ciphers ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4:HIGH:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!AESGCM;

    #支持的sll版本
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
	ssl_session_cache shared:SSL:10m;

    #服务器配置的加密套件优先
    ssl_prefer_server_ciphers on;

在线安全检查

自己的服务器配置是否安全,怎么判断呢? 最近一个在线检查的网站 点击前往

参考链接

https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc785811(v=ws.10)
https://kamranahmed.info/blog/2016/08/13/http-in-depth/
https://tools.ietf.org/html/rfc2616
https://en.wikipedia.org/wiki/Transport_Layer_Security#History_and_development
https://en.wikipedia.org/wiki/Transport_Layer_Security#TLS_handshake
https://blog.csdn.net/mrpre/article/details/77868669
https://developer.baidu.com/resources/online/doc/security/https-pratice-1.html