如何在Python3的requests程序中捕获SSL客户端与服务端交互数据?
嘿,我来给你梳理几种实用的方法,既能满足你捕获HTTPS交互数据的需求,也能适配不同的场景——从你熟悉的Wireshark配合方式,到纯代码内的捕获,再到第三方工具辅助,都给你列出来:
1. 沿用你熟悉的Wireshark解密:Python导出SSL密钥
既然你已经会用Firefox导出SSL密钥配合Wireshark解密,那这个方法对你来说上手最快,几乎不用改代码。Python 3.7+支持通过环境变量SSLKEYLOGFILE输出SSL主密钥,Wireshark可以用这个文件解密Python发出的HTTPS流量。
实现步骤:
在你的代码开头添加一行设置环境变量的代码,然后正常运行程序,最后用Wireshark导入密钥文件即可:
import os import requests # 生成SSL密钥日志文件,Wireshark会用它解密流量 os.environ['SSLKEYLOGFILE'] = 'python_ssl_keys.log' # 下面是你的原有代码,记得补充url和header的实际值 url = "https://你的目标域名" header = {"User-Agent": "Mozilla/5.0 ..."} # 替换成实际请求头 def get_city_id(city_name): result = requests.get(url+'/json/ac-geo', params='q=' + city_name, headers=header) return result def search_annonce(criteres): result = requests.post(url+'/annonce', headers=header, data=criteres) return result # 建议加上return,方便后续处理 print(get_city_id('draveil').json()) city_id = get_city_id('versailles').json() criteres = {'produit': 'vente', 'geo_objets_ids': city_id[0]['id'], 'typesbien[]': 'appartement', 'surface[min]': 40, 'prix[max]': '', 'nb_pieces[list][]': 2, 'recherche': 1, 'reference_courte': ''} search_annonce(criteres)
Wireshark配置:
打开Wireshark后,依次点击 Edit > Preferences > Protocols > TLS,在(Pre)-Master-Secret log filename选项中选择刚才生成的python_ssl_keys.log,然后捕获对应的网络接口,就能看到解密后的HTTPS明文数据了。
2. 纯Python代码内捕获应用层数据
如果只需要获取请求和响应的明文内容(不需要SSL层的握手细节),可以直接用requests的**钩子(hooks)**功能,在请求发送前和响应返回后自动记录数据,完全不需要外部工具。
示例代码:
import requests def log_request_details(request): # 记录请求信息 print("=== 发送请求 ===") print(f"方法: {request.method}") print(f"URL: {request.url}") print(f"请求头: {dict(request.headers)}") if request.body: print(f"请求体: {request.body}") return request # 必须返回request,否则请求会被终止 def log_response_details(response, *args, **kwargs): # 记录响应信息 print("\n=== 收到响应 ===") print(f"状态码: {response.status_code}") print(f"响应头: {dict(response.headers)}") print(f"响应内容: {response.text}") return response # 必须返回response,否则响应会被丢弃 # 创建session对象来统一配置钩子 session = requests.Session() session.hooks['request'].append(log_request_details) session.hooks['response'].append(log_response_details) # 你的原有业务代码 url = "https://你的目标域名" header = {"User-Agent": "Mozilla/5.0 ..."} def get_city_id(city_name): result = session.get(url+'/json/ac-geo', params='q=' + city_name, headers=header) return result def search_annonce(criteres): result = session.post(url+'/annonce', headers=header, data=criteres) return result print(get_city_id('draveil').json()) city_id = get_city_id('versailles').json() criteres = {'produit': 'vente', 'geo_objets_ids': city_id[0]['id'], 'typesbien[]': 'appartement', 'surface[min]': 40, 'prix[max]': '', 'nb_pieces[list][]': 2, 'recherche': 1, 'reference_courte': ''} search_annonce(criteres)
运行后,控制台会直接输出每一次请求和响应的完整明文信息,适合快速调试。
3. 第三方工具辅助:mitmproxy
如果你想要可视化的流量分析界面,或者需要更强大的流量处理能力,可以用mitmproxy——一款专门用于拦截、查看和修改HTTP/HTTPS流量的工具,配置起来也很简单。
实现步骤:
- 安装mitmproxy:
pip install mitmproxy - 启动mitmproxy:在命令行输入
mitmproxy,会打开一个交互式的终端界面 - 修改你的Python代码,添加代理配置,让请求通过mitmproxy转发:
import requests url = "https://你的目标域名" header = {"User-Agent": "Mozilla/5.0 ..."} # 设置代理指向mitmproxy的默认端口8080 proxies = { 'http': 'http://localhost:8080', 'https': 'http://localhost:8080', } def get_city_id(city_name): # 添加proxies和verify=False(跳过证书验证,因为mitmproxy用的是自签名证书) result = requests.get(url+'/json/ac-geo', params='q=' + city_name, headers=header, proxies=proxies, verify=False) return result def search_annonce(criteres): result = requests.post(url+'/annonce', headers=header, data=criteres, proxies=proxies, verify=False) return result # 第一次运行需要安装mitmproxy的根证书:访问http://mitm.it,下载对应系统的证书并安装 print(get_city_id('draveil').json()) city_id = get_city_id('versailles').json() criteres = {'produit': 'vente', 'geo_objets_ids': city_id[0]['id'], 'typesbien[]': 'appartement', 'surface[min]': 40, 'prix[max]': '', 'nb_pieces[list][]': 2, 'recherche': 1, 'reference_courte': ''} search_annonce(criteres)
运行代码后,mitmproxy的界面会实时显示所有经过的请求和响应,你可以用键盘快捷键查看详情、导出数据等。
方案选择建议
- 如果你需要完整的SSL层交互细节(比如握手过程、密钥交换):选方案1(SSLKEYLOGFILE+Wireshark)
- 如果你只需要快速查看应用层的请求/响应明文:选方案2(纯代码钩子)
- 如果你需要可视化分析或修改流量:选方案3(mitmproxy)
内容的提问来源于stack exchange,提问作者p305




