TCP数据段格式说明
TCP创建链接和断开链接细节
Https如何保证通讯安全
一次Https网络请求通讯细节
网络数据包分析工具wireshark的使用
问题:
SYN、ACK、FIN具体含义是什么?
TCP创建链接超时的表现?html
为何须要证书来下发服务端公钥?
客户端是如何验证证书合法性的?
对称秘钥是如何协商出来的?
为何不直接让客户端本身生成一个秘钥发送给服务端使用?
TLS如何避免重放攻击?git
TCP数据包格式说明
TCP数据段分为首部+数据两部分。
首部又分为固定首部和可选项首部。
经过对TCP数据包格式的分析,就是了解TCP协议定义的过程。算法
来源链接端口(16比特位)-辨识发送链接端口
目的链接端口(16比特位)-辨识接收链接端口
序列号(seq,32比特位)-TCP数据包标识。
无惧传输时的乱序或丢包
创建链接时发送和接收方第一次数据段的seq均为随机生成(TCP序号预测攻击),以后是上次序列号加1
发送数据时seq为上一次发送的数据长度加1,若是数据长度为0则seq不变
确认号(ack,32比特位)-表示接收方指望下次收到的数据包的序列号的值,也是当前收到的数据的字节长度加1
数据偏移(4比特位)-以4字节为单位计算出的数据段开始地址的偏移值,例1111 -> 15 -> 60字节
保留位(3比特位)-需置为0
标志符(9比特位)
NS:Nonce Sum 随机和,
CWR:Congestion Window Reduced 拥塞窗口减小标志被发送主机设置,用来代表它接收到了设置ECE标志的TCP包。拥塞窗口是被TCP维护的一个内部变量,用来管理发送窗口大小
ECE:ECN-Echo(显式拥塞通知回显) ECN响应标志被用来在TCP3次握手时代表一个TCP端是具有ECN功能的,而且代表接收到的TCP包的IP头部的ECN被设置为11 NS/CWR/ECE三个标志组合实现估计网络拥塞状况的功能
URG:为1表示高优先级数据包,紧急指针字段有效
ACK:为1表示确认号字段有效
PSH:为1表示是带有PUSH标志的数据,指示接收方应该尽快将这个报文段交给应用层而不用等待缓冲区装满
RST:为1表示出现严重差错,可能须要从新建立TCP链接,还能够用于拒绝分发的报文段和拒绝链接请求
SYN:为1表示这是链接请求或是链接接受请求,用于建立链接和使顺序号同步
FIN:为1表示发送方没有数据要传输了,要求释放链接
窗口(WIN 16比特位)-表示从确认号开始,本报文的接收方能够接收的字节数,即接收窗口大小,用于流量控制
校验和(Checksum 16比特位) -对整个TCP报文段,包括TCP首部和TCP数据,计算出来的16位值,这是一个强制字段。校验方式为:将TCP报文段的头部和数据部分的和计算出来,再对其求反码
紧急指针(16比特位)-本报文段中的紧急数据的最后一个字节的序号
选项字段 -最多40字节,每一个选项的开始是1字节的kind字段,说明选项的类型。下面具体说明支持的选项字段类型
0:(1字节)选项表结束
1:无操做(1字节)用于选项字段之间的字节边界对齐和分割不一样的选项数据
2:最大报文长度(4字节,Maximum segment size,MSS) -在握手阶段告知接收方,发送方支持的最大报文数据段的长度,以太网通常为1460。只能出如今同步报文段中,不然将被忽略。一般将MSS设置为MTU-40字节(Maximum Transmission Unit 最大传输单元),这样携带TCP报文段的IP数据报的长度就不会超过MTU,从而避免本机发生IP分片。
3:窗口扩大因子(3字节,wscale)-取值0-14,用来把TCP的窗口的值左移的位数。只能出如今同步报文中,不然将被忽略。这是由于如今的TCP接收数据缓冲区(接收窗口)的长度一般大于65535字节
4:sackOK -发送端支持并赞成使用SACK(Selective Acknowledgements,选择确认)选项
5:SACK实际工做的选项,存放丢包的边界信息,最多存放4个包的边界信息。例如123,丢了2,那么SACK存放的就是2号包的开始和结束的字节序列号
8:时间戳(10字节,TCP Timestamps Option,TSopt)
发送端的时间戳(Timestamp Value field, TSval,4字节)
时间戳回显应答(Timestamp Echo Reply field,TSecr,4字节)
时间戳的功能有两个:
用来计算往返时间RTT(Round-Trip Time),发送方在收到确认报文后,能够准确计算出RTT。
防止回绕的序列号,经过时间戳能够判断出相同序列号的数据报,哪一个是最近发送的,哪一个是之前发送的。
滑动窗口
简单一句话就是接收方能够动态控制发送方下次发送的TCP包数据段的大小。
当接收方处理数据较慢时,就能够经过WIN字段,在ACK包中告知发送方:“之后的数据段少发一些,我处理不过来了。”
在极端状况下,接收方连1字节的数据也不能处理了,那么WIN字段就设置为0,发送方就会中止发送后续的TCP包。
那么,当接收方缓过气来,能够处理更多数据时,发送方是怎么知道的呢?答案是Zero Window Probe(零窗口探针)技术。
发送方会在必定时间间隔内重复发送ZWP包,这时接收方就有机会告知发送方最新的窗口大小。
又有极端状况,接收方一直返回WIN为0,那么发送方在发送必定次数的ZWP后,就会发送RST包来断开链接(不一样的系统有不一样的实现)。浏览器
另一种极端状况,接收方返回的WIN值特别小,相对于TCP的首部来讲,发送较少的数据时一种浪费。这个时候接收方就会使用David D Clark’s 方案。接收方直接返回WIN为0,知道接收方有足够的能力处理新数据时再把WIN打开。缓存
若是是因为发送方发送的数据特别少引发的,那么发送方就会使用Nagle’s algorithm。将多个小的数据包缓存起来,直到知足发送条件。安全
ECE和CWR
当两个支持ECN的TCP端进行TCP链接时,对于支持ECN的TCP端来讲,SYN包的ECE和CWR标志都被设置了。SYN-ACK只设置ECE标志。bash
一个支持ECN的TCP主机在支持ECN的TCP链接上发送设置了IP头部为10或者01的TCP包。支持ECN的路由器在经历拥塞时设置IP头部的ECN域为11。当一个TCP接收端发送针对收到的一个设置ECN位为11的TCP包的响应时,它设置TCP包头中的ECE,而且在接下来的ACK中也作一样设置。服务器
当发送主机接收到设置了ECE标志的ACK时,它就像感知到包丢失同样,开始减小发送窗口,运行慢启动过程和拥塞避免算法。在下一个数据包中,发送者设置CWR标志。在接收到新的设置CWR标志的包时,接受者中止在接下来的ACK中设置ECE标志。网络
超时重传
创建链接时:app
若是发送方在发送一个SYN包后,在超时时间内没有收到确认包,则发送方会从新发送,称为超时重发。
默认Linux重试次数为5次,重试时间间隔由1s开始每次翻倍,即1s,2s,4s,8s,16s。若是通过1+2+4+8+16+32=63s后,仍没有收到确认包,则发送方认为接收方已掉线,会主动断开当前链接。
数据传输时:
为了网络总体的稳定,须要动态的根据往返时间设置数据包的超时时间。这里就不展开说具体算法过程了。
RTO(Retransmission Timeout)重传超时时间
RTT(Round-Trip Time)往返时间
拥塞控制
慢启动
拥塞避免
快速重传
快速恢复
三次握手 和 四次挥手
三次握手
这是简单的三次握手流程示意图,三次握手意思是须要在发送方和接收方之间传递三个数据包。经过设置不一样的标识位,来告知对方当前数据包的意图。
第一次:C发送一个数据包P1给S,并将标识位的SYN置为1,代表“我要和你创建链接”。
第二次:S若是能够接受C的请求,会给C回发一个数据包P2,并将标识位SYN置为1,代表“我赞成和你创建链接”。同时将ACK位置为1,代表“确认号ack”字段有效,其值为P1数据包序列号+1。
第三次:C接到P2后,会再次向S发送数据包P3,将ACK为置为1,其值为P2数据包的序列号+1,代表“我知道了你赞成了”。
至此,链接就被创建完成了,双方就能够任意发送数据了。
可是,在三次握手过程当中,除了要协商链接的创建,还有其余通信参数的设置。下面以一个真实请求在三次握手过程当中发生的数据交换做说明:
第一次:
第二次:
第三次:
这是TCP链接断开时四次挥手的示意图。划重点:
每一侧的链接都单独的被终止。
主动终止链接的一方在接收到ACK后,不能再发送数据,但能够接收数据,也就是半双工状态。
首先终止链接的一方,在给对方响应了ACK后,就会等待2*MSL(Max Segment Lifetime 报文最大生存时间)时间,而后关闭链接。RFC793定义了MSL为2分钟,Linux设置成了30s。
四次挥手也能够经过三次握手实现,即主机A发出FIN,主机B回复FIN&ACK,主机A回复ACK。
下面是三次握手实现的链接断开的报文传输细节:
第一次:
第二次:
第三次:
Https如何保证通讯安全
简介
Https 超文本传输安全协议(Hypertext Transfer Protocol Secure),1994年由网景公司提出,Https经由Http进行通讯,但利用SSL/TLS来加密数据,即在Http协议与TCP协议之间添加SSL/TLS层。
安全防御:
身份认证,防止中间人攻击
消息加密,防止被窃听
消息校验,防止被篡改
安全前提:
系统或浏览器正确的实现了Https并安装了正确的证书颁发机构
安全通讯流程
对称加密
算法公开(AES)
一个秘钥,秘钥不公开
加解密速度快
非对称加密
算法公开(RSA)
两个秘钥,公钥公开,私钥不公开
公钥加密的数据,私钥能够解密。私钥加密的数据,公钥能够解密
加解密速度慢
非对称加密算法除了能够直接将隐私数据加密外,还能够实现对非隐私数据的防篡改校验功能,也就是数字签名。
Hash/散列/摘要算法
以任意长度的数据为输入,输出固定长度的数字“指纹”。
MAC,消息认证码,是带秘钥的Hash算法,即在对数据计算散列值时将秘钥和数据同时做为输入,并采用二次散列迭代的方式。
Alice和Bob
在没有SSL/TLS的世界里,Alice和Bob的通信是这样的。
Alice(i love you)–明文(i love you)–>Bob(i love you)
一些坏人能够在明文的传输过程当中,对数据进行更改。
Alice(i love you)–>坏人(i hate you)–>Bob(i hate you)
Bob(i still love you )–>坏人(i hate you too)–>Alice(i hate you too)
当两人见面后,发现对方误会了本身,就想到这个世界仍是有坏人,而后双方约定将通讯内容加密后再发送给对方。约定的加密算法为AES,秘钥为“Alice/Bob”。
加密后就会出现两种状况:
Alice(i love you)–加密(123abc)–>坏人(123abc)–>Bob(123abc)–>解密(i love you)
Alice(i love you)–加密(123abc)–>坏人(!!!)–>Bob(!!!)–>解密(???)
单纯使用对称加密会有两个问题:
坏人虽然不能窃听内容,可是仍能篡改。
对称加密的秘钥只能Alice和Bob两我的知道,若是想再和更多的人加密通讯的话,就无能为力了。
Alice和Bob必须在通讯以前就约定好秘钥(在互联网世界中办不到),中途没法更新。
因此,咱们要解决这些问题,须要作到:
为了过滤掉被篡改的数据,通讯过程须要有内容校验机制
为了能够和无限多人通讯,须要能动态生成和更新秘钥
Alice和Bob很是聪明,他们想到了非对称加密算法RSA,Bob拿着私钥,而后把公钥给Alice,当Alice想要和Bob通讯时,利用手中的公钥将对称加密算法的秘钥加密后发送给Bob,Bob拿着本身的私钥将对称加密的秘钥解密后,双方就能够继续用对称加密算法将数据加密后通讯了。固然,其余人也能够拿到Bob的公钥,与Bob通讯。
Alice(我想和你说话,给我公钥)------->Bob(我想和你说话,给我公钥)
Bob(给你公钥(Pubkey)) --------->Alice(拿到公钥PubKey)
Alice(秘钥:123)–>公钥PubKey加密(321)–>Bob(321)–>私钥解密(123)
Alice(i love you)–>秘钥123加密(123abc+摘要签名)---->Bob(123abc+摘要签名)–>正确性验证–>秘钥123解密(i love you)
上述第二个过程是无懈可击的,可是第一个过程当中,若是存在坏人的话,就变成下面的情形
Bob(给你公钥(PubKey))---->坏人(PubKey换成本身的PubKey1)--------->Alice(拿到公钥PubKey1)
Alice(秘钥:123)–>公钥PubKey1加密(abc)–>坏人(abc),本身的私钥解密123,再用PubKey加密321–>Bob(321)–>私钥解密(123)
完犊子了,对称加密的秘钥被坏人窃取了,通讯数据又至关于裸奔了。其中核心问题就是:
接收方没法肯定公钥的合法性
那若是把公钥事先告知Alice能够么?也就是内置在系统中。理论上是没问题的,但当Alice须要和更多的人通讯时,她须要记住不少不少的公钥,这是不可行的。
因此Alice和Bob须要商量出一套方案,能保证公钥在网络上安全的传输,若是受到篡改,接收方能感知到。这时,他们想到数字签名的方式。
Bob(给你公钥+签名(摘要的私钥加密))------>Alice(公钥+签名,对签名解密,并再次计算摘要,而后比对)
上述方式能够作到防篡改么?能够,可是作不到防替换。中间人能够把签名连同公钥所有换成本身的。
接下来就到了数字签名证书出场的时刻了。
Bob找到了一个很是权威的机构,“人民政府”。
Bob向“人民政府”证实“我是真Bob”,并提供本身的公钥。
“人民政府”根据Bob的信息和公钥颁发给Bob一个证书文件.cer,里面写了颁发机构的信息、Bob的信息和公钥、摘要算法以及最重要的颁发机构的签名。
公钥下发过程变成了数字证书下发过程。
同时,Alice也是很是相信“人民政府”的,只要是“人民政府”签名的证书,Alice就认为证书上面的公钥就是Bob的。
可是,Alice并不能无脑的相信,她须要判断了两点:
接收到的证书是不是”人民政府“签发的。
证书上面的信息是否被篡改。
那么具体的判断流程是怎样的呢?
因为Alice信任”人民政府“这个机构,因此Alice能够内置一份”人民政府“自签名的证书,上面有”人民政府“生成的公私钥中的公钥,私钥由”人民政府“本身保管。
在下发证书过程当中,Alice拿到Bob发过来的由”人民政府“私钥签名过得证书cert0。
Alice首先根据cert0上的证书颁发机构信息判断本身是否信任这个机构颁发的证书,cert0是由”人民政府“签发的,而Alice是信任”人民政府“的,因此Alice信任cert0。
Alice经过查找内置的”人民政府“的自签名证书拿到”人民政府“的公钥
用此公钥验证cert0上的信息是否被篡改
问题:Bob的公钥不是由”人民政府“签发的,而是由其下属的”地方政府“签发的。而Alice只有”人民政府“的自签名政府,如何判断证书合法性呢?
答:在证书下发过程当中,实际是下发的一个证书链,相似于”Bob的证书“–>“地方政府的证书”–>”人民政府的证书“,Alice能够逐级查找,直到根证书。
证书内容
Https证书格式遵循的是X.509标准。X.509是ITU-T标准化部门基于他们以前的ASN.1定义的一套证书标准。
在浏览器中随便下载一个证书,经过如下命令获取到其文本格式。
openssl x509 -in *.xxx.com.cer -inform der -text -noout >> cer.txt
Certificate: Data: Version: 3 (0x2) Serial Number: 09:3e:8a:aa:5a:f8:14:de:9d:d9:4d:28:2e:97:a8:16 Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=GeoTrust RSA CA 2018 //颁发者信息 Validity Not Before: Aug 22 00:00:00 2018 GMT Not After : Nov 12 12:00:00 2020 GMT Subject: C=CN, ST=\xE5\x8C\x97\xE4\xBA\xAC, L=\xE5\x8C\x97\xE4\xBA\xAC, O=Beijing Qfpay Technology Co., ltd., CN=*.qfpay.com //公钥主题信息,公钥全部者的信息 Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:e6:c0:8b:f0:12:1e:f0:92:9c:17:7d:7e:d5:69: 47:fc:dd:0b:51:5a:0e:79:df:b1:0e:b4:d6:7d:d0: 5a:bc:f9:93:f6:3c:e3:40:a8:66:9f:d0:ae:3c:e1: f8:9a:55:a2:84:0e:9c:1d:65:f9:d2:63:51:48:b2: 88:a5:09:a6:be:92:80:f8:3b:eb:b8:78:1b:35:58: 47:ac:eb:47:cd:3d:7f:36:74:30:7a:01:86:48:96: b3:7b:14:82:b6:63:0b:b6:43:20:98:3f:07:9d:1a: 56:76:25:cf:cd:d5:49:fd:6e:dc:86:f0:7f:15:f3: 7d:58:98:75:a5:7f:f9:ab:b2:c4:ec:fc:30:bd:75: 27:b3:0e:72:3d:44:d1:04:42:52:65:9b:3e:53:9b: a5:c2:eb:ac:c5:01:b6:1d:0d:2f:75:79:7d:98:d4: 2b:b6:c0:28:ea:c7:dc:14:04:b6:4d:a3:dc:01:2c: f0:14:13:b9:d2:29:31:00:37:af:17:d6:82:a6:f9: 57:9e:4c:2f:27:27:08:50:16:e3:ca:fa:58:32:c7: f5:04:43:b4:5d:0e:97:81:e9:c3:01:36:f9:b7:c8: 14:ec:98:27:e9:31:86:ab:f5:c4:ff:50:aa:c4:df: cc:6e:7d:1c:5a:fa:b8:47:c9:fa:78:b4:de:6d:15: 8d:27 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Authority Key Identifier: //受权秘钥标识符 keyid:90:58:FF:B0:9C:75:A8:51:54:77:B1:ED:F2:A3:43:16:38:9E:6C:C5 X509v3 Subject Key Identifier: //主题秘钥标识符 EC:99:74:D5:FF:C6:1B:4F:FB:39:88:8C:E2:C1:7B:8D:90:59:AB:1F X509v3 Subject Alternative Name: DNS:*.xxx.com, DNS:xxx.com X509v3 Key Usage: critical Digital Signature, Key Encipherment X509v3 Extended Key Usage: TLS Web Server Authentication, TLS Web Client Authentication X509v3 CRL Distribution Points: Full Name: URI:http://cdp1.digicert.com/GeoTrustRSACA2018.crl X509v3 Certificate Policies: Policy: 2.16.840.1.114412.1.1 CPS: https://www.digicert.com/CPS Policy: 2.23.140.1.2.2 Authority Information Access: OCSP - URI:http://ocsp1.digicert.com CA Issuers - URI:http://cacerts.geotrust.com/GeoTrustRSACA2018.crt Signature Algorithm: sha256WithRSAEncryption 07:8d:b9:34:62:e8:4b:83:00:af:ab:38:d4:b1:24:12:a4:37: 5e:8f:e7:ff:d9:96:48:ae:72:6f:d2:0b:41:6a:55:92:2a:06: 39:86:a9:78:18:cd:0d:5f:33:fa:22:81:50:b7:67:2f:dc:a1: b4:ee:0f:6c:f8:73:87:0d:65:e7:19:9a:55:07:49:a4:2d:09: 11:8b:5f:1c:c1:46:ce:94:22:fa:b0:1b:88:f0:f0:6f:63:11: e4:56:f4:51:3c:12:90:db:44:63:8b:fd:17:d2:e5:7a:66:5e: f5:d8:90:70:5c:d6:c2:74:d9:74:b3:75:ce:83:e3:db:57:bb: b6:3a:81:e7:ca:7a:48:82:6c:0b:01:a8:ed:a2:8e:d0:b0:ed: 25:15:a2:2a:7f:6f:a5:6d:da:5a:ac:91:f4:dc:23:d8:9f:9d: d3:0a:f4:c7:8f:b0:c2:18:54:97:f5:00:30:36:65:e1:aa:25: 9c:f1:b8:77:d6:7d:33:79:39:0e:41:86:1d:79:47:0e:34:cc: fd:e8:63:83:9d:f5:86:d6:e2:0c:fa:58:d5:d2:81:c1:92:da: e7:41:45:bc:a0:91:d5:40:6e:c8:22:76:69:e4:67:9a:d4:03: ca:8d:28:d5:ca:98:09:e0:d6:dd:ae:c2:6f:08:82:1b:89:79: 14:d6:ca:b7
SSL协议属于分层协议,一个SSL报文能够包含多个记录层,每一个记录层分为两部分:头部 + 协议数据。
Content Type:协议类型
Version:TLS版本
Length:报文长度
协议数据,不一样的协议包含数据字段不一样
报文支持的协议类型
Handshake Protocol
握手协议是最主要的协议,负责协商会话的安全属性。按照不一样的功能区分为不一样握手类型。
1 enum { 2 hello_request(0), client_hello(1), server_hello(2), 3 certificate(11), server_key_exchange (12), 4 certificate_request(13), server_hello_done(14), 5 certificate_verify(15), client_key_exchange(16), 6 finished(20), (255) 7 } HandshakeType; 8 9 struct { 10 HandshakeType msg_type; /* handshake type */ 11 uint24 length; /* bytes in message */ 12 select (HandshakeType) { 13 case hello_request: HelloRequest; 14 case client_hello: ClientHello; 15 case server_hello: ServerHello; 16 case certificate: Certificate; 17 case server_key_exchange: ServerKeyExchange; 18 case certificate_request: CertificateRequest; 19 case server_hello_done: ServerHelloDone; 20 case certificate_verify: CertificateVerify; 21 case client_key_exchange: ClientKeyExchange; 22 case finished: Finished; 23 } body; 24 } Handshake;
每种握手协议类型,也都包含一些通用字段,如
HandshakeType
Version
Length
下面具体说明每种握手类型的做用:
Hello Request
”你好,请求“,该类型的握手协议做为一个简单的通知,由服务端发送,告知客户端从新开始协商过程。做为响应,客户端应该在方便时发送ClientHello消息。
若是客户端不但愿从新协商会话,能够选择忽略此消息,或者返回一个no_renegotitation消息。
若是服务端发送HelloRequest后没有收到ClientHello做为响应,它可能会经过致命警报关闭链接。
Client Hello
”你好,我是客户端“,该类型的消息用于首次链接服务器时,或响应服务端发送的HelloRequest,或主动发送,以便从新协商链接中的安全参数。
Random 由安全随机数生成器生成的28字节随机数,用于对称秘钥计算
Session ID 会话标识,可变长,用于会话恢复时重用其安全参数
Cipher Suites 加密算法套件,客户端提供支持的密码算法套件列表,按照客户端的偏好顺序排列,通常由四个算法组成,格式为秘钥交换算法+身份认证算法+批量加密算法+摘要算法
例:Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)
ECDHE 秘钥交换算法,因为对称秘钥并非客户端直接生成发送给服务端的,而是双方又各自生成了一对"公私钥",而后互相交换“公钥”,这里生成“公私钥”的算法就是ECDHE
ECDSA 身份认证算法,用于加密握手消息,确认未被篡改
AES_256_GCM 批量加密算法,用于应用数据加密,它还包括秘钥大小及显示和隐式初始化向量的长度
SHA384 散列算法,用于计算主秘钥和建立会话消息摘要
Compression Methods 压缩算法列表
这四个属于固定字段,若是还须要协商其余内容,能够经过下面的扩展字段。
renegotiation_info 从新协商信息,
signature_algorithms 签名算法,列出客户端支持的哈希和签名算法,用于后续消息签名时的参考。
server_name 服务器域名,用于解决一台机器部署多个不一样域名的站点,而引发证书冲突的状况。
aplication_layer_negotiation 用来肯定后续的应用层协议,例http/1.1 spdy h2
…
Server Hello
”你好,我是服务端“,该类型的消息用于响应ClientHello消息。若是服务器找到一组能够接受的算法套件时,则回复此消息,不然响应握手失败的警报。
Random 由服务端独立生成的随机数,28字节,用于对称秘钥的计算。
Session ID 当前的会话标识,若是ClientHello的参数SessionID不为空,则服务器将在其会话告诉缓存中查找匹配项,找到而且愿意是定指定的会话状态创建链接,则服务器使用与客户端提供的SessionID做为响应,而后恢复会话并进入Finished消息流程。不然将从新生成该值以标识新会话。若是SessionID为空代表服务端不缓存此会话,没法恢复。
Cipher Suite 服务端从ClientHello.cipher_suites列表中选择的单个密码套件。若是是恢复会话,此字段为正在恢复的会话状态的值。
例:Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
ECDHE 椭圆曲线离散对数算法
RSA 非对称加密算法
AES_256_GCM 高级加密算法,对称加密,32字节的秘钥 GCM为加密模式
SHA384 安全散列算法
Compress Method 服务端从ClientHello.CompressionMethods列表中选择的压缩算法
Server Hello消息也能够包含扩展,可是这些扩展必须在ClientHello中有相同的扩展类型,服务端不能擅自添加。若是客户端在ServerHello中收到它未在ClientHello请求中关联的扩展类型,客户端必须使用unsupported_extension致命警告来终止握手。
Certificate
”服务器证书“,只要商定的秘钥交换方法使用证书进行身份验证,则服务端必须发送该证书消息。该消息紧跟在Server Hello消息后,用于向客户端下发证书。
何时服务端不须要下发证书呢?就是在秘钥协商过程当中使用DH_anon(Diffie-Hellman ANON)匿名Diffie-Hellman算法,即不配合其余身份验证算法,而单独只读使用DH算法,这样没法保证数据被”篡改“。
Certificates 证书链,服务端的证书必须放在第一位,之后的证书必须直接证实其前面的证书。
证书限制
证书类型必须是X.509v3,除非另行协商。
证书必须适用于协商密码套件的秘钥交换算法和任何协商扩展。
若是客户端提供了”signature_algorithms“扩展,那么服务端提供的全部证书必须由该扩展中出现的散列/签名算法进行签名。
Server Key Exchange
”服务器秘钥交换“,用于发送服务端的预主秘钥。此消息在Certificates消息后当即发送。
当且仅当与秘钥交换算法相关联的证书类型不能为客户端提供足够的信息来交换预主秘钥时,才会发送服务器秘钥交换信息。
该消息主要描述了使用协商的秘钥交换算法后,服务端计算出来的公开秘钥。
本示例中使用的是ECDHE算法。其原理简单理解以下所示:
服务端生成随机整数a,做为私钥
计算出A = f1(a),其中a为私钥,A为公钥,并将A发送给客户端
客户端重复相同的步骤,先生成随机整数b,计算 B = f1(b),并将B发送给服务端
客户端持有A和b,服务端持有a和B
服务端和客户端计算出相同的预主秘钥 K = f2(a, B) = f2(b, A)
以后再根据预主秘钥和两个随机数计算出主秘钥
上述计算过程由ECDHE提供
服务端为了证实此消息是真实可靠的,须要用本身证书私钥和ClientHello提供的扩展signature_algorithms里选择合适摘要和签名算法对参数进行签名。
Certificate Request 可选
”要求证书“,若是服务端须要客户端提供证书以验证客户端身份,则使用此消息。消息格式与服务端下发给客户端的证书消息格式相同。
Server Hello Done
“服务器Hello完成”,表示服务端已经把支持秘钥交换的消息发送完成。发送此消息后,服务端等待客户端响应。客户端应该检查服务器是否提供了有效的证书(若是须要),并检查服务端Hello消息参数是否可接受。
Client Certificate
“客户端证书”,用于将客户端证书发送给服务端。
这是客户端在收到ServerHelloDone消息后能够发送的第一条消息。仅当服务器请求证书时才会发送此消息。若是没有合适的证书,客户端必须发送不包含证书的证书消息。也就是说,certificate_list结构的长度为零。若是客户端没有发送任何证书,服务器能够自行决定是否在没有客户端身份验证的状况下继续握手,或者使用致命的handshake_failure警报进行响应。此外,若是证书链的某些方面是不可接受的(例如,它没有由已知的,可信的CA签名),服务器能够自行决定是继续握手(考虑客户端未经身份验证)仍是发送致命警报。
Client Key Exchange
“客户端秘钥交换”,用于发送客户端计算的预主秘钥。该消息是在客户端收到ServerHelloDone消息后发送的第一条消息。或者是跟在Client Certificate消息后发送。
这个消息内容比较简单,就是用服务端证书公钥加密的预主秘钥。
Certificate Verify
“证书验证”,此消息用于客户端证书的显示验证。发送这个消息的前提有两个:
服务端请求了客户端证书
客户端发送了非0长的证书
此时,客户端须要证实本身拥有该证书,须要用本身的私钥签名一段数据发送给服务端作验证。
签名的数据为:此消息以前的全部接收和发送过的握手消息。
Finished
“协商完成”,此消息是第一个使用上述握手过程当中协商的算法和秘钥来加密的消息。接收方必须验证内容是否正确。
该消息在Change Cipher Spec消息以后被发送,以验证密钥交换和身份验证过程是否成功。
发送的数据为:PRF(master_secret, finished_label, Hash(handshake_messages))
finished_label为“client finished”/“server finished”
handshake_messages包含除去Hello Request消息以外的以前全部发送和接收的握手消息。
Change Cipher Spec Protocol
更改密码规范协议,该协议在TSL1.3被移除。
Change Cipher Spec
“变动秘钥规范”,用于通知接收方后续的通信数据将在新协商的秘钥规范保护下交换。
此消息在Finished消息以前被发送。
客户端在交换预主秘钥后,就当即发送了“Change Cipher Spec”消息。
以后,服务端也发送一个“Change Cipher Spec”消息。
应用数据协议
若是握手过程结束一切正常,Alice和Bob就用这条加密信道放心的发送数据了,这些数据都是被加密过的。
http-over-tls
Alert Protocol
警报消息传达消息的严重性(警告或致命)以及警报的描述。 具备致命级别的警报消息致使链接当即终止。在这种状况下,对应于会话的其余链接能够继续,可是会话标识符必须无效,防止失败的会话被用于创建新链接。与其余消息同样,警报消息按当前链接状态的指定进行加密和压缩。
警报协议包含不少异常场景,如证书过时、没有符合密码套件、未知的ca等,这里就不一一列出了。
TLS握手简化流程图
Client Server
ClientHello ----------->
ServerHello
Certificate*
ServerKeyExchange*
CertificateRequest*
<----------- ServerHelloDone
Certificate*
ClientKeyExchange
CertificateVerify*
[ChangeCipherSpec]
Finished ----------->
[ChangeCipherSpec]
<----------- Finished
Application Data <-----------> ApplicationData
中括号号标识的协议不属于握手协议
星号标识的不是必须的握手流程
至此TLS握手过程说完了,但貌似没有说到**对称秘钥(会话秘钥)**是如何被计算出来的?
咱们知道,经过前面的握手流程,客户端和服务端都知道了如下信息:
预主秘钥(计算出来的)
客户端随机数
服务端随机数
经过这三个参数,客户端和服务端就能够分别计算出主秘钥:
master_secret = PRF(pre_master_secret, "master secret", ClientHello.random + ServerHello.random)
master_secret 长度为48个字节。Master secret是有系列的hash值组成的
PRF (pseudo random function)伪随机函数,也就是选择的加密套件中的第四个算法SHA384。计算完主秘钥,就应当把预主秘钥从内存中删除。
PRF算法须要一个“秘钥”、一个“种子”和一个“文本标识”做为输入,而后产生一个不定长的输出。
其中的“秘钥”就是预主秘钥,“种子”就是两个随机数的和,“文本标识”就是 master secret。
由于客户端和服务端的输入参数都是同样的,因此计算出来的主秘钥也是一致的。
主秘钥是用来作对称加密的秘钥的么?
不是,须要由主秘钥再次计算,主秘钥在建立会话秘钥时做为一个熵来源。最终计算出来的结果以下:
客户端写入MAC密钥
服务器写入MAC密钥
客户端写入加密密钥
服务器写入加密密钥
客户端写入IV
服务端写入IV
其实是生成了两个会话秘钥:
MAC(Message Authentication Code),是一个数字签名,用来验证数据的完整性,能够检测到数据是否被串改。
当客户端向服务端发送消息时,使用“客户端写入MAC秘钥”生成消息摘要附加在消息结尾,使用“客户端写入秘钥”加密;服务端接收到消息后,使用“客户端写入秘钥”解密,使用“客户端写入MAC秘钥”作消息摘要并对比两次摘要结果。
反过来则是,服务端向客户端发送消息时,使用“服务端写入MAC秘钥”生成消息摘要附加在消息结尾,使用“服务端写入秘钥”加密;客户端接收到消息后,使用“服务端写入秘钥”解密,使用“服务端写入MAC秘钥”作消息摘要并对比两次摘要结果。
若是须要在TLS层压缩数据,则在加密以前先压缩。
一些AEAD(认证加密)秘钥套件可能额外须要一个客户端写入向量和服务端写入向量
那么这些值是怎么计算出来的呢?
key_block = PRF(master_secret,“key expansion”,server_random + client_random); = P_hash(master_secret, “key expansion"+server_random + client_random) P_hash定义为: P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + HMAC_hash(secret, A(2) + seed) + HMAC_hash(secret, A(3) + seed) + ... A(0) = seed; A(i) = HMAC_hash(secret, A(i-1)); ... HMAC: 基于消息认证码的哈希算法,也就是对消息进行哈希运算时添加一个秘钥。
以TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384为例,AES256会话加密算法须要32字节的会话秘钥,而咱们须要2个会话秘钥(2 * 32)和2个MAC秘钥(2 * 48),就是2 * 32 + 2 * 48= 160字节。而摘要算法SHA384每次的运算输出为48字节,为了能知足160个字节,至少须要计算4次,拼接后获得172字节的输出。
而后按照上述顺序:
0~47字节为“客户端写入MAC秘钥”
48~95字节为“服务器写入MAC秘钥”
96~127字节为“客户端写入加密秘钥”
128~159字节为“服务端写入加密秘钥”
剩下的12字节则舍弃。
总结:
握手过程当中,客户端和服务端交换了哪些东西?
两个随机数
DH算法的公钥
证书
握手过程当中,哪些消息是通过加密的?加密的目的是什么?
Server/Client Key Exchange 使用服务器私钥加密,防止中间人篡改
Finished 使用主秘钥加密并签名,验证主秘钥是否正确生成和握手消息是否被篡改
若是服务端的私钥泄漏,坏人可否解密会话数据?
RSA 能够
DH 不能够
PSK 不能够
参考:TLS握手协议分析与理解——某HTTPS请求流量包分析
解密应用数据方式:
启动Chrome并制定SSL的日志文件
sudo /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --ssl-key-log-file=/Users/joye/Downloads/sslkeylog.log
在WireShark中Preferences->Protocols->SSL-(Pre)-Master-Secret log filename设置日志文件