python+mitmproxy 如何在一百行代码实现拦截本地HTTP和HTTPS协议请求

前置: 本次代码均为可执行示例,将所有依赖安装完成后 可直接执行
可能出现的问题:
1. 之前未开启过本地代理 可能会报错.需要在本地设置代理里 开启一次
2. 缺少依赖 将文件内使用到的依赖全部安装即可
3. 端口冲突.本地已启动占用该配置端口的服务 导致端口冲突无法启动 更改端口即可
4. 服务停止后 仍然无法连接网络 代码内已对强杀信号做了拦截 但是不排除会有其他问题导致程序异常所以未在服务停止时将本地代理关闭 所以需要手动前往设置 代理处关闭
三方依赖: requirements.txt

asyncio
json
sys
winreg
ctypes
signal
mitmproxy
loguru

使用pipinstall -r 命令批量安装即可
建议使用Python版本:3.8+

示例

import asyncio
import json
import sys
import winreg
import ctypes
import signal
from mitmproxy import addons
from mitmproxy.http import HTTPFlow
from mitmproxy.options import Options
from mitmproxy.master import Master
from mitmproxy.addons import dumper, errorcheck, keepserving, readfile, termlog
from loguru import logger
# 这里是读取配置文件 如果后续不使用配置文件的话 可以注释掉 在最下方直接传参
with open('./application.json', 'r', encoding='utf-8') as f:
    conf = json.load(f)

# ProxyLocal 本地代理类
class ProxyLocal:
	# 加载本地配置 为了修改本地代理
    INTERNET_SETTINGS = winreg.OpenKey(winreg.HKEY_CURRENT_USER,
                                       r'Software\Microsoft\Windows\CurrentVersion\Internet Settings',
                                       0, winreg.KEY_ALL_ACCESS)
    # 设置刷新
    INTERNET_OPTION_REFRESH = 37
    INTERNET_OPTION_SETTINGS_CHANGED = 39
    internet_set_option = ctypes.windll.Wininet.InternetSetOptionW
	# 修改配置的键值对
    def set_key(self, name, value):
        # 修改键值
        _, reg_type = winreg.QueryValueEx(self.INTERNET_SETTINGS, name)
        winreg.SetValueEx(self.INTERNET_SETTINGS, name, 0, reg_type, value)

    def updateProxy(self, proxy: dict):
        # 启用代理 可设置多个参数
        for k, v in proxy.items():
            self.set_key(k, v)  
        # 启用
        self.internet_set_option(0, self.INTERNET_OPTION_REFRESH, 0, 0)
        self.internet_set_option(0, self.INTERNET_OPTION_SETTINGS_CHANGED, 0, 0)

# 这里重写Master类 是为了解决在python中运行DumMaster方法报错 No running event loop 的错误
# 原始方法中 并未开放对事件轮询的入参 所以这里有可能是源码的bug 也有可能有其他的入口参数 
class Masters(Master):
    # 重写创建服务的继承类 开放事件循环
    def __init__(
            self,
            options: Options,
            with_termlog=True,
            with_dumper=True,
            evn_loop: asyncio.AbstractEventLoop = None
    ) -> None:
        super().__init__(options, event_loop=evn_loop)
        if with_termlog:
            self.addons.add(termlog.TermLog())
        self.addons.add(*addons.default_addons())
        if with_dumper:
            self.addons.add(dumper.Dumper())
        self.addons.add(
            keepserving.KeepServing(),
            readfile.ReadFileStdin(),
            errorcheck.ErrorCheck(),
        )

# 这里是插件类, 也是后续框架执行的过程中进行拦截的一些操作  主要逻辑就在这里,过滤 打印 记录等 都在这个方法里
# 名称固定为response
class PrintRequestsUrl:
    def response(self, flow: HTTPFlow):
        requestsInfo = {
            'url': flow.request.url,
            'scheme': flow.request.data.scheme,
            'headers': flow.request.headers,
            'methods': flow.request.method
        }
        logger.info(f"拦截到的请求:{requestsInfo}")
        responseInfo = {
            'status': flow.response.status_code,
            'data': flow.response.text,
            'headers': flow.response.headers
        }
        logger.info(f'这里是响应{responseInfo}')

# 入口方法
def run(Host: str, Port: int, log: bool = False):
    # 开启本地代理
    proxy = ProxyLocal()
    # 更新配置
    proxy.updateProxy(
        {
        	# 1是开启 0是关闭
            "ProxyEnable": 1,
            "ProxyOverride": u'*.local;<local>', # 绕过本地
            "ProxyServer": u"%s:%d" % (Host, Port) # 设置需要配置的代理ip+端口
        }
    )
    p = PrintRequestsUrl() # 示例化插件类
    # Options 是配置 可选 具体参数可以点进Options中查看所有配置项
    opts = Options(listen_host=Host, listen_port=Port, add_upstream_certs_to_client_chain=True)
    loop = asyncio.get_event_loop() # 获取异步事件循环
	# 实例化执行主类
    m = Masters(options=opts, evn_loop=loop, with_termlog=log)
	# 将差距类示例注册到框架执行的步骤中
    m.addons.add(p)
    logger.info(f'当前代理配置为:{Host}:{Port},拦截本地请求开始')
    signal_handler(m, proxy) # 这里是监听系统的一些信号 例如Kill命令 和ctrl+c关闭
    loop.run_until_complete(asyncio.wait([m.run()])) # 阻塞执行异步事件 等待Coroutine和Task执行完成


def signal_handler(m: Masters, p: ProxyLocal):
    SIG_List = [signal.SIGINT, signal.SIGTERM] # 其余信号源可以查看源码中的说明;
	# 回调方法. 当信号执行后 signal中执行的方法
    def handler(num, f):
        logger.info('服务即将关闭,正在准备服务资源回收,关闭代理服务以及关闭本地代理')
        m.shutdown() # 关闭代理服务
        p.updateProxy({
            "ProxyEnable": 0
        }) #  将本地代理关闭
        logger.info('资源已回收,正在关闭残留线程')
        sys.exit()# 退出进程

    for s in SIG_List:
        signal.signal(s, handler)


if __name__ == '__main__':
    run(conf['host'], conf['port'])

总结:
mitmproxy 不单单可以进行请求拦截 也可以作用在正反向代理,以及中间人攻击等场景中
同时我们在工作中会经常运用到一些抓包工具 但是在一些自动化操作中又无法进行手动抓包时 就可以通过mitmproxy 对本地代理进行请求拦截 进而过滤出一些我们想要的接口来 或者进行一些中间人攻击操作

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
可以使用mitmproxy库来实现Python中的代理功能。首先,你需要创建一个名为addons.py的文件,并在其中编写以下代码: ```python from mitmproxy import ctx class Counter: def request(self): ctx.log.info('we have seen') with open('1.txt', 'a', encoding='utf-8') as f: f.write('we have seen') addons = [ Counter() ] ``` 然后,在命令中执以下命令来启动mitmdump并加载addons.py文件: ``` mitmdump -s addons.py ``` 这样,你就可以拦截任意请求并进处理了。如果遇到了`ImportError: cannot import name 'soft_unicode' from 'markupsafe'`的错误,可以尝试更新markupsafe库的版本为2.01。 总结来说,mitmproxy不仅可以用于请求拦截,还可以用于正向和反向代理,以及中间人攻击等场景。在工作中,我们经常会使用抓包工具,但在一些自动化操作中无法进手动抓包时,可以使用mitmproxy对本地代理进请求拦截,从而过滤出我们想要的接口或进中间人攻击操作。 在使用mitmdump启动后,会在`C:\Users\85025\.mitmproxy`目录下生成一些证书文件,这些文件的作用如下: - `mitmproxy-ca.pem`:PEM格式的证书私钥 - `mitmproxy-ca-cert.pem`:PEM格式的证书,适用于大多数非Windows平台 - `mitmproxy-ca-cert.p12`:PKCS12格式的证书,适用于Windows平台 - `mitmproxy-ca-cert.cer`:与`mitmproxy-ca-cert.pem`相同,只是改变了后缀,适用于部分Android平台 - `mitmproxy-dhparam.pem`:PEM格式的秘钥文件,用于增强SSL安全性 这些证书文件可以用于配置SSL代理,以实现更安全的通信。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值