主題
修改request或者response內容
介紹
mitmdump無交互界面的命令,與python腳本對接,來源於mitmproxy支持inline script,這里的script指的是python腳本,inline script提供了http、Websocket、tcp等各個時間點事件(events)的hook函數,如http中的request、response等
主要events一覽表
需要修改各種事件內容時,重寫以下對應方法,這里主要用的是request、response方法
import typing
import mitmproxy.addonmanager
import mitmproxy.connections
import mitmproxy.http
import mitmproxy.log
import mitmproxy.tcp
import mitmproxy.websocket
import mitmproxy.proxy.protocol
class Events:
# HTTP lifecycle
def http_connect(self, flow: mitmproxy.http.HTTPFlow):
"""
An HTTP CONNECT request was received. Setting a non 2xx response on
the flow will return the response to the client abort the
connection. CONNECT requests and responses do not generate the usual
HTTP handler events. CONNECT requests are only valid in regular and
upstream proxy modes.
"""
def requestheaders(self, flow: mitmproxy.http.HTTPFlow):
"""
HTTP request headers were successfully read. At this point, the body
is empty.
"""
def request(self, flow: mitmproxy.http.HTTPFlow):
"""
The full HTTP request has been read.
"""
def responseheaders(self, flow: mitmproxy.http.HTTPFlow):
"""
HTTP response headers were successfully read. At this point, the body
is empty.
"""
def response(self, flow: mitmproxy.http.HTTPFlow):
"""
The full HTTP response has been read.
"""
def error(self, flow: mitmproxy.http.HTTPFlow):
"""
An HTTP error has occurred, e.g. invalid server responses, or
interrupted connections. This is distinct from a valid server HTTP
error response, which is simply a response with an HTTP error code.
"""
# TCP lifecycle
def tcp_start(self, flow: mitmproxy.tcp.TCPFlow):
"""
A TCP connection has started.
"""
def tcp_message(self, flow: mitmproxy.tcp.TCPFlow):
"""
A TCP connection has received a message. The most recent message
will be flow.messages[-1]. The message is user-modifiable.
"""
def tcp_error(self, flow: mitmproxy.tcp.TCPFlow):
"""
A TCP error has occurred.
"""
def tcp_end(self, flow: mitmproxy.tcp.TCPFlow):
"""
A TCP connection has ended.
"""
# Websocket lifecycle
def websocket_handshake(self, flow: mitmproxy.http.HTTPFlow):
"""
Called when a client wants to establish a WebSocket connection. The
WebSocket-specific headers can be manipulated to alter the
handshake. The flow object is guaranteed to have a non-None request
attribute.
"""
def websocket_start(self, flow: mitmproxy.websocket.WebSocketFlow):
"""
A websocket connection has commenced.
"""
def websocket_message(self, flow: mitmproxy.websocket.WebSocketFlow):
"""
Called when a WebSocket message is received from the client or
server. The most recent message will be flow.messages[-1]. The
message is user-modifiable. Currently there are two types of
messages, corresponding to the BINARY and TEXT frame types.
"""
def websocket_error(self, flow: mitmproxy.websocket.WebSocketFlow):
"""
A websocket connection has had an error.
"""
def websocket_end(self, flow: mitmproxy.websocket.WebSocketFlow):
"""
A websocket connection has ended.
"""
# Network lifecycle
def clientconnect(self, layer: mitmproxy.proxy.protocol.Layer):
"""
A client has connected to mitmproxy. Note that a connection can
correspond to multiple HTTP requests.
"""
def clientdisconnect(self, layer: mitmproxy.proxy.protocol.Layer):
"""
A client has disconnected from mitmproxy.
"""
def serverconnect(self, conn: mitmproxy.connections.ServerConnection):
"""
Mitmproxy has connected to a server. Note that a connection can
correspond to multiple requests.
"""
def serverdisconnect(self, conn: mitmproxy.connections.ServerConnection):
"""
Mitmproxy has disconnected from a server.
"""
def next_layer(self, layer: mitmproxy.proxy.protocol.Layer):
"""
Network layers are being switched. You may change which layer will
be used by returning a new layer object from this event.
"""
# General lifecycle
def configure(self, updated: typing.Set[str]):
"""
Called when configuration changes. The updated argument is a
set-like object containing the keys of all changed options. This
event is called during startup with all options in the updated set.
"""
def done(self):
"""
Called when the addon shuts down, either by being removed from
the mitmproxy instance, or when mitmproxy itself shuts down. On
shutdown, this event is called after the event loop is
terminated, guaranteeing that it will be the final event an addon
sees. Note that log handlers are shut down at this point, so
calls to log functions will produce no output.
"""
def load(self, entry: mitmproxy.addonmanager.Loader):
"""
Called when an addon is first loaded. This event receives a Loader
object, which contains methods for adding options and commands. This
method is where the addon configures itself.
"""
def log(self, entry: mitmproxy.log.LogEntry):
"""
Called whenever a new log entry is created through the mitmproxy
context. Be careful not to log from this event, which will cause an
infinite loop!
"""
def running(self):
"""
Called when the proxy is completely up and running. At this point,
you can expect the proxy to be bound to a port, and all addons to be
loaded.
"""
def update(self, flows: typing.Sequence[mitmproxy.flow.Flow]):
"""
Update is called when one or more flow objects have been modified,
usually from a different addon.
"""
針對http,常用的API
http.HTTPFlow 實例 flow
flow.request.headers #獲取所有頭信息,包含Host、User-Agent、Content-type等字段
flow.request.url #完整的請求地址,包含域名及請求參數,但是不包含放在body里面的請求參數
flow.request.pretty_url #同flow.request.url目前沒看出什么差別
flow.request.host #域名
flow.request.method #請求方式。POST、GET等
flow.request.scheme #什么請求 ,如https
flow.request.path # 請求的路徑,url除域名之外的內容
flow.request.get_text() #請求中body內容,有一些http會把請求參數放在body里面,那么可通過此方法獲取,返回字典類型
flow.request.query #返回MultiDictView類型的數據,url直接帶的鍵值參數
flow.request.get_content()#bytes,結果如flow.request.get_text()
flow.request.raw_content #bytes,結果如flow.request.get_content()
flow.request.urlencoded_form #MultiDictView,content-type:application/x-www-form-urlencoded時的請求參數,不包含url直接帶的鍵值參數
flow.request.multipart_form #MultiDictView,content-type:multipart/form-data
時的請求參數,不包含url直接帶的鍵值參數
以上均為獲取request信息的一些常用方法,對於response,同理
flow.response.status_code #狀態碼
flow.response.text#返回內容,已解碼
flow.response.content #返回內容,二進制
flow.response.setText()#修改返回內容,不需要轉碼
以上為不完全列舉
示例
修改response內容,這里是服務器已經有返回了結果,再更改,也可以做不經過服務器處理,直接返回,看需求
def response(flow:http.HTTPFlow)-> None:
#特定接口需要返回1001結果
interface_list=["page/**"] #由於涉及公司隱私問題,隱藏實際的接口
url_path=flow.request.path
if url_path.split("?")[0] in interface_list:
ctx.log.info("#"*50)
ctx.log.info("待修改路徑的內容:"+url_path)
ctx.log.info("修改成:1001錯誤返回")
ctx.log.info("修改前:\n")
ctx.log.info(flow.response.text)
flow.response.set_text(json.dumps({"result":"1001","message":"服務異常"}))#修改,使用set_text不用轉碼
ctx.log.info("修改后:\n")
ctx.log.info(flow.response.text)
ctx.log.info("#"*50)
elif flow.request.host in host_list:#host_list 域名列表,作為全局變量,公司有多個域名,也隱藏
ctx.log.info("response= "+flow.response.text)
應用
移動app測試中,為了測試app的容錯能力,在不改動數據庫或者折騰服務器的情況下,腳本修改request或者response內容【這里也可以選擇第三方工具,如fiddler同樣支持,看個人需求】,查看app的表現;亦或是根據接口定義檢查app的接口請求情況
作者:小蝸牛的成長
鏈接:https://www.jianshu.com/p/a495cc016682
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權並注明出處。
