虎牙、B站APP流量分析
虎牙直播
对于直播来说,拉流采用的时http-flv。在建立连接过程中,建立TCP连接以及发送GET请求即可。可以从历史的GET请求携带的中获取直播源并进行请求。
B站直播
建立连接的过程中需要建立TCP连接后进行协商tls加密信息。
对于断开重连的场景,有两种方式:
session id会话复用:对于已经建立的SSL会话,使用session id为key(session id来自第一次请求的server hello中的session id字段),主密钥为value组成一对键值,保存在本地,服务器和客户端都保存一份。
当第二次握手时,客户端若想使用会话复用,则发起的client hello中session id会置上对应的值,服务器收到这个client hello,解析session id,查找本地是否有该session id,如果有,判断当前的加密套件和上个会话的加密套件是否一致,一致则允许使用会话复用,于是自己的server hello 中session id也置上和client hello中一样的值。
session ticket会话复用:客户端和服务器端建立了一次完整的握手过程后,服务器端将本次的会话数据进行加密,例如会话标识符、证书、密码套件和主密钥等,加密后生成一个ticket票据,并将票据通过NewSessionTicket子消息发送给客户端,由客户端来保存,下一次连接时客户端如果希望恢复上一次会话而不是重新进行握手,就将“票据”一起发送给服务器端,待服务器端解密校验无误后,进行一次简短的握手,恢复上一次会话。
这种方式适用于重连的服务器变化的情况。
B站点播
基于UDP的DTLS、QUIC协议占主要部分。
推流
对于推流,则以RTMP协议为主:
B站推流
虎牙推流
RTMP的建联过程
握手阶段
- 客户端发送 C0+C1
- 服务端发送 S0+S1+S2
- 客户端发送 C2
建立网络连接:服务端反馈确认窗口大小、带宽大小
- ①、客户端发起连接请求
- ②、服务器设置客户端的应答窗口大小
- ③、服务器设置客户端的发送带宽大小
- ④、服务器设置客户端的接收块大小
- ⑤、服务器响应连接结果
- ⑥、客户端设置服务器的接收块大小
建立网络流
- 客户端发送命令消息中的“创建流” (createStream) 命令到服务器端。
- 服务器端接收到“创建流” 命令后, 发送命令消息中的“结果” (_result), 通知客户端流的状态
- 客户端向服务器获取指定流的长度
播放/推流
- 客户端发送命令消息中的“推流” (publish()) 命令到服务器。
- 服务器发送用户控制消息中的 “stream begin” ,告知客户端流 ID
- 服务器发送客户端要播放的音频和视频数据
HTTP-FLV
HTTP-FLV 是将音视频数据以 FLV 文件格式进行封装,再将 FLV 格式数据封装在 HTTP 协议中进行传输的一种流媒体传输方式。
HTTP-FLV 被广泛采用的原因:
- HTTP 优点: a. 一些防火墙会墙掉 RTMP 或者其他的一些协议,但是防火墙对 HTTP 非常友好,不会墙掉 HTTP,因此基于 HTTP 传输的成功率更高。
- FLV 优点: a. MP4、MKV 等封装格式将音视频数据和音视频元数据、索引、时间戳等分开存放,必须拿到完整的音视频文件才能播放,因为里面的单个音视频数据块不带有时间戳信息,播放器不能将这些没有时间戳信息的数据块连续起来,因此不能实时的解码播放。(当然 MP4 后来扩展了 FMP4 用于流媒体) b. FLV 格式的 FLV Tag Header 中携带时间戳,FLV 将每一帧音视频数据(Tag Body)封装成包含时间戳等音视频元数据(Tag Header)的数据包(Tag)。当播放器拿到 Tag 后,可根据时间戳等音视频元数据进行解码和播放。
HTTP-FLV 的实现原理: HTTP-FLV 利用 HTTP/1.1 分块传输机制发送 FLV 数据。虽然直播服务器无法知道直播流的长度,但是 HTTP/1.1 分块传输机制可以不填写 content-length
字段而是携带 Transfer-Encoding: chunked
字段,这样客户端就会一直接受数据。
解析后的协议使用的依然是http-flv
可以通过设置SSLKEYLOGFILE的环境变量, 就能够获取到每次对话产生的log文件。利用每次对话中,存储下来的log来解密报文。
设置SSLKEYLOGFILE环境变量
通过ssl.log中的client random(在TLS握手期间由客户端发送的随机非加密值)来标识会话,并从中获取对应的密钥。
切换操作流程:
拉流端:http-flv
建立TCP连接;
建立TLS连接(对于B站APP);
通过首次建立连接时收集到的session id或者是session ticket进行会话恢复。
发出HTTP-GET请求FLV视频数据;
通过历史信息获取直播源并生成URI请求。
推流端:RTMP
建立TCP连接;
RTMP握手;
建立网络连接:客户端与服务端交换确认窗口大小、带宽大小;
建立网络流;
设置SSLKEYLOGFILE环境变量
在Wireshark中通过”编辑->首选项->Protocols->TLS“配置TLS协议中的(Pre)-Master-Secret log filename,将其配置成环境变量SSLKEYLOGFILE指向的log文件。
再重新进行抓包即可解析出TLS文件。
对话窗不能是通过恢复协议而恢复的窗口, 报文中一定要包含有 ClientKeyExchange
的握手消息
如果是使用RSA密钥交换算法,那么报文中一定要包含ClientKeyExchange的消息, 这样wireshark 才能拿到客户端产生的随机数(预主密钥),才能把密钥和报文匹配起来, 而恢复会话就很难确定之前的密钥是什么值了。