【网络】实践:Wireshark分析HTTPS协议

介绍

在本博客中我们基于一个简单的HTTPS会话示例,展示如何通过各种加密算法等,在TLSv1.2协议规则下计算并验证各个域,为学习HTTPS协议以及实现HTTPS协议的初学者提供参考示例。

本博客示例TLS协议的基本信息如下:

  • TLS版本:TLSv1.2
  • Cipher:TLS_RSA_WITH_AES_128_CBC_SHA, 选择该套件的原因是其不是十分复杂,适合用于展示;
  • 扩展:Extened Master SecretMaster Secret的计算不同于最初的TLS v1.2 RFC文档使用的方式,具体参见对应的RFC。
  • 扩展:Encrypt-then-MAC:最初的TLSv1.2协议使用MAC-then-Encrypt进行消息加密和验证,但是该扩展先加密再计算摘要验证。

下面的讲解会假定你已经初步了解TLS协议的某些细节,如果遇到不清楚的概念,你随时可以参考博客HTTPS协议的正文和附录部分,包括Extened Master SecretEncrypt-then-MAC扩展和PRF等内容。

此外,下面的所有内容都可以在github仓库net-protocol-tools:demo/demo-TLS_RSA_WITH_AES_128_CBC_SHA中找到。

Setup

准备工具

此次分析实践用到的主要工具是基于Wireshark, opensslnginx:

  • Wireshark:抓取流量包,导入RSA私钥后可以解析各个加密的域;可以用来验证我们手动分析的结果;
  • openssl:用于生成私钥、证书、计算摘要和加解密;
  • nginx: 配置HTTPS服务器。

此次分析在Windows上进行,其中openssl工具使用cygwin安装。对于LinuxMacos,可以使用对应的包管理器安装openssl,版本信息:1.1.1c

上面的工具安装完成后,我们创建一个目录demo并进入其中,后面的所有数据都会保存在demo中。

openssl命令参考博客:openssl及其使用

配置Nginx服务器和相关证书

参考另一篇博客nginx配置HTTPS实践案例1部分,主要信息如下:

  • 网址:https://my-ssl.test:443
  • 私钥:my-ssl.test.key
  • 证书:my-ssl.test.crt

将上面的my-ssl.test.keymy-ssl.test.crt复制到demo目录方便后续引用。

打开Wireshark并准备过滤数据

  • 1.准备监听数据
    我们将使用本地端口12443连接到上面我们配置的nginx服务器,因此我们使用tcp.port==12443 && tls来过滤包,如下图所示:
    在这里插入图片描述
  • 2.导入私钥进行解密
    Edit > Preferences > Protocols下找到TLS协议选项,按照下面的指引导入私钥:
    edit TLS config
  • 3.点击Wireshark工具栏中左侧的在这里插入图片描述按钮开始进行捕获

使用openssl构造请求

打开一个命令行并切换到demo目录,执行下面的命令:

echo -ne 'GET / HTTP/1.1\r\nHost: my-ssl.test\r\n\r\n'|openssl s_client  -CAfile my-ssl.test.crt -cipher AES128-SHA -tls1_2 -servername my-ssl.test -bind localhost:12443 -connect my-ssl.test:443 -keylogfile key.log

各选项含义如下:

  • -CAfile 指定证书,保证证书校验成功;
  • -cipher AES128-SHA指定加密套件TLS_RSA_WITH_AES_128_CBC_SHA
  • -tls1_2 指定TLSv1.2版本
  • -keylogfile 记录master secret信息,用于后面计算验证
    其他选项参见上面提及的博客。

我们可以在Wireshark中看到相应的请求记录:
在这里插入图片描述

验证

协议

查看ClientHello中包含两个扩展
在这里插入图片描述

证书签名验证

参见博客证书证书验证一节。

pre_master_secret

我们使用RSA交换,因此在ClientKeyExchange中能够看到使用公钥加密的pre_master_secret
在这里插入图片描述
右键 > Export Packet Bytes...将文件保存到demo目录并命名为pre_master_secret_encrypted.bin
在这里插入图片描述
使用下面的命令解密pre_master_secret_encrypted.bin

openssl rsautl -decrypt -inkey my-ssl.test.key -in pre_master_secret_encrypted.bin -out pre_master_secret

解密后的文件为pre_master_secret

将解密的结果与key.log中的RSA xxxx yyyy中的yyyy部分对比,相同即解密成功:
在这里插入图片描述

extended_master_secret

根据Extened Master Secret扩展的规定,master_secret生成规则:

master_secret = PRF(pre_master_secret, “extended master secret”, session_hash) [0…47];

首先需要session数据,将ClientHello,ServerHello,ServerCertificate,ServerHelloDone,ClientKeyExchange部分的消息体(注意:不包括TSL Record的头部)导出,分别命名为:client_hello_handshake.bin,server_hello_handshake.bin,server_certificate_handshake.bin,server_hello_done_handshake.bin,client_key_exchange_handshake.bin
导出参考:
export

应用博客HTTPS协议附录 > PRF部分的shell脚本,计算extended_master_secret:

./prf.sh pre_master_secret 'extended master secret' <(openssl dgst -sha256 -binary <(cat client_hello_handshake.bin server_hello_handshake.bin server_certificate_handshake.bin server_hello_done_handshake.bin client_key_exchange_handshake.bin)) 48 extended_master_secret

在这里插入图片描述

key_block

TLS_RSA_WITH_AES_128_CBC_SHA的加密算法是AES128,即加密key长度16字节(128位), MAC算法是SHA1,因此MAC的key长度是20字节,所以总长度是 20*2 + 16*2 = 72
根据key_block的计算规则:

key_block = PRF(SecurityParameters.master_secret,
“key expansion”,
SecurityParameters.server_random +
SecurityParameters.client_random);

我们需要ServerHello.randomClientHello.random作为种子,从Wireshark导出命名为server_random.binclient_random.bin

然后生成key_block

./prf.sh extended_master_secret 'key expansion' <(cat server_random.bin client_random.bin) $((20*2+16*2)) key_block

然后将其拆分为4个key:

head -c 20 key_block > client_MAC_key
tail -c +21 key_block|head -c 20 > server_MAC_key
tail -c 32 key_block|head -c 16 > client_ENC_key
tail -c 32 key_block|tail -c 16 > server_ENC_key

计算Finished消息体的验证码

根据RFC文档:

签名数据=
PRF(master_secret, “client finished”, Hash(handshake_messages))
[0…verify_data_length-1];

因此计算如下:

./prf.sh extended_master_secret 'client finished' <(openssl dgst -sha256 -binary <(cat client_hello_handshake.bin server_hello_handshake.bin server_certificate_handshake.bin server_hello_done_handshake.bin client_key_exchange_handshake.bin)) 12 client_finished_verify_data

解密Client Finished

根据Encrypt-then-MAC扩展,TLS Record的结构为:

{
   uint8 contentType; // Handshake 为0x16
   uint16 version; // TLSv1.2 = 0x0303
   uint16 length; // IV(16)字节 + 加密消息体长度 + MAC长度(20)
   uint8[] IV; // CBC模式独有,对于AES-128,为16字节
   uint8[]  encBody; // 加密消息体
   uint8[]  MAC; // SHA1的MAC长度为20字节 
}

在Wireshark中,Change Cipher Spec之后我们可以看到客户端发送的Finished消息体是加密的,将消息体(包括TLS Record头部)导出为client_finished_record_encrypted.bin
因此,解密encBody如下:

openssl enc -aes-128-cbc -d -in <(tail -c +22 client_finished_record_encrypted.bin|head -c -20) -iv "$(hexdump -ve '1/1 "%02x"' <(tail -c +6 client_finished_record_encrypted.bin|head -c 16))" -K "$(hexdump -ve '1/1 "%02x"' client_ENC_key)" -nopad

注意:tail -c +22意味着跳过前面的21个字节,即跳过contentType,version,lengthIV部分。

与client_finished_verify_data比较:
在这里插入图片描述

计算Finished加密体中的MAC

根据Encrypt-Then-MAC扩展,MAC计算如下:

MAC(MAC_write_key, seq_num +
TLSCipherText.type +
TLSCipherText.version +
TLSCipherText.length +
IV +
ENC(content + padding + padding_length));

特别注意,其中TLSCipherText.length指的IVencBody的长度之和

计算如下:

openssl dgst -sha1 -mac hmac -macopt "hexkey:$(hexdump -ve '1/1 "%02x"' client_MAC_key)" <(cat <(echo -ne '\x00\x00\x00\x00\x00\x00\x00\x00') <(echo -ne '\x16\x03\x03\x00\x30') <(tail -c +6 client_finished_record_encrypted.bin|head -c -20))

在上面的命令中,第2个echo -ne部分,\x16是协议类型,\x03\x03是协议版本,\x00\x30(=48)IV(16)encBody(68-16-20=32)的长度和。

从Wireshark导出的client_finished_record_encrypted.bin的后20个字节时MAC的数据,对比:
在这里插入图片描述

Application Data数据解密

解密过程同Client Finished,首先从Wireshark导出ApplicationData(包括TLS Record头部),保存为client_application_data_record_encrypted.bin,解密:

openssl enc -aes-128-cbc -d -in <(tail -c +22 client_application_data_record_encrypted.bin|head -c -20) -iv "$(hexdump -ve '1/1 "%02x"' <(tail -c +6 client_application_data_record_encrypted.bin|head -c 16))" -K "$(hexdump -ve '1/1 "%02x"' client_ENC_key)" -nopad|hexdump -C

在这里插入图片描述
注意padding是最后一个字节的重复,而不是\x00.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值