BaseProxy
異步http/https代理,可攔截並修改報文,可以作為中間人工具.僅支持py3.5+.項目地址:BaseProxy。
意義
BaseProxy項目的本意是為了使HTTP/HTTPS攔截更加純粹,更加易操作,學習成本更低。
在Python領域,中間人工具非常強大和成功的是MitmProxy,但是有些地方不是很喜歡。
- Windows上安裝比較費時費力
- 功能太多了,可惜我用不到這么多(似乎不是它的錯,哈哈)
- 隨着版本升級,采用插件化框架,需要定制功能,需要寫個插件成為它的一部分(我只是想集成它而已).
因此BaseProxy就誕生了,不僅支持HTTPS透明傳輸,還支持HTTP/HTTPS攔截,簡單易用,可以很好地集成到你們的項目中。
安裝
安裝非常簡單,本項目已經發布到PyPI中...
pip3 install baseproxy
使用配置
啟動baseproxy
在test文件夾下,有很多測試用例。以startserver.py為例。
from baseproxy.proxy import AsyncMitmProxy
baseproxy = AsyncMitmProxy(https=True)
baseproxy.serve_forever()
使用上述代碼,就可以將HTTPServer運行起來了.對代碼的解釋如下:
https=True
是對https進行解密;https=False
是對於https實行透傳- baseproxy默認運行在8788端口,如果想改變端口的話,修改為
AsyncMitmProxy(server_addr=('',port),https=True)
.
運行結果如下:
[2018-06-22 18:46:32] INFO HTTPServer is running at address( , 8788 )......
安裝CA證書
1.將chrome瀏覽器代理服務器設置為127.0.0.1:8788,推薦使用SwitchyOmega插件.
2.設置好代理,並將baseproxy運行后,訪問www.baidu.com.
3.這時候訪問被拒絕,需要安裝證書.在當前網頁訪問 baseproxy.ca,下載證書.
4.雙擊下載的證書,並安裝到合法機構中.
5.接着訪問百度就可以了.
注意:只有https=True
時,才需要安裝CA證書。
開發
經過上一步的使用配置,baseproxy已經可以正常運行了,但是這樣是遠遠不夠的.baseproxy還提供了接口,方便開發者對http請求和響應進行修改.
接口
baseproxy提供了兩個接口,一個是修改請求,一個是修改響應.
攔截請求
class ReqIntercept(InterceptPlug):
def deal_request(self,request):
pass
對於請求的攔截,需要繼承ReqIntercept類,並重寫其中的deal_request函數.在deal_request函數的最后,需要將修改后的request參數返回出去.
如果想拋棄這個請求,直接返回None.
request參數
deal_request函數中的request參數類型為Request類
成員變量
Name | 類型 | 含義 |
---|---|---|
hostname | str | 域名 |
port | int | 端口 |
command | str | 請求類型 |
path | str | 請求路徑 |
request_version | str | HTTP協議版本 |
成員函數
def set_headers(self,headers)
- headers:類型為dict
- 用於設置頭部
def get_header(self,key):
- key:類型為str
- 用於獲取指定頭部,返回str
def get_headers(self):
- 用於獲取整個頭部,返回為dict
def set_header(self,key,value):
- 頭部 key,類型str
- 頭部 value,類型str
- 用於設置頭信息
def get_body_data(self):
- 獲取請求體內容,返回類型為bytes
def set_body_data(self,body):
- 設置請求體內容,body類型為bytes
攔截響應
class RspIntercept(InterceptPlug):
def deal_response(self,response):
pass
對於響應的攔截,需要繼承RspIntercept類,並重寫其中的deal_response函數.在deal_response函數的最后,需要將修改后的response參數返回出去.
如果想拋棄這個響應,直接返回None.
response參數
deal_response函數中的response參數類型為Response類
成員變量
Name | 類型 | 含義 |
---|---|---|
hostname | str | 域名 |
port | int | 端口 |
status | int | 狀態碼 |
reason | str | 狀態描述 |
response_version | str | HTTP協議版本 |
request | Request | 響應對應的請求實例 |
成員函數
def set_headers(self,headers)
- headers:類型為dict
- 用於設置頭部
def get_header(self,key):
- key:類型為str
- 用於獲取指定頭部,返回str
def get_headers(self):
- 用於獲取整個頭部,返回為dict
def set_header(self,key,value):
- 頭部 key,類型str
- 頭部 value,類型str
- 用於設置頭信息
def get_body_data(self):
- 獲取響應體內容,返回類型為bytes
def set_body_data(self,body):
- 設置響應體內容,body類型為bytes
def get_body_str(self,decoding=None):
- decoding:編碼,默認為None,內部采用chardet探測
- 返回響應體,類型為str.如果無法解碼,返回None
def set_body_str(self,body_str,encoding=None):
- encoding:編碼,默認為None,內部采用chardet探測
- 設置響應體,body_str類型為str
注冊攔截插件
將攔截類完成后,需要注冊到baseproxy中,需要調用AsyncMitmProxy的register函數.示例如下:
from baseproxy.proxy import ReqIntercept, RspIntercept, AsyncMitmProxy
__author__ = 'qiye'
__date__ = '2018/6/21 23:35'
class DebugInterceptor(ReqIntercept, RspIntercept):
def deal_request(self, request):
return request
def deal_response(self, response):
return response
if __name__=="__main__":
baseproxy = AsyncMitmProxy(https=False)
baseproxy.register(DebugInterceptor)
baseproxy.serve_forever()
小例子
將淘寶中的所有產品圖片換成我公眾號的二維碼.代碼在test文件夾的replace_image.py中,內容如下:
from baseproxy.proxy import RspIntercept, AsyncMitmProxy
class ImageInterceptor( RspIntercept):
def deal_response(self, response):
if response.get_header("Content-Type") and 'image' in response.get_header("Content-Type"):
with open("../img/qiye2.jpg",'rb') as f:
response.set_body_data(f.read())
return response
if __name__ == "__main__":
baseproxy = AsyncMitmProxy(https=True)
baseproxy.register(ImageInterceptor)
baseproxy.serve_forever()
效果如下:
參考項目
福利大放送
關注公眾號:七夜安全博客
- 回復【1】:領取 Python數據分析 教程大禮包
- 回復【2】:領取 Python Flask 全套教程
- 回復【3】:領取 某學院 機器學習 教程
- 回復【4】:領取 爬蟲 教程
知識星球已經50人了,隨着人數的增多,價格之后會上漲,越早關注越多優惠。星球的福利有很多:
- 比如上面的教程,已經提前在知識星球中分享
- 可以發表一些問題,大家一塊解決
- 我之后寫的電子書,錄制的教學視頻,對於知識星球的朋友都是優惠的(基本上免費)
- 一些節假日會給大家發個紅包或者贈書