HLS AES-128 加密视频解密实战:Fiddler 抓包提取密钥与 Python 3.12 自动化下载 HLS AES-128 加密视频解密实战Fiddler 抓包提取密钥与 Python 3.12 自动化下载流媒体技术已经成为现代互联网视频传输的主流方案其中 HLSHTTP Live Streaming协议因其良好的兼容性和适应性被广泛采用。然而许多平台为了保护版权内容会对 HLS 视频流进行 AES-128 加密处理。本文将深入探讨如何通过 Fiddler 抓包工具提取加密密钥并利用 Python 3.12 实现自动化下载和解密流程。1. HLS 加密原理与关键技术解析HLS 协议的核心是将视频分割成一系列小的 TSTransport Stream文件并通过 M3U8 索引文件进行管理。当视频内容被加密时M3U8 文件中会包含#EXT-X-KEY标签指明加密方法和密钥获取方式。AES-128 加密是 HLS 最常用的加密方案其工作流程如下密钥生成内容提供商使用 16 字节随机数生成加密密钥分片加密每个 TS 文件使用相同的密钥进行 AES-128 CBC 模式加密密钥分发密钥通过 HTTPS 单独传输M3U8 文件仅包含密钥 URI初始向量(IV)可为固定值或随机生成用于 CBC 模式的初始块典型的加密 M3U8 文件示例如下#EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:10 #EXT-X-MEDIA-SEQUENCE:0 #EXT-X-KEY:METHODAES-128,URIhttps://example.com/key.key,IV0x00000000000000000000000000000000 #EXTINF:10.000000, segment0.ts #EXTINF:10.000000, segment1.ts2. Fiddler 抓包与密钥提取实战Fiddler 是一款强大的 HTTP 调试代理工具在分析加密视频流时尤为有用。以下是使用 Fiddler 捕获密钥的具体步骤2.1 Fiddler 基础配置安装 HTTPS 证书打开 Fiddler → Tools → Options → HTTPS勾选 Decrypt HTTPS traffic点击 Actions → Trust Root Certificate过滤目标流量在右侧 Filters 面板中设置目标主机名或使用CtrlF搜索 .m3u8 或 key2.2 密钥捕获与提取当播放加密视频时Fiddler 会捕获到两类关键请求M3U8 文件请求包含#EXT-X-KEY标签密钥请求返回 16 字节二进制密钥数据获取密钥的两种方法方法一直接查看响应体找到密钥请求通常为 key/key.key/encryptkey 等路径在 Inspectors → Headers 查看 Content-Length 应为 16切换到 HexView 标签页复制 16 进制数据方法二Base64 编码导出右键点击密钥请求 → Save → Response → Entire Response用文本编辑器打开保存的文件删除 HTTP 头部分对剩余二进制数据进行 Base64 编码注意某些平台会动态生成密钥需要确保在同一个会话中完成抓包和下载操作。3. Python 自动化下载解密实现下面是一个完整的 Python 3.12 脚本实现从 M3U8 解析到 TS 下载解密的自动化流程import os import re import requests from Crypto.Cipher import AES from concurrent.futures import ThreadPoolExecutor from urllib.parse import urljoin class HLSDownloader: def __init__(self, m3u8_url, output_fileoutput.mp4): self.m3u8_url m3u8_url self.output_file output_file self.session requests.Session() self.session.headers.update({ User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) }) def fetch_key(self, key_uri, ivNone): 获取并解析解密密钥 response self.session.get(key_uri) if response.status_code ! 200: raise ValueError(f密钥获取失败: {response.status_code}) key response.content if len(key) ! 16: raise ValueError(密钥长度必须为16字节) # 处理初始向量 if iv is None: iv bytes([0]*16) elif isinstance(iv, str): if iv.startswith(0x): iv bytes.fromhex(iv[2:]) else: iv iv.encode(utf-8) return key, iv def parse_m3u8(self): 解析M3U8文件获取TS片段和加密信息 response self.session.get(self.m3u8_url) if response.status_code ! 200: raise ValueError(M3U8文件获取失败) content response.text.splitlines() ts_list [] key_uri None iv None for line in content: line line.strip() if line.startswith(#EXT-X-KEY): # 解析加密信息 match re.search(rURI([^]), line) if match: key_uri urljoin(self.m3u8_url, match.group(1)) iv_match re.search(rIV([^,]), line) if iv_match: iv iv_match.group(1) elif line and not line.startswith(#): # 添加TS片段 ts_url urljoin(self.m3u8_url, line) ts_list.append(ts_url) return ts_list, key_uri, iv def download_ts(self, ts_url, cipherNone): 下载并解密单个TS片段 response self.session.get(ts_url, streamTrue) if response.status_code ! 200: print(f下载失败: {ts_url}) return None data response.content if cipher: data cipher.decrypt(data) return data def run(self): 执行完整下载流程 # 1. 解析M3U8 ts_list, key_uri, iv self.parse_m3u8() if not ts_list: raise ValueError(未找到有效的TS片段) # 2. 获取解密密钥 cipher None if key_uri: key, iv self.fetch_key(key_uri, iv) cipher AES.new(key, AES.MODE_CBC, iviv) print(f成功获取解密密钥: {key.hex()}) # 3. 多线程下载TS片段 print(f开始下载 {len(ts_list)} 个TS片段...) with ThreadPoolExecutor(max_workers8) as executor: futures [executor.submit(self.download_ts, ts, cipher) for ts in ts_list] ts_data [f.result() for f in futures if f.result()] # 4. 合并TS文件 print(合并TS片段...) with open(self.output_file, wb) as f: for data in ts_data: f.write(data) print(f视频下载完成: {self.output_file}) if __name__ __main__: # 使用示例 m3u8_url https://example.com/playlist.m3u8 downloader HLSDownloader(m3u8_url) downloader.run()3.1 关键代码解析密钥处理fetch_key方法处理密钥URI和初始向量支持十六进制(0x...)和字符串格式的IV自动验证密钥长度是否为16字节M3U8解析使用正则表达式提取#EXT-X-KEY标签自动补全相对路径的TS片段URL并发下载使用ThreadPoolExecutor实现多线程下载每个线程独立处理下载和解密解密处理使用 PyCryptodome 库的 AES CBC 模式解密在下载流中实时完成减少内存占用3.2 依赖安装执行脚本前需安装以下依赖pip install requests pycryptodome4. 高级技巧与异常处理在实际应用中可能会遇到各种特殊情况以下是几个常见问题的解决方案4.1 动态密钥与鉴权许多商业平台会采用动态密钥和访问控制# 处理带鉴权参数的密钥请求示例 def fetch_key_with_auth(self, key_uri, auth_token): params {token: auth_token} response self.session.get(key_uri, paramsparams) return response.content4.2 TS 片段校验为确保下载完整性可添加校验逻辑def download_ts(self, ts_url, cipherNone, retry3): for attempt in range(retry): try: response self.session.get(ts_url, timeout10) response.raise_for_status() data response.content if len(data) 0: raise ValueError(空内容) if cipher: data cipher.decrypt(data) # 简单校验TS文件头 if data[0] ! 0x47: # TS同步字节 raise ValueError(无效TS格式) return data except Exception as e: if attempt retry - 1: print(f下载失败 {ts_url}: {str(e)}) return None4.3 性能优化对于大型视频可采用以下优化策略分段合并每下载N个TS文件就合并一次减少内存压力进度显示添加tqdm进度条显示下载进度断点续传记录已下载的TS片段支持中断后继续from tqdm import tqdm def run_with_progress(self): ts_list, key_uri, iv self.parse_m3u8() cipher self.prepare_cipher(key_uri, iv) with tqdm(totallen(ts_list), desc下载进度) as pbar: with ThreadPoolExecutor(max_workers8) as executor: futures {executor.submit(self.download_ts, ts, cipher): ts for ts in ts_list} with open(self.output_file, wb) as f: for future in as_completed(futures): data future.result() if data: f.write(data) pbar.update(1)5. 安全与法律注意事项在实施HLS视频下载方案时必须注意以下关键点版权合规仅下载拥有合法权限的内容不得规避技术保护措施用于侵权用途网络安全使用HTTPS确保密钥传输安全避免在代码中硬编码敏感信息资源节制添加合理的请求间隔(如time.sleep(0.1))设置User-Agent标识合规爬虫数据保护下载的内容不应在未授权情况下二次分发及时删除临时解密文件在实际开发中建议将下载速度控制在合理范围内并尊重网站的robots.txt协议。对于商业级应用应考虑使用官方API而非逆向工程方案。