zoukankan      html  css  js  c++  java
  • MitmProxy使用:http/https劫持脚本开发

    如何编写一个插件

    插件的作用主要是用于拦截请求,根据自身业务需求,在不同的事件函数中,添加业务逻辑处理代码。插件的编写格式相对比较简单,如果不熟悉如何编写,可参考官方样例:https://github.com/mitmproxy/mitmproxy/blob/master/examples/addons进行模仿,这里摘取其中一个增加响应头部信息的样例,anatomy.py如下:

    from mitmproxy import ctx

    class
    AddHeader: def __init__(self): self.num = 0 //这里选择所需要处理的事件函数,e.g. 如对 response 进行处理 def response(self, flow): self.num = self.num + 1 flow.response.headers["count"] = str(self.num)
         ctx.log.info("We've seen %d flows"%self.num)
    //这个是固定格式 addons = [ AddHeader() ]
    在命令行输入:mitmproxy -s anatomy.py。

    事件

    mitmproxy 插件编写主要是基于事件可以在不同层面上分为 5 类:HTTP、TCP、WebSocket、Network、General。
     
    其中最常用的就是HTTP事件,包括:
    def http_connect(self, flow: mitmproxy.http.HTTPFlow):
        """
            (Called when) 收到了来自客户端的 HTTP CONNECT 请求。在 flow 上设置非 2xx 响应将返回该响应并断开连接。CONNECT 不是常用的 HTTP 请求方法,目的是与服务器建立代理连接,仅是 client 与 proxy 的之间的交流,所以 CONNECT 请求不会触发 request、response 等其他常规的 HTTP 事件
        """
    
    def requestheaders(self, flow: mitmproxy.http.HTTPFlow):
        """
            (Called when) 来自客户端的 HTTP 请求的头部被成功读取。此时 flow 中的 request 的 body 是空的。
        """
    
    def request(self, flow: mitmproxy.http.HTTPFlow):
        """
            (Called when) 来自客户端的 HTTP 请求被成功完整读取。
        """
    
    def responseheaders(self, flow: mitmproxy.http.HTTPFlow):
        """
            (Called when) 来自服务端的 HTTP 响应的头部被成功读取。此时 flow 中的 response 的 body 是空的。
        """
    
    def response(self, flow: mitmproxy.http.HTTPFlow):
        """
            (Called when) 来自服务端端的 HTTP 响应被成功完整读取。
        """
    
    def error(self, flow: mitmproxy.http.HTTPFlow):
        """
            (Called when) 发生了一个 HTTP 错误。比如无效的服务端响应、连接断开等。注意与“有效的 HTTP 错误返回”不是一回事,后者是一个正确的服务端响应,只是 HTTP code 表示错误而已。
        """

    核心 API 

    mitmproxy.http.HTTPRequest

    • cookies

      返回一个MultiDictView对象

    • get_content(strict: bool = True) → bytes
      使用内容编码标头(例如gzip)解码的HTTP消息正文
    • get_text(strict: bool = True) → typing.Union[str, NoneType]
      使用内容编码标头(例如gzip)和内容类型标头字符集解码的HTTP消息正文。
    • headers
      返回mitmproxy.net.http.Headers对象
    • multipart_form
      多部分表单数据作为MultiDictView对象。
      键和值都是bytes。
    • pretty_url:拦截的url路径
    • urlencoded_form
      URL编码的表单数据作为MultiDictView对象。
    • replace(pattern, repl, flags=0, count=0)
      将header,请求路径和请求体中的repl替换为正则表达式模式。编码后的内容将在替换前进行解码,然后再进行编码。

    mitmproxy.http.HTTPResponse

    • make(status_code: int = 200, content: AnyStr = b'', headers: typing.Union[typing.Dict[AnyStr, AnyStr], typing.Iterable[typing.Tuple[bytes, bytes]]] = ())
      用于创建response对象的简化API。
    • status_code
      状态码
    • 大部分和mitmproxy.http.HTTPRequest差不多

    mitmproxy.http.HTTPFlow

    HTTPFlow是代表单个HTTP事务的对象的集合

    • request
    • response

    mitmproxy.log.Log

    中央记录器,在脚本中暴露为mitmproxy.ctx.log

    • debug
    • info
    • warn
    • error

    HTTP脚本

    拦截篡改 http 请求的工具类,包含的功能主要有:

    • 拦截请求并请求 header 信息
    • 拦截请求及修改 body 信息
    • 拦截请求方法及修改类型,e.g. get/post
    • 拦截请求及修改 query 参数
    • 拦截响应并修改响应状态码
    • 拦截响应并修改响应头信息
    • 拦截响应并修改响应正文信息
    • 拦截响应并构造响应信息,e.g. 状态码、响应头、响应体
    class HTTPRecordModifier:
    
        def __init__(self, flow: http.HTTPFlow):
            self.flow = flow
        //设置请求头信息
        def set_request_header(self, headers):
            for header_key, header_value in headers.items():
                self.flow.request.headers[header_key] = header_value
    
        //设置请求 body 参数
        def set_request_body(self, body):
            self.flow.request.content = bytes(body, "utf-8")
    
        //设置请求方法
        def set_request_method(self, method):
            self.flow.request.method = method
    
        //设置请求 query 参数
        def set_request_query(self, key, value):
            self.flow.request.query[key] = value
    
        //设置响应状态码
        def set_response_status_code(self, code):
            self.flow.response.status_code = code
    
        //设置响应头信息
        def set_response_header(self, headers):
            for header_key, header_value in headers.items():
                self.flow.response.headers[header_key] = header_value
    
         //设置响应体内容
        def set_response_body(self, body):
            self.flow.response.content = bytes(body, "utf-8")
    
        //构造响应报文
        def create_mocked_response(self, code=200, header={}, body=""):
            self.flow.response = http.HTTPResponse.make(code, bytes(body, "utf-8"), header)
    class Test:
    
        def response(self, flow: http.HTTPFlow):
            """
            Event for handling response before sending it back to the client
            """
            //这里编写我们的 mock 逻辑代码
            breakpoint_url = "https://frodo.douban.com/api/v2/user/91807076/following"
            if breakpoint_url in flow.request.pretty_url:
                response_content = json.loads(flow.response.content.decode("utf-8"))
                response_content['total'] = 20
                new_response = HTTPRecordModifier(flow)
                userinfo = {
                    //这里放置上面抓包获取的用户信息格式
                   }
                for i in range(response_content['total']):
                    //添加 20 个用户信息
                    response_content['users'].append(userinfo)
                new_response.set_response_body(json.dumps(response_content))
    
    addons = [
        Test()
    ]

    启动 mitmproxy 插件脚本,如下:

     mitmdump -s 插件的脚本名字

  • 相关阅读:
    python操作pymysql
    使用raise语句抛出异常
    异常处理
    01.正太分布模型
    常用正则表达式总结(47条)
    Scrapy项目_苏宁图书信息
    Scrapy项目_阳光热线问政平台
    Scrapy 项目:腾讯招聘
    Python爬虫_糗事百科
    Python爬虫_百度贴吧(title、url、image_url)
  • 原文地址:https://www.cnblogs.com/-wenli/p/13940591.html
Copyright © 2011-2022 走看看