注册 登录

清河洛

python中的中间人代理模块mitmporxy

qingheluo2022-04-11清河洛721
mitmproxy是一个交互式的、支持SSL/TLS的拦截代理,启动后会提供一个命令行界面,用户可以实时看到发生的请求,并通过命令过滤请求,查看请求数据mitmweb是一个基于web的mitmproxy界面。启动后会提供一个web界面,用户可以实时看到发生的请求,并通过GUI交互来过滤请求,查看请求数据mitmdump是命令行版本。启动后没有界面,无法提供过滤请求、查看数据的功能,只能结合自定义脚本来实现功能mitmproxy命令的交互操作稍显繁杂,我们主要的使用方式是载入自定义脚本,并不需要交互,所以只需要mitmdump即可安装:pip install mitmproxy运行命令:m...

mitmproxy是一个交互式的、支持SSL/TLS的拦截代理,启动后会提供一个命令行界面,用户可以实时看到发生的请求,并通过命令过滤请求,查看请求数据

mitmweb是一个基于web的mitmproxy界面。启动后会提供一个web界面,用户可以实时看到发生的请求,并通过GUI交互来过滤请求,查看请求数据

mitmdump是命令行版本。启动后没有界面,无法提供过滤请求、查看数据的功能,只能结合自定义脚本来实现功能

mitmproxy命令的交互操作稍显繁杂,我们主要的使用方式是载入自定义脚本,并不需要交互,所以只需要mitmdump即可

安装:pip install mitmproxy

运行命令:mitmdump -p port -h host后通过代理访问网址mitm.it,下载安装CA证书之后才能通过代理访问https网站

编写好python脚本以后使用命令"start /b mitmdump -p port -s path/script.py > nul"即可通过指定的端口使用代理实现拦截代理

最后使用命令"taskkill /f /t /im mitmdump*"关闭后台的代理服务

python脚本编写有两种方式

一、面向过程

import mitmproxy.http
from mitmproxy import ctx

num = 0
def request(flow: mitmproxy.http.HTTPFlow):
    global num
    num = num + 1
    ctx.log.info("We've seen %d flows" % num)

定义若干函数,这些函数实现了特定的的事件,mitmproxy会在某个事件发生时调用对应的函数

二、面向对象

import mitmproxy.http
from mitmproxy import ctx

class Counter:
    def __init__(self):
        self.num = 0

    def request(self, flow: mitmproxy.http.HTTPFlow):
        self.num = self.num + 1
        ctx.log.info("We've seen %d flows" % self.num)

addons = [
    Counter()
]

定义了数组变量addons,每个元素是一个类实例,这些类有若干方法,这些方法实现了特定的的事件,mitmproxy会在某个事件发生时调用对应的方法
这些类,称为一个个addon,如一个叫Counter的addon

建议使用第二种面向对象方式,会更容易管理和拓展

mitmproxy中的事件

针对HTTP生命周期

http_connect(flow: mitmproxy.http.HTTPFlow):收到了来自客户端的CONNECT请求
    CONNECT不是常用的HTTP请求方法,目的是与服务器建立代理连接,仅是client与proxy的之间的交流
    所以CONNECT请求不会触发request、response等其他常规的HTTP事件
    在flow上设置非2xx响应将返回该响应并断开连接

http_connect_upstream(flow: mitmproxy.http.HTTPFlow):CONNECT请求即将发送到上游代理
    此事件可用于为上游代理设置自定义身份验证标头

requestheaders(flow: mitmproxy.http.HTTPFlow):来自客户端的HTTP请求的头部被成功读取。此时flow中的request的body是空的

request(flow: mitmproxy.http.HTTPFlow):来自客户端的HTTP请求被成功完整读取

def responseheaders(flow: mitmproxy.http.HTTPFlow):来自服务端的HTTP响应的头部被成功读取。此时flow中的response的body是空的

def response(flow: mitmproxy.http.HTTPFlow):来自服务端的HTTP响应被成功完整读取

def error(flow: mitmproxy.http.HTTPFlow):发生了一个HTTP错误。如无效的服务端响应、连接断开等。注意与“有效的HTTP错误返回”不同,后者是一个正确的服务端响应,只是HTTP code表示错误而已

针对 TCP 生命周期

tcp_start(flow: mitmproxy.tcp.TCPFlow):建立了一个TCP连接

tcp_message(flow: mitmproxy.tcp.TCPFlow):TCP连接收到了一条消息,最近一条消息存于flow.messages[-1]。消息是可修改的
def tcp_error(flow: mitmproxy.tcp.TCPFlow):发生了TCP错误
def tcp_end(flow: mitmproxy.tcp.TCPFlow):TCP连接关闭

针对Websocket生命周期

websocket_handshake(flow: mitmproxy.http.HTTPFlow):客户端试图建立一个websocket连接

可以通过控制HTTP头部中针对websocket的条目来改变握手行为。flow的request属性保证是非空的

websocket_start(flow: mitmproxy.websocket.WebSocketFlow):建立了一个 websocket 连接。
websocket_message(flow: mitmproxy.websocket.WebSocketFlow):收到一条来自客户端或服务端的websocket消息

最近一条消息存于flow.messages[-1],是可修改的
目前有两种消息类型,BINARY类型或TEXT类型

websocket_error(flow: mitmproxy.websocket.WebSocketFlow):发生了websocket错误
websocket_end(flow: mitmproxy.websocket.WebSocketFlow):websocket连接关闭

针对网络连接生命周期

client_connected(client: mitmproxy.connection.Client):客户端连接到了mitmproxy。注意一条连接可能对应多个HTTP请求
client_disconnected(client: mitmproxy.connection.Client):客户端断开了和mitmproxy的连接
server_connected(data: mitmproxy.proxy.server_hooks.ServerConnectionHookData):mitmproxy连接到了服务端。注意一条连接可能对应多个HTTP请求
server_disconnected(data: mitmproxy.proxy.server_hooks.ServerConnectionHookData):mitmproxy断开了和服务端的连接

通用生命周期

configure(updated: typing.Set[str]):配置发生变化

updated参数是一个类似集合的对象,包含了所有变化了的选项
在mitmproxy启动时,该事件也会触发,且updated包含所有选项

done():addon关闭或被移除,又或者mitmproxy本身关闭

由于会先等事件循环终止后再触发该事件,所以这是一个addon可以看见的最后一个事件
此时log也已经关闭,所以此时调用log函数没有任何输出

load(Loader: mitmproxy.addonmanager.Loader):首次加载插件(addon第一次加载)时调用

此事件接收一个Loader对象,包含用于添加选项和命令的方法。此方法是插件配置自身的位置

log(entry: mitmproxy.log.LogEntry):通过mitmproxy.ctx.log产生了一条新日志。不要在这个事件内打日志,会造成死循环
running():mitmproxy完全启动并开始运行。此时mitmproxy已经绑定了端口,所有的addon都被加载了
update(flows: typing.Sequence[mitmproxy.flow.Flow]):一个或多个flow对象被修改了,通常是来自一个不同的addon

mitmproxy.http.Response.make(code:int,content:str,headers:dict)创建一个Response对象用于返回

类mitmproxy.http.HTTPFlow是表示单个HTTP事务的对象的集合,常用属性和方法

request:获取请求对象
response:获取响应对象
error:获取错误对象,通过msg属性查看错误描述,timestamp属性为错误的发生时间戳
websocket:获取所有关联的WebSocket数据
timestamp_start:流的开始时间,是mitmproxy.http.Request.timestamp_start的别名
killable:此流是否可以终止
live:流是否属于当前活动的连接(如流已完成或已从磁盘加载则返回False)
copy():创建副本
modified():此对象是否已被用户修改
backup():保存该对象的备份
revert():还原上次备份的状态
kill():杀死这个流。当前请求/响应不会转发到其目标
intercept():暂停处理此流
resume():继续处理流,用在intercept()之后

request对象和response对象

request和response拥有共同的Message父类,也就是说这两个对象拥有部分属性和方法是通用的

stream:bool,控制是否应流式传输消息正文
为False,mitmproxy将缓冲整个body,然后再转发到目的地(这样可以对body进行替换等操作)
为True,则消息正文不会在代理上缓冲,而是立即转发
必须在requestheaders或responseheaders事件中设置此属性,太晚则mitmproxy已经缓冲了消息体

http_version: HTTP协议版本,如"HTTP/1.1"
is_http10: 是否是HTTP的1.0版本
is_http11: 是否是HTTP的1.1版本
is_http2: 是否是HTTP的2.0版本
headers: HTTP标头
raw_content: bytes,原始(可能已压缩)HTTP消息正文(body),访问此属性永远不会异常
content: bytes,未压缩的HTTP消息正文(body),当HTTP内容编码无效时引发ValueError
text: str,未压缩和解码的HTTP消息正文(body)文本,当HTTP内容编码无效时引发ValueError

set_content(value: bytes): 设置HTTP消息正文(body)的值
get_content(strict: bool = True):同content属性,参数设为False则不会引发异常

set_text(text: str):设置HTTP消息正文(body)的值
get_text(strict: bool = True):同text属性,参数设为False则不会引发异常

timestamp_start: float,响应的开始时间戳
timestamp_end: float,,响应的结束时间戳

decode(strict: bool = True):根据内容编码标头解码正文,然后删除该标头

如果没有内容编码标头,则不执行任何操作
则当内容编码无效且参数为True时引发ValueError

encode(encoding: str):只用指定的编码对正文编码,内容不会事先解码,encoding可用的值"gzip"、 "deflate"、 "identity"、 "br" 或 "zstd"

requests对象的属性和方法

method:HTTP请求的方法
scheme:HTTP请求协议
authority:HTTP请求权限
host: 请求的主机头
host_header: 请求的主机(如果是HTTP/1.x)/颁发机构标头(如果是HTTP/2.0)
port: 目标端口
path: HTTP请求路径,常以斜杠开头
url: 完整的URL字符串,由scheme、host和path构造而成
pretty_host: 只读属性,类似于host,但是会以headers中的host标头作为首选值,具有欺骗性
pretty_url: 只读属性,类似于url,但是使用pretty_host代替host
query: 返回url中的查询映射,类似于字典,通过key的索引获取对应的值
cookies: 返回请求的Cookie,类似于字典,通过key的索引获取对应的值
path_components: path通过斜杠分割的元组
anticache():删除可能生成缓存的响应标头
anticomp():修改Accept-Encoding标头为仅接受未压缩的响应
constrain_encoding():根据当前的系统环境修改可以实现解码的Accept-Encoding标头值
urlencoded_form: URL编码的表单数据。类似于字典,如果无法分析或非表单数据则为空

response对象的属性和方法

status_code:HTTP状态码
reason: HTTP状态码的描述



网址导航