Python基于Mitmproxy实现被动式浏览器请求抓取与解析
本文介绍如何利用Python结合Mitmproxy库构建被动式代理,以捕获浏览器发出的HTTP/HTTPS请求。内容涵盖环境安装、目录结构配置及核心代码实现,重点解析如何过滤静态资源并提取请求关键信息,适用于安全扫描器开发场景。
项目背景与工具选择
近期开发一款基于被动模式的漏洞扫描器,其核心机制是捕获用户在浏览器浏览过程中发出的网络请求,并将这些数据交由扫描器进行后续处理。起初考虑自行编写代理程序,但由于需要支持HTTPS协议的抓取,最终选择了功能完善的Mitmproxy工具。
环境安装与目录结构
安装步骤如下:
执行命令:pip install mitmproxy
随后通过一个具体案例来演示其使用方式,项目目录结构如下所示:
sproxy
|utils
|__init__.py
|parser.py
|sproxy.py
核心代码实现
sproxy.py主要代码实现如下:
#coding=utf-8
from pprint import pprint
from mitmproxy import flow, proxy, controller, options
from mitmproxy.proxy.server import ProxyServer
from utils.parser import ResponseParser
# http static resource file extension
static_ext = ['js', 'css', 'ico', 'jpg', 'png', 'gif', 'jpeg', 'bmp']
# media resource files type
media_types = ['image', 'video', 'audio']
# url filter
url_filter = ['baidu','360','qq.com']
static_files = [
'text/css',
'image/jpeg',
'image/gif',
'image/png',
]
class WYProxy(flow.FlowMaster):
def __init__(self, opts, server, state):
super(WYProxy, self).__init__(opts, server, state)
def run(self):
try:
pprint("proxy started successfully...")
flow.FlowMaster.run(self)
except KeyboardInterrupt:
pprint("Ctrl C - stopping proxy")
self.shutdown()
def get_extension(self, flow):
if not flow.request.path_components:
return ''
else:
end_path = flow.request.path_components[-1:][0]
split_ext = end_path.split('.')
if not split_ext or len(split_ext) == 1:
return ''
else:
return split_ext[-1:][0][:32]
def capture_pass(self, flow):
# filter url
url = flow.request.url
for i in url_filter:
if i in url:
return True
"""if content_type is media_types or static_files, then pass captrue"""
extension = self.get_extension(flow)
if extension in static_ext:
return True
# can't catch the content_type
content_type = flow.response.headers.get('Content-Type', '').split(';')[:1][0]
if not content_type:
return False
if content_type in static_files:
return True
http_mime_type = content_type.split('/')[:1]
if http_mime_type:
return True if http_mime_type[0] in media_types else False
else:
return False
@controller.handler
def request(self, f):
pass
@controller.handler
def response(self, f):
try:
if not self.capture_pass(f):
parser = ResponseParser(f)
result = parser.parser_data()
if f.request.method == "GET":
print result['url']
elif f.request.method == "POST":
print result['request_content'] # POST提交的参数
except Exception as e:
raise e
@controller.handler
def error(self, f):
pass
# print("error", f)
@controller.handler
def log(self, l):
pass
# print("log", l.msg)
def start_server(proxy_port, proxy_mode):
port = int(proxy_port) if proxy_port else 8090
mode = proxy_mode if proxy_mode else 'regular'
if proxy_mode == 'http':
mode = 'regular'
opts = options.Options(
listen_port=port,
mode=mode,
cadir="~/.mitmproxy/",
)
config = proxy.ProxyConfig(opts)
state = flow.State()
server = ProxyServer(config)
m = WYProxy(opts, server, state)
m.run()
if __name__ == '__main__':
start_server("8090", "http")
parser.py模块代码:
# from __future__ import absolute_import
class ResponseParser(object):
"""docstring for ResponseParser"""
def __init__(self, f):
super(ResponseParser, self).__init__()
self.flow = f
def parser_data(self):
result = dict()
result['url'] = self.flow.request.url
result['path'] = '/{}'.format('/'.join(self.flow.request.path_components))
result['host'] = self.flow.request.host
result['port'] = self.flow.request.port
result['scheme'] = self.flow.request.scheme
result['method'] = self.flow.request.method
result['status_code'] = self.flow.response.status_code
result['content_length'] = int(self.flow.response.headers.get('Content-Length', 0))
result['request_header'] = self.parser_header(self.flow.request.headers)
result['request_content'] = self.flow.request.content
return result
@staticmethod
def parser_multipart(content):
if isinstance(content, str):
res = re.findall(r'name=\"(\w+)\"\r\n\r\n(\w+)', content)
if res:
return "&".join([k + '=' + v for k, v in res])
else:
return ""
else:
return ""
@staticmethod
def parser_header(header):
headers = {}
for key, value in header.items():
headers[key] = value
return headers
@staticmethod
def decode_response_text(content):
for _ in ['UTF-8', 'GB2312', 'GBK', 'iso-8859-1', 'big5']:
try:
return content.decode(_)
except:
continue
return content
参考资料与总结
参考链接:
https://github.com/ring04h/wyproxy
以上关于Python使用Mitmproxy抓取浏览器请求的方法分享完毕,希望能为读者提供有价值的参考,欢迎继续支持本站获取更多技术内容。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









