Wireshark 抓包理解 HTTPS 请求流程(2) - TLS/SSL 握手

本文目录:

创建 HTTP 代理(非必要)

这次请求,为了让 Wireshark 抓到手机的包,我使用了电脑作为代理。

其实就是客户端 A 使用 HTTP 协议和代理服务器 B 建立连接。和普通的 HTTP 请求一样,需要携带 IP + 端口号,如果有身份验证的时候还会带上授权信息,代理服务器 B 会使用授权信息进行验证。然后代理服务器会去连接远程主机,连接成功后返回 200。

Wireshark 抓到的包有这样两条信息,就是在创建代理:

No. Time Source Destionation Protocol Length Info
396 4.798832 172.17.32.211 172.17.32.19 HTTP 284 CONNECT nex.163.com:443 HTTP/1.1
401 4.816127 172.17.32.19 172.17.32.211 HTTP 105 HTTP/1.0 200 Connection established

请求报文:

CONNECT nex.163.com:443 HTTP/1.1
User-Agent: Mozilla/5.0 (Linux; Android 6.0.1; MI 5 Build/MXB48T; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/51.0.2704.81 Mobile Safari/537.36
Host: nex.163.com

响应报文:

HTTP/1.0 200 Connection established

HTTP CONNECT 是在 HTTP1.1 新增的命令,用于支撑 https 加密。

因为我采用代理的方式抓包才有这一个步骤。如果是直接抓 PC 机上浏览器发出的 HTTPS 包,不会有这个过程。

然后我们思考一下,为什么代理服务器需要这些信息,要连接的主机名和端口号?

这是因为后面进行 SSL 加密 HTTP协议,因为代理服务器拿不到加密密钥,是无法获取到 HTTP 首部的,进而无法这个请求是要发到哪个主机的。所以,这里先使用 CONNECT 方法,把主机名和对应的端口号通知代理服务器。

这个也被称为 HTTPS SSL 隧道协议。建立这个 SSL 隧道后,这个特殊代理就会对数据进行盲转发。

TLS/SSL 握手

TLS/SSL 协议内容

SSL 整个协议实际上分两层,SSL 记录协议和其他子协议(SSL握手协议,SSL改变密码协议,SSL警告协议):

SSL 协议

这两层协议的关系,其实就是数据封装的关系,SSL 握手封装协议封装其他上层协议。

封装握手协议:

Secure Sockets Layer
    TLSv1.2 Record Layer: Handshake Protocol: Client Hello
        Content Type: Handshake (22)
        Version: TLS 1.0 (0x0301)
        Length: 153
        Handshake Protocol: Client Hello

封装应用数据协议,比如 HTTP:

Secure Sockets Layer
    TLSv1.2 Record Layer: Application Data Protocol: http
        Content Type: Application Data (23)
        Version: TLS 1.2 (0x0303)
        Length: 1072
        Encrypted Application Data: 6d9b3c9089271630c33506fe28cd6a61fed1f4bd2808f537...

封装交换密码协议:

Secure Sockets Layer
    TLSv1.2 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec
        Content Type: Change Cipher Spec (20)
        Version: TLS 1.2 (0x0303)
        Length: 1
        Change Cipher Spec Message

封装警报协议:

Secure Sockets Layer
    TLSv1.2 Record Layer: Encrypted Alert
        Content Type: Alert (21)
        Version: TLS 1.2 (0x0303)
        Length: 48
        Alert Message: Encrypted Alert

所以 SSL 记录协议其实就是一个其他协议的载体,只是提供了一个封装的功能。它的格式为:

| 内容类型 | 主要版本 | 次要版本 | 长度 |
|          明文/加密/压缩 数据包       |
|          MAC(0, 16, 20)            |

MAC 就是消息验证码,用来验证数据的完整性,保证中途没有篡改。这个消息验证码比数字签名弱一些,使用的是对称密钥加密摘要。数字签名使用的是非对称密钥加密,有区分公钥私钥。

记录协议的主要目的有这几个,为其他 SSL 子协议提供了以下服务:

  • 分组、组合。如果有几个协议的内容,是可以不用等客户端确认后再发送的,这里会进行组合合并,然后在同一个 TCP 包中发送。接收方接收到组合的 SSL 记录协议报文,也会根据协议来进行分组。

  • 压缩、解压缩。可选项,如果需要压缩的话。

  • 消息认证(MAC)。注意,这里不提供数字签名。消息认证用的是用对称密钥,解密算法效率比公钥算法快,安全性弱一些。如果已经明确了,加密用的对称密钥只有合法的客户端和服务端获得,那么这个的安全效果和数字签名一样。

  • 加密传输 。比如已经协商好加密密钥和算法了,直接对应用层协议加密传输:

    Encrypted Application Data: 6d9b3c9089271630c33506fe28cd6a61fed1f4bd2808f537...

TCP 三次握手结束并且和代理服务器成功连接后,建联成功,客户端 A 就开始发起 SSL 连接,首先会进入 SSL 握手阶段。

SSL 握手阶段的主要目的有这么几个:

  • 协商加密算法。为了能够提供效率,使用对称密钥。对称加密使用的是位运算,速度快,甚至可以硬件加速。非对称加密比如 RSA,使用了大数乘法等,整体会比较慢。对称加密只要密钥没有泄漏,那也是非常安全的。这也是后面 SSL 握手协议要确保的。
  • 协商加密密钥 。用来对后面的 HTTP 协议等应用协议内容进行加密。这个密钥又称为主密钥,为加密算法的密钥。

  • 验证身份 。通常情况下,只要验证服务端身份。特殊情况下,比如一些安全级别高的应用场景,还要验证客户端身份。服务端会返回证书链,有根 CA 证书在里头。通过证书的链式担保,可以确认服务端是否是可信任的。同时,在握手期间,公钥传输成功后,还会对某些信息进行数字签名,确保数据没有被篡改且身份无误。

SSL 握手的流程并不是一成不变的,根据实际的应用场景来。主要有三种:

  • 只验证服务端。这个用三个阶段就完成握手,我们这次的请求也是这样。一般的网络请求也仅仅到这个程度。
  • 验证服务端和客户端。在安全性要求较高的场景,服务端也要验证客户端的身份。方式也是发证书证明自己。
  • 恢复原有会话 。这个属于HTTPS 优化的范畴。使用 Session Ticket 或者 Session ID 机制恢复之前已经完成握手的会话。这个是可以允许在不同的 TCP 上进行的。因为握手的加密数据已经保存,直接恢复就可以开始传递了。Session Ticket 由客户端保存加密信息,Session ID 的方式由服务端保存加密信息。不过 Session Ticket 在 Android 客户端还没有得到广泛的支持,和具体机型和内置的 OpenSSL 的版本有关。

SSL 握手的完整的交互过程如下,这里是验证服务端又验证了客户端的情况:

SSL-握手流程

我们的请求只验证服务端,所以 7,8,9 是不存在的。

现在具体分析每一个阶段的内容。

阶段一

Client Hello

作为 SSL 握手的第一个握手包,我们详细分析和理解一下包的内容。

下面是 Wireshark 解析好的这个 SSL 协议的数据包:

Secure Sockets Layer
    TLSv1.2 Record Layer: Handshake Protocol: Client Hello
        Content Type: Handshake (22)
        Version: TLS 1.0 (0x0301)
        Length: 153
        Handshake Protocol: Client Hello
            Handshake Type: Client Hello (1)
            Length: 149
            Version: TLS 1.2 (0x0303)
            Random
                GMT Unix Time: Dec  1, 2050 02:37:13.000000000 �й���׼ʱ��
                Random Bytes: 4e12e967b6169c4d67caf0575079f34b277d12318385f5a9...
            Session ID Length: 0
            Cipher Suites Length: 40
            Cipher Suites (20 suites)
            Compression Methods Length: 1
            Compression Methods (1 method)
            Extensions Length: 68
            Extension: server_name
            Extension: Extended Master Secret
            Extension: signature_algorithms
            Extension: ec_point_formats
            Extension: elliptic_curves

这个包如何解读,按照之前对 SSL 协议的分析,其实分成两个部分:

  • SSL 握手协议。
  • SSL 记录协议。

因为是握手过程,密钥还没协商,这里还是使用明文传输,记录协议的数据载体就是明文的 SSL 握手协议。

SSL 握手协议的格式为:

+-------+--------+----------------------
| 类型  | 长度    | 内容                   
+-------+--------+----------------------

我们可以从握手协议的数据包中得到这些信息:

  • 版本,TLS 1.2 也是 SSLv3.2。这是 SSL 客户端能够支持的 SSL 最高版本,主版本号 3,此版本号 2。TLS 目前的版本如下:
Major Version Minor Version Version Type
3 0 SSLv3
3 1 TLS 1.0
3 2 TLS 1.1
3 3 TLS 1.2

最后使用什么样的版本,得由服务端决定。如果服务端不支持的话,客户端得降版本。

  • 随机数 ,生成一个32字节随机数。最后加密数据用的主密钥,需要客户端和服务端一起协商出来。后面服务端的 Server Hello 阶段也会生成一个随机数。一同用来计算出主密钥。

    Random Bytes: 4e12e967b6169c4d67caf0575079f34b277d12318385f5a9...
  • 会话ID ,这里为 0。这个 Session ID 是可以重用的,具体看服务端资源和支持情况。如果要复用 Session ID, SSL 服务端需要维护连接的状态和上次握手成功留下的加密信息。因为这是这是第一次访问该网址,会话 ID 尚未创建,客户端没记录,这里为 0。如果客户端保存了 Session ID 的信息,下次发起 SSL 请求的时候会带上。

  • 加密套件 ,客户端可以支持的密码套件列表。这些套件会根据优先级排序。每一个套件代表一个密钥规格。以 “TLS” 开头,接着是密钥交换算法,然后用 “WITH” 连接加密算法和认证算法。一个加密套件有这么几个内容:密钥交换算法、加密算法(会带有支持的最高密钥位数)、认证算法还有加密方式

    密钥交换算法用在 SSL 握手阶段的交换协商好的对称密钥的阶段,为非对称加密,比如:

    • EC Deffie-Hellman 密钥交换算法。这里会被缩写为 ECDHE,也称为 DH 加密。
    • RSA 密钥加密算法。

    加密算法,是最后要用来加密 HTTP 数据的,为对称加密算法,比如:

    • DES
    • 3DES
    • AES

    摘要算法,也是对数据进行摘要。后面可以用来做数据的校验,保证数据的一致性,让中途被篡改的包失效,比如:

    • MD5
    • SHA1
    • SHA256

    所以这里一共应用了三种密钥技术,非对称密钥,对称密钥和摘要算法。用一句话总结:用非对称加密算法来传递对称加密算法的密钥,同时用摘要算法保证数据的完整性。

    这一次请求,客户端提供了 20 种密码套件供服务端选择,最终使用什么密码套件是服务端决定的。要什么密码套件会在 Server Hello 中进行反馈。

    Cipher Suites (20 suites)
      Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
      Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)
      Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
      Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
      Cipher Suite: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x009e)
      Cipher Suite: TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x009f)
      Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009)
      Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)
      Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
      Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)
      Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x0033)
      Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x0039)
      Cipher Suite: TLS_ECDHE_ECDSA_WITH_RC4_128_SHA (0xc007)
      Cipher Suite: TLS_ECDHE_RSA_WITH_RC4_128_SHA (0xc011)
      Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c)
      Cipher Suite: TLS_RSA_WITH_AES_256_GCM_SHA384 (0x009d)
      Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f)
      Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035)
      Cipher Suite: TLS_RSA_WITH_RC4_128_SHA (0x0005)
      Cipher Suite: TLS_EMPTY_RENEGOTIATION_INFO_SCSV (0x00ff)
  • 压缩算法 ,这里为 0,说明不支持压缩算法

  • 扩展字段 ,一些扩展信息,比如 SNI 的支持,ALPN 的信息等等。

密码套件随着密码学的发展而发展,而且根据现实应用中,可能会有某些密码被破解,从而导致密码套件可能会导致安全问题,所以一般都会使用当前最新最安全的密码套件。

在 Android 系统中,一般情况下,使用 SSLSocket进行连接的时候,会带上系统默认的支持的密码套件。但是这个有个缺点,比如某些密码套件的加密算法被破解或者出现安全漏洞,而且要跟着系统升级反应缓慢。OkHttp 在进行 SSL 握手的时候,会使用 ConnectionSpec 类中带上提供了一系列最新的密码套件。可以从注释上看,这些密码套件在 Chrome 51 和 Android 7.0 以上得到了完全支持。

OkHttp 密码套件

然后,再把这些密码套件和 Android 系统支持的密码套件取交集,提交给服务端。这样,万一哪个密码套件有问题,OkHttp 官方会下降支持。网络库 OkHttp 库会随着版本的迭代,不断地去提供比较新的密码套件,并且放弃那些不安全的密码套件。接入应用即时更新 OkHttp,就不用等待缓慢的系统更新了。

如果提供的所有密码套件服务端都不支持,OkHttp 有回退机制,退而求其次,选比较旧的套件。

阶段二

Server Hello

服务端收到了客户端的 Hello,通过客户端的配置信息,结合服务端的自身情况,给出了最终的配置信息。

Wireshark 解析后的内容如下:

Secure Sockets Layer
    TLSv1.2 Record Layer: Handshake Protocol: Server Hello
        Content Type: Handshake (22)
        Version: TLS 1.2 (0x0303)
        Length: 93
        Handshake Protocol: Server Hello
            Handshake Type: Server Hello (2)
            Length: 89
            Version: TLS 1.2 (0x0303)
            Random
                GMT Unix Time: Jul  4, 2022 12:28:57.000000000 �й���׼ʱ��
                Random Bytes: 6e15dfda5067399e9cd552ba30fb961914c5ce0e3f61d8f8...
            Session ID Length: 32
            Session ID: 7a92546002c514f9a0b11ef585935c7cc5182d9db3ef0db3...
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
            Compression Method: null (0)
            Extensions Length: 17
            Extension: server_name
            Extension: renegotiation_info
            Extension: ec_point_formats

具体内容如下:

  • 版本,指定这次 SSL 使用 TLSv1.2 版本。

  • 随机数 ,上面的 Client Hello 过程也生产了一个 32 位随机数,这两个随机数将参与主密钥(master key)的创建。

    Random Bytes: 6e15dfda5067399e9cd552ba30fb961914c5ce0e3f61d8f8...
  • 会话ID ,这里不为 0。说明服务端允许客户端再以后的 SSL 连接中复用这次会话。在使用 HTTPS 的 Session Ticket 可以用到。会话 ID 由服务端维持,采用恢复会话的方式创建 SSL 连接。

    Session ID: 7a92546002c514f9a0b11ef585935c7cc5182d9db3ef0db3...
  • 加密套件TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 。这个是从客户端 Client Hello 上传的 20 个加密套件中选中的,根据密码套件的格式,上面的信息有,

    交换加密算法为ECDHE ,就是EC Diffie-Hellman ,RSA 表示后面 Server Key Exchange 阶段的携带 DH 加密算法的公钥的包的数字签名的加密算法是 RSA。

    加密算法为 AES ,最高密钥支持 128 位,使用 CBC 分组。

    认证算法 SHA 。所谓 CBC 就是 AES 的机密模式,为分组加密。ECDHE_RSA,表示交换加密算法为 ,RSA 是后面的 获取 ECDHE 的参数的包进行的数字签名用的算法。

  • 压缩方法 ,这里为 0,表示不使用压缩算法。

Certificate

上面的 Server Hello 已经制定了接下来的非对称加密算法

服务端下发证书,客户端验证服务端的身份,并且取出证书携带的公钥,这个公钥是交换加密算法的公钥。也就是在 Server Hello 阶段指定的 ECDHE (EC Diffie-Hellman)算法,也是通常说的 DH 加密。

这个 Certificate 消息下发了从携带自己公钥的数字证书和 CA 证书的证书链,在 Certificates 字段中:

Secure Sockets Layer
    TLSv1.2 Record Layer: Handshake Protocol: Certificate
        Content Type: Handshake (22)
        Version: TLS 1.2 (0x0303)
        Length: 2403
        Handshake Protocol: Certificate
            Handshake Type: Certificate (11)
            Length: 2399
            Certificates Length: 2396
            Certificates (2396 bytes)
                Certificate Length: 1283
                Certificate: 308204ff308203e7a0030201020210248b4dd17f3ef11a77... 
                Certificate Length: 1107
                Certificate: 3082044f30820337a0030201020203023a6f300d06092a86... 

CA 是 PKI 体系的重要组成部分,称为认证机构。

那什么是 CA 证书?就是用来 CA 中心发布的,认证该服务单证书的合法性,可以确保该证书来源可靠而不是被中间人替换了。但是 CA 证书也可能被中间人拦截造假?那就再用一个证书来认证它。看起来好像没完没了。实际上到最后有一个根 CA 证书,这个证书存储再浏览器或者操作系统中,是系统直接信任的。

服务端证书需要 CA 证书做认证。使用的还是数字签名方式,从数据中摘要一段信息,用 CA 证书的加密。然后验证的时候时候,用 CA 证书的公钥解密,用同样的摘要算法摘要数据部分和解密好的信息进行比较。

证书签名和认

客户端在验证服务端证书的有效性有这样的一个过程。首先会找到该证书的认证证书,也就是中级 CA 证书。然后找中级 CA 证书的认证证书,可以是另一个中级 CA 证书,也可能是根 CA 证书。这样直到根 CA 证书。

接着从根 CA 证书开始往下去验证数字签名。比如有这样的证书链:根 CA 证书-> 中级 CA 证书 -> 服务端证书。用 CA 证书的公钥去验证中级证书的数字签名,再用中级证书的公钥去验证服务器证书的数字签名。任何一个环节验证失败,就可以认为证书不合法。

这就是整个证书链的认证过程:

证书验证

查看抓到的包的数据,发现只有两个证书。为服务端证书和中级 CA 证书。根 CA 证书呢?顺藤摸瓜找到它。

首先看服务端证书。它内容如下:

Certificate: 308204ff308203e7a0030201020210248b4dd17f3ef11a77... 
    signedCertificate
        version: v3 (2)
        serialNumber: 0x248b4dd17f3ef11a7733fead4cd68c21
        signature (sha256WithRSAEncryption)
        issuer: rdnSequence (0)
            rdnSequence: 3 items
                RDNSequence item: 1 item (id-at-countryName=US)
                RDNSequence item: 1 item (id-at-organizationName=GeoTrust Inc.)
                RDNSequence item: 1 item (id-at-commonName=GeoTrust SSL CA - G3)
        validity
            notBefore: utcTime (0)
                utcTime: 15-10-14 00:00:00 (UTC)
            notAfter: utcTime (0)
                utcTime: 17-12-30 23:59:59 (UTC)
        subject: rdnSequence (0)
            rdnSequence: 6 items
                RDNSequence item: 1 item (id-at-countryName=CN)
                RDNSequence item: 1 item (id-at-stateOrProvinceName=Zhejiang)
                RDNSequence item: 1 item (id-at-localityName=Hangzhou)
                RDNSequence item: 1 item (id-at-organizationName=NetEase (Hangzhou) Network Co., Ltd)
                RDNSequence item: 1 item (id-at-organizationalUnitName=MAIL Dept.)
                RDNSequence item: 1 item (id-at-commonName=*.163.com)
        subjectPublicKeyInfo
            algorithm (rsaEncryption)
            Padding: 0
            subjectPublicKey: 3082010a0282010100ce9da6fb3a940ae04a939b85a1a961...
        extensions: 8 items
            Extension (id-ce-subjectAltName)
            Extension (id-ce-basicConstraints)
            Extension (id-ce-keyUsage)
            Extension (id-ce-cRLDistributionPoints)
            Extension (id-ce-certificatePolicies)
            Extension (id-ce-extKeyUsage)
            Extension (id-ce-authorityKeyIdentifier)
            Extension (id-pe-authorityInfoAccessSyntax)
    algorithmIdentifier (sha256WithRSAEncryption)
    Padding: 0
    encrypted: ad75f99ff40e582bc9a17c01c98edf02696aa4f821dfe870...

从这个证书中我们可以窥见这些信息:

首先是 signedCertificate 字段的内容,即数字证书的数据:

  • 版本,version,v3。对应的就是 X.509 V3 标准。

  • 序列号 ,serialNumber,0x248…,证书颁发者唯一序列号。

  • 签名算法ID ,Signature Algorithm。这里指的是使用 SHA-256 进行摘要,RSA 进行加密的签名算法。

  • 证书颁发者 ,issuer,就是颁发该证书的 CA 的信息。里面携带后该 CA 的唯一名称(DN,Distinguished Name),比如国家为 US(美国),组织机构为 GeoTrust Inc.,名称为 GeoTrust SSL CA - G3。后面我们需要从证书链找到该 CA 证书,去认证当前证书。

  • 有效期 ,validity,证书的起始时间和终止时间。可以得出该证书到 17 年 12 月 30 日后过期。

  • 对象名称 ,subject,里面就是该证书的名称等主要信息了。比如国家为 CN(中国),组织为 NetEase (Hangzhou) Network Co., Ltd。名称为 *.163.com ,也是该证书适用的域名。

  • 对象公钥信息 ,subjectPublicKeyInfo。因为这是服务端证书,这个公钥后面将用于主密钥的交换过程,从中可以了解到这个公钥采用 RSA 加密,公钥内容为 3082010a0282010100ce9da6fb3a940ae04a939b85a1a961…

  • 扩展部分 ,一些扩展信息。比如对象的别名。这个如果是 CDN 的服务器证书,那么别名将会非常多。是所有使用该 CDN 的网站的域名。比如之前抓到的 CDNetworks 的 CDN 证书,它的扩展字段 subjectAltName 有这些信息:

    Certificate: 308220a630821f8ea00302010202100b8a2d407d6121375c... 
      signedCertificate
          version: v3 (2)
          serialNumber: 0x0b8a2d407d6121375cba2fac96354a41
          signature (sha256WithRSAEncryption)
          issuer: rdnSequence (0)
          validity
          subject: rdnSequence (0)
              rdnSequence: 5 items
                  RDNSequence item: 1 item (id-at-countryName=US)
                  RDNSequence item: 1 item (id-at-stateOrProvinceName=California)
                  RDNSequence item: 1 item (id-at-localityName=Campbell)
                  RDNSequence item: 1 item (id-at-organizationName=CDNetworks Inc.)
                  RDNSequence item: 1 item (id-at-commonName=support13.cdnetworks.net)
          subjectPublicKeyInfo
          extensions: 10 items
              Extension (id-ce-authorityKeyIdentifier)
              Extension (id-ce-subjectKeyIdentifier)
              Extension (id-ce-subjectAltName)
                  Extension Id: 2.5.29.17 (id-ce-subjectAltName)
                  GeneralNames: 314 items
                      GeneralName: dNSName (2)
                          dNSName: support13.cdnetworks.net
                      GeneralName: dNSName (2)
                          dNSName: china.ray-ban.com
                      GeneralName: dNSName (2)
                          dNSName: static1.read.ru
                      GeneralName: dNSName (2)
                          dNSName: ps4.cache.square-enix.co.jp
                      ...
              Extension (id-ce-keyUsage)
              Extension (id-ce-extKeyUsage)
              Extension (id-ce-cRLDistributionPoints)
              Extension (id-ce-certificatePolicies)
              Extension (id-pe-authorityInfoAccessSyntax)
              Extension (id-ce-basicConstraints)
              Extension (iso.3.6.1.4.1.11129.2.4.2)
      algorithmIdentifier (sha256WithRSAEncryption)
      Padding: 0
      encrypted: 68728010fd9e4b7e3bdbe5e47ec680330b6851e1ea4dc737...
    

    可以了解到该 CDN 为 314 个域名提供服务。

然后是证书颁发机构的签名信息:

  • 签名算法,algorithmIdentifier。这里得出使用的还是 SHA-256 摘要加 RSA 加密的签名算法。这个就是认证该证书的 CA 证书使用的签名算法。
  • 签名信息 ,encrypted,这个信息的内容,CA 证书对 SHA-256 对上面的数据部分进行摘要后,使用 RSA 的私钥加密获得。后面会用在该证书的认证过程,取出 CA 证书的公钥,解密签名信息,用同样的算法获取数据摘要,对比一下是否相同。

从上面的 issuer 可以了解到,认证该服务器证书的 CA 证书为 GeoTrust SSL CA - G3 ,我们从 Certificates 找到对应的中级证书的内容如下(中级证书可以有好几级,我们这儿只有一级):

Certificate: 3082044f30820337a0030201020203023a6f300d06092a86... 
    signedCertificate
        version: v3 (2)
        serialNumber: 146031
        signature (sha256WithRSAEncryption)
        issuer: rdnSequence (0)
            rdnSequence: 3 items
                RDNSequence item: 1 item (id-at-countryName=US)
                RDNSequence item: 1 item (id-at-organizationName=GeoTrust Inc.)
                RDNSequence item: 1 item (id-at-commonName=GeoTrust Global CA)
        validity
            notBefore: utcTime (0)
                utcTime: 13-11-05 21:36:50 (UTC)
            notAfter: utcTime (0)
                utcTime: 22-05-20 21:36:50 (UTC)
        subject: rdnSequence (0)
            rdnSequence: 3 items
                RDNSequence item: 1 item (id-at-countryName=US)
                RDNSequence item: 1 item (id-at-organizationName=GeoTrust Inc.)
                RDNSequence item: 1 item (id-at-commonName=GeoTrust SSL CA - G3)
        subjectPublicKeyInfo
            algorithm (rsaEncryption)
            Padding: 0
            subjectPublicKey: 3082010a0282010100e3be7e0a86a3cf6b6d3d2ba197ad49...
        extensions: 8 items
            Extension (id-ce-authorityKeyIdentifier)
            Extension (id-ce-subjectKeyIdentifier)
            Extension (id-ce-basicConstraints)
            Extension (id-ce-keyUsage)
            Extension (id-ce-cRLDistributionPoints)
            Extension (id-pe-authorityInfoAccessSyntax)
            Extension (id-ce-certificatePolicies)
            Extension (id-ce-subjectAltName)
    algorithmIdentifier (sha256WithRSAEncryption)
    Padding: 0
    encrypted: a0d4f72cfb740b7f64f1cd436a9f62531c027c9890a2ee4f...

可以得到中级证书名为 GeoTrust SSL CA - G3 ,证书组织为 GeoTrust Inc.

认证该 CA 证书的证书呢?还是看 issue 字段,认证证书名为 GeoTrust Global CA ,组织同样是 GeoTrust Inc.

其实这个就是根 CA 证书。在这个请求中没有找到,但在浏览器或者操作系统可以找到。一般的浏览器和系统都会内置该 CA 证书。所以根证书是受浏览器或者操作系统信任的,无需其他证书做担保。

如果想要自己的系统再信任某些非通用的权威机构的根 CA 证书,那么就去安装它。

比如我的 Windows 系统就安装了 GeoTrust Global CA 证书:

证书管理

像我们平时使用 Charles 抓 HTTPS 就是这个原理,把 Charles 的 CA 证书安装在手机中,成为受信任的根 CA 证书。

基本原理就是,Charles 代理作为 SSL 隧道,并没有透明传输,而是作为一个中间人,拦截了 SSL 握手信息,修改里面的 CA 证书。仿冒手机端和真实服务端建立连接获取主密钥,然后又仿冒服务端和手机客户端建立 SSL 连接,修改服务端证书的 CA 和数字签名,这样 Charles 就可以解析到加密的 HTTP 内容了。

修改后的服务端证书如下,可以看到 issuer 被替换成了 Charles 的证书。

Certificate: 30821ff230821edaa0030201020206015e7406ab1c300d06... 
    signedCertificate
        version: v3 (2)
        serialNumber: 1505185147676
        signature (sha256WithRSAEncryption)
        issuer: rdnSequence (0)
            rdnSequence: 6 items
                RDNSequence item: 1 item (id-at-commonName=Charles Proxy Custom Root Certificate)
                RDNSequence item: 1 item (id-at-organizationalUnitName=http://charlesproxy.com/ssl)
                RDNSequence item: 1 item (id-at-organizationName=XK72 Ltd)
                RDNSequence item: 1 item (id-at-localityName=Auckland)
                RDNSequence item: 1 item (id-at-stateOrProvinceName=Auckland)
                RDNSequence item: 1 item (id-at-countryName=NZ)
        validity
        subject: rdnSequence (0)
            rdnSequence: 5 items
                RDNSequence item: 1 item (id-at-countryName=US)
                RDNSequence item: 1 item (id-at-stateOrProvinceName=California)
                RDNSequence item: 1 item (id-at-localityName=Campbell)
                RDNSequence item: 1 item (id-at-organizationName=CDNetworks Inc.)
                RDNSequence item: 1 item (id-at-commonName=support13.cdnetworks.net)
        subjectPublicKeyInfo
        extensions: 7 items
    algorithmIdentifier (sha256WithRSAEncryption)
    Padding: 0
    encrypted: da491fc58682c7b85751db9def0b366d58cf09755ab8ef7d...

到这个阶段,我们有了一个小想法,是不是可以自己搞个根 CA ,然后推广到各个设备上使用?

理论上可以。但是推广成本太高,市场上被大多数系统认可的就这几家机构:

  • Symantec(VeriSign/GeoTrust)
  • Comodo
  • GoDaddy

像 BAT 这样的大厂也需要买它们的证书。像我这次抓的是网易的包,使用的也是 GeoTrust 。不过也有例外,我们的 12306 比较任性,就没有购买这些机构的证书,所以上这个网站在 Chrome 等浏览器经常会弹出不受信任等等。

Server Key Exchange

密钥交换阶段,这个步骤是可选步骤,对 Certificate 阶段的补充,只有在这几个场景存在:

  • 协商采用了 RSA 加密,但是服务端证书没有提供 RSA 公钥。
  • 协商采用了 DH(EC Diffie-Hellman) 加密,但是服务端证书没有提供 DH 参数。
  • 协商采用 fortezza_kea 加密,但是服务端证书没有提供参数。

我们满足了哪一个场景?

可以知道我们前面协商了使用 EC Diffie-Hellman 算法,而且没带参数,所以这个包就是服务端带过来的用来协商 DH 密钥参数的。

TLSv1.2 Record Layer: Handshake Protocol: Server Key Exchange
    Content Type: Handshake (22)
    Version: TLS 1.2 (0x0303)
    Length: 333
    Handshake Protocol: Server Key Exchange
        Handshake Type: Server Key Exchange (12)
        Length: 329
        EC Diffie-Hellman Server Params
            Curve Type: named_curve (0x03)
            Named Curve: secp256r1 (0x0017)
            Pubkey Length: 65
            Pubkey: 04a10ad7a23135095205caf7ca8e4c838728e877dbcb23c3...
            Signature Hash Algorithm: 0x0601
                Signature Hash Algorithm Hash: SHA512 (6)
                Signature Hash Algorithm Signature: RSA (1)
            Signature Length: 256
            Signature: 8c7c51f60574144e9e1385a534e12f85911e8dc7cd40dc04...

这个包把 DH 算法需要的公钥给传递过来了,即 Pubkey: 04a10ad7a23135095205caf7ca8e4c838728e877dbcb23c3...

同样这个包也携带了数字签名 Signature: 8c7c51f60574144e9e1385a534e12f85911e8dc7cd40dc04... ,用服务端证书带过来的公钥验证一下完整性和来源。

Server Hello Done

通知客户端,版本和加密套件协商结束。

TLSv1.2 Record Layer: Handshake Protocol: Server Hello Done
    Content Type: Handshake (22)
    Version: TLS 1.2 (0x0303)
    Length: 4
    Handshake Protocol: Server Hello Done
        Handshake Type: Server Hello Done (14)
        Length: 0

这个 Server Hello Done,就像 TCP 协议的 ACK 确认包一样,这里服务端也给了个确认的信息,通知客户端已经做好进入下一个阶段的准备。

通过 Wireshark 抓包发现了一个现象,就是 Server Key Exchange 和 Server Hello Done 被放到了同一个 SSL 记录协议中,这是因为 SSL 记录协议具有组合功能。客户端收到这样的包后,会处理成两个单独的协议包,这又是 SSL 记录协议的分组功能。

Secure Sockets Layer
    TLSv1.2 Record Layer: Handshake Protocol: Server Key Exchange
    TLSv1.2 Record Layer: Handshake Protocol: Server Hello Done

这样做的好处,可以减少发 TCP 包的次数,减少 SSL 握手的时间。

阶段三

如果在一些安全级别高的场景,服务端也会要求客户端上报证书,会有 Certificate Request 的 SSL 握手报文。这样的情况下,接下来会有完整的客户端证书上报服务端的流程。整个流程和阶段二类似。

阶段四

因为我们这里只需要验证服务端的证书,所以直接进入阶段四,开始最后的握手。这个阶段的主要目的,就是生产加密密钥,并进行安全传输。

Client Key Exchange

这里,客户端不直接生成加密密钥,而是通过之前客户端和服务端生成的随机数又再生成一个随机数,使用前面协商好的用 EC Diffie-Hellman 算法进行加密传输给服务端。这个值又被称为 “premaster secret“。

TLSv1.2 Record Layer: Handshake Protocol: Client Key Exchange
    Content Type: Handshake (22)
    Version: TLS 1.2 (0x0303)
    Length: 70
    Handshake Protocol: Client Key Exchange
        Handshake Type: Client Key Exchange (16)
        Length: 66
        EC Diffie-Hellman Client Params
            Pubkey Length: 65
            Pubkey: 0433cfbd121d0fa5299819604a15237fc9359845a2a9dffe...

服务端收到这个报文后,会使用自己的私钥解开这个随机数。

在这个阶段过后,服务端和客户端都有三个随机数:客户端随机数、服务端随机数和预备主密钥。

在服务端收到了 Client Key Exchange 消息后,两端都按照相应的算法生成了主密钥,加密密钥交换完成。

交换完了,因为主密钥是两个端按照约定好的算法产生的,如何保证这个主密钥是正确的?

这时候会进入下一个阶段。客户端和服务端会对握手信息使用 SHA 做个摘要,用 AES 加密算法和主密钥加密,传递给对方验证。这种方式也称为消息认证。就是下面的过程:

Change Cipher Spec(Client)

客户端通知服务端,后续的报文将会被加密。

Encrypted Handshake Message(Client)

这里就是客户端的 Client Finished 消息。

也是整个 SSL 过程中,发送给服务端的第一个加密消息。

服务端接收后,服务端用同样的方式计算出已交互的握手消息的摘要,与用主密钥解密后的消息进行对比,一致的话,说明两端生成的主密钥一致,完成了密钥交换。

Change Cipher Spec(Server)

服务端通知客户端,后续的报文将会被加密。

Encrypted Handshake Message(Server)

这里就是服务端的 Server Finish 消息。

和上面的客户端的 Encrypted Handshake Message 一样,是服务端发出的第一条加密信息。

客户端按照协商好的主密钥解密并验证正确后,SSL 握手阶段完成。

小结

整个 SSL 握手主要是要完成这几个目标:

  • 对服务端身份的验证,或者客户端

  • 协商好对称加密算法和对称加密密钥

对应 Java API 为 SSLSocket :

sslSocket.startHandshake();

这次请求的整个过程耗时大约为 380ms。可以看出,SSL 握手是很消耗请求时间的。所以对握手进行优化,比如使用 Session ID 或者 Session Ticket。这个类似于 HTTP 协议的 Session 和 Cookie 的使用。

数据传输

经过了 SSL 握手后,服务端的身份认证成功,协商出了加密算法为 AES,密钥为 xxxxx(客户端和服务端拿三个随机值用相同算法计算出来的,并没有明文传输)。一切准备就绪。

SSL 握手成功,已经可以对接下来的数据加密了,接下来各种应用层协议都可以加密传输。

Application Data

应用数据传输消息。因为这里是 HTTPS,所以可以对 HTTP 应用协议数据加密然后传输了。

Secure Sockets Layer
    TLSv1.2 Record Layer: Application Data Protocol: http
        Content Type: Application Data (23)
        Version: TLS 1.2 (0x0303)
        Length: 1072
        Encrypted Application Data: 6d9b3c9089271630c33506fe28cd6a61fed1f4bd2808f537...

从这里,不知道密钥是无法知道这里传输的是什么数据,连传输的是什么协议的内容都不知道。

所以之前创建 SSL 隧道,让代理服务器盲传 HTTPS 数据,就得通过 CONNECT 方法告诉代理服务器要连哪台主机,哪个端口号,要不然代理服务器也是一脸懵逼。

所以 SSL 协议是很独立的,这里是对 HTTP 进行了加密,也可以对其他协议进行加密。它就像是 TCP 和应用层协议的中间层,为上层协议提供了加密的数据传输。

Encryted Alert

SSL 警告消息,因为是加密的内容,所以单从 Wireshark 看不出警报的内容。

Secure Sockets Layer
    TLSv1.2 Record Layer: Encrypted Alert
        Content Type: Alert (21)
        Version: TLS 1.2 (0x0303)
        Length: 48
        Alert Message: Encrypted Alert

但因为警报消息经常只是客户端用来提示服务端 SSL 传输结束,对照抓包到的内容确实如此。所以这里只是 SSL 传输结束的一个信号。

发出了 Encryted Alert 后客户端数据传输完毕,准备进入四次挥手断开 TCP 连接。

猜你喜欢

转载自blog.csdn.net/firefile/article/details/80537053