1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        一探究竟!Whistle攔截HTTPS是如何實現(xiàn)的?

        共 5714字,需瀏覽 12分鐘

         ·

        2021-12-23 10:17


        導(dǎo)語?|?本文主要介紹Whistle的實現(xiàn)原通過這篇文章讀者可以了解Whistle的具體實現(xiàn)過程,并且自己也可以實現(xiàn)一個簡單的抓包調(diào)試工具。


        項目Github地址:https://github.com/avwo/whistle


        Whistle是基于Node實現(xiàn)的跨平臺Web抓包調(diào)試(HTTP)代理,主要功能:


        • 實時抓包:支持HTTP、HTTPS、HTTP2、WebSocket、TCP等常見Web請求


        • 修改請求響應(yīng):與一般抓包調(diào)試工具采用斷點的方式不同,Whistle采用類似系統(tǒng)host的配置規(guī)則方式


        • 擴展功能:支持通過Node編寫插件,或作為獨立NPM包引入項目兩種擴展方式



        本文將從最基本的概念開始逐步實現(xiàn)Whistle功能,包含以下內(nèi)容:


        • 什么是HTTP代理


        • 實現(xiàn)簡單HTTP代理


        • 完整HTTP代理架構(gòu)(Whistle)


        • 各個模塊的實現(xiàn)原理


        • 參考資料



        一、什么是HTTP代理



        代理是客戶端到服務(wù)端的中轉(zhuǎn)服務(wù),其中:


        • 不經(jīng)過代理的請求:客戶端和服務(wù)端直接建立連接后,即可開始交換數(shù)據(jù)


        • 經(jīng)過代理的請求:客戶端不與服務(wù)端直接建立連接,而是先跟代理建立連接后,將目標(biāo)服務(wù)器的地址發(fā)送給代理,通過代理再跟服務(wù)端建立連接,這里如果代理服務(wù)為HTTP Server,則稱為HTTP代理。


        接下來看下客戶端如何將目標(biāo)服務(wù)器地址傳給HTTP代理,以及HTTP代理如何跟目標(biāo)服務(wù)器建立連接。



        二、實現(xiàn)簡單HTTP代理


        先看一個用Node實現(xiàn)的最簡單HTTP代理:


        const http = require('http');const { connect } = require('net');
        /****************** 工具方法 ******************/const getHostPort = (host, defaultPort) => { let port = defaultPort || 80; const index = host.indexOf(':'); if (index !== -1) { port = host.substring(index + 1); host = host.substring(0, index); } return {host, port};};
        const getOptions = (req, defaultPort) => { // 這里假定 host 一定存在,完整實現(xiàn)參見 Whistle const { host, port } = getHostPort(req.headers.host, defaultPort); return { hostname: host, // 指定請求域名,用于通過 DNS 獲取服務(wù)器 IP 及設(shè)置請求頭 host 字段 port, // 指定服務(wù)器端口 path: req.url || '/', method: req.method, headers: req.headers, rejectUnauthorized: false, // 給 HTTPS 請求用的,HTTP 請求會自動忽略 };};
        // 簡單處理,出錯直接斷開,完整實現(xiàn)邏輯參考 Whistleconst handleClose = (req, res) => { const destroy = (err) => { // 及時關(guān)閉無用的連接,防止內(nèi)存泄露 req.destroy(); res && res.destroy(); }; res && res.on('error', destroy); req.on('error', destroy); req.once('close', destroy);};
        /****************** 服務(wù)代碼 ******************/const server = http.createServer();// 處理 HTTP 請求server.on('request', (req, res) => { // 與服務(wù)端建立連接,透傳客戶端請求及服務(wù)端響應(yīng)內(nèi)容 const client = http.request(getOptions(req), (svrRes) => { res.writeHead(svrRes.statusCode, svrRes.headers); svrRes.pipe(res); }); req.pipe(client); handleClose(res, client);});
        // 隧道代理:處理 HTTPS、HTTP2、WebSocket、TCP 等請求server.on('connect', (req, socket) => { // 與服務(wù)端建立連接,透傳客戶端請求及服務(wù)端響應(yīng)內(nèi)容 const client = connect(getHostPort(req.url), () => { socket.write('HTTP/1.1 200 Connection Established\r\n\r\n'); socket.pipe(client).pipe(socket); }); handleClose(socket, client);});
        server.listen(8080);


        上述代碼實現(xiàn)了一個具有轉(zhuǎn)發(fā)請求功能的HTTP代理,從代碼可知HTTP代理就是一個普通的HTTP Server,并監(jiān)聽request和connect這兩個事件,客戶端會通過這兩個事件將目標(biāo)服務(wù)器地址傳過來,其中:


        • request:一般普通HTTP會通過該事件將目標(biāo)服務(wù)器地址傳過來。


        • connect:一般非HTTP請求,如HTTPS、HTTP/2、WebSocket、TCP等會通過該事件將目標(biāo)服務(wù)器地址傳過來,觸發(fā)該事件的代理請求也叫隧道代理。


        可以在事件里面的req.url或req.headers.host獲取目標(biāo)服務(wù)器的地址(host:port),再跟該服務(wù)器地址建立連接并將結(jié)果通過HTTP響應(yīng)的方式返回給客戶端,這里只是實現(xiàn)代理的最基本功能,完整的HTTP除了請求轉(zhuǎn)發(fā),至少應(yīng)該還有:


        • 查看實時抓包;


        • 解析HTTPS請求;


        • 修改請求響應(yīng)內(nèi)容;


        • 擴展功能。


        下面以Whistle為例看下如何用Node.js實現(xiàn)一個完整的HTTP代理。



        三、完整HTTP代理架構(gòu)(Whistle)



        主要分五個模塊


        • 請求接入模塊


        • 隧道代理模塊


        • 處理HTTP請求模塊


        • 規(guī)則管理模塊


        • 插件管理模塊



        四、具體實現(xiàn)原理


        下面分別看下這五個模塊具體是怎么實現(xiàn)的。


        (一)請求接入模塊



        所有請求先會經(jīng)過請求接入模塊,Whistle支持四種請求接入方式:


        • HTTP&HTTPS直接請求:相當(dāng)于配hosts或DNS的方式,將請求轉(zhuǎn)發(fā)到Whistle;


        • HTTP代理:Whistle默認(rèn)接入方式,即配系統(tǒng)代理或通過瀏覽器插件配 HTTP代理的方式;


        • HTTPS代理:在HTTP代理之上對代理請求進(jìn)行了加密,即HTTPS Server,可以通過指定證書轉(zhuǎn)成HTTP代理請求;


        • Socks5代理:利用npm包socksv5轉(zhuǎn)成普通的TCP請求,并將TCP請求轉(zhuǎn)成隧道代理請求。


        實現(xiàn)原理將所有請求都轉(zhuǎn)成HTTP代理的隧道代理請求或HTTP請求,再解析隧道代理請求轉(zhuǎn)成HTTP請求。


        如何將普通tcp請求轉(zhuǎn)成隧道代理請求參見:lack-proxy


        下面看下如何從隧道代理請求解析出HTTP請求。



        (二)隧道代理模塊



        關(guān)鍵點(HTTP請求也可以走隧道代理):


        • 通過匹配的全局規(guī)則判斷是否要解析隧道代理請求,如果不解析,則當(dāng)成普通TCP請求處理;


        • 如果需要,則通過socket.once('data', handler)?讀取請求點第一幀數(shù)據(jù);


        • 將第一幀數(shù)據(jù)轉(zhuǎn)成字符串,通過正則/^(\w+)\s+(\S+)\s+HTTP\/1.\d$/mi是否是HTTP請求?如果是HTTP請求,再判斷下是否是CONNECT請求,即隧道代理請求(隧道代理請求也可以代理隧道代理請求),如果是,則轉(zhuǎn)回隧道代理方法處理,如果不是,則轉(zhuǎn)到HTTP請求模塊處理;


        • 如果不是HTTP請求,則當(dāng)成HTTPS請求處理,這里需要用到中間人的方式將HTTPS請求轉(zhuǎn)成HTTP請求;


        • Whistle會先按以下順序獲取請求證書:


        • 通過匹配的插件獲取(可以通過規(guī)則 sniCallback://plugin 指定加載證書的插件);


        • 通過啟動參數(shù)-z certDir指定目錄或~/.WhistleAppData/custom_certs 加載的自定義證書;


        • 如果沒有上述兩種自動證書,Whistle會自動生成一個默認(rèn)的證書。


        • 獲取到證書后,再利用該證書啟動一個HTTPS Server,將HTTPS請求轉(zhuǎn)成HTTP請求交給HTTP請求模塊處理。



        (三)HTTP請求處理模塊



        HTTP 請求處理可以分兩個階段:


        • 請求階段


        • 匹配全局規(guī)則;


        • 果規(guī)則里類似whistle.xx的規(guī)則,執(zhí)行對應(yīng)插件鉤子,獲取插件規(guī)則并跟匹配的全局規(guī)則合并;


        • 執(zhí)行規(guī)則、記錄狀態(tài)并請求到指定服務(wù)。


        • 響應(yīng)階段


        • 執(zhí)行匹配插件的鉤子,獲取插件規(guī)則并跟匹配的全局規(guī)則合并;


        • 執(zhí)行規(guī)則、記錄狀態(tài)并請求返回客戶端。



        (四)規(guī)則管理


        與傳統(tǒng)抓包調(diào)試代理采用斷點修改請求響應(yīng)數(shù)據(jù)不同,Whistle采用配置規(guī)則的方式修改請求響應(yīng),采用配置方式的好處是操作簡單,且可以將操作持久化存儲及共享給他人,先看幾個例子:



        Whistle的規(guī)則管理主要兩個功能:解析規(guī)匹配規(guī)則。


        • 解析規(guī)則


        Whistle有兩類規(guī)則:


        • 全局規(guī)則(公共規(guī)則),所有請求都會嘗試匹配的規(guī)則,由以下規(guī)則組成:


        • 界面Rules配置的規(guī)則;


        • 插件根目錄rules.txt配置文件;


        文檔:https://github.com/whistle-plugins/whistle.autosave/blob/master/rules.txt? ?


        • 界面或插件rules.txt通過@url方式引入的遠(yuǎn)程規(guī)則(要單獨一行,Whistle會定時更新遠(yuǎn)程規(guī)則)。



        • 插件規(guī)則(私有規(guī)則),即進(jìn)入插件的請求(匹配的全局規(guī)則里有whistle.xxx協(xié)議)才會匹配到的規(guī)則,由以下規(guī)則組成:


        文檔https://wproxy.org/whistle/plugins.html


        • 插件reqRulesServer等hooks動態(tài)返回;


        • 插件根目錄_rules.txt等文件配置的靜態(tài)規(guī)則。



        • 匹配規(guī)則


        Whistle規(guī)則的完整結(jié)構(gòu)為:



        文檔:https://wproxy.org/whistle/mode.html



        (五)插件管理



        Whistle插件的功能很多,不僅具備Node的所有能力,且可以操作Whistle的所有規(guī)則(理論上可以基于插件實現(xiàn)一個Whistle),主要用來做以下事情:


        • 鑒權(quán)功能


        • 提供UI交互界面


        • 作為請求Server(直接響應(yīng)或轉(zhuǎn)發(fā)并修改請求響應(yīng))


        • 統(tǒng)計請求信息(查看上報/打點數(shù)據(jù)等)


        • 設(shè)置規(guī)則(動態(tài)、靜態(tài)、全局及私有規(guī)則)


        • 獲取抓包數(shù)據(jù)


        • 編解碼請求響應(yīng)數(shù)據(jù)流(pipe stream功能)


        • 擴展界面右鍵菜單(如:分享抓包數(shù)據(jù))


        • 保存并同步Rules&Values數(shù)據(jù)


        • 自定義HTTPS請求的證書


        比如:


        • whistle.script:實現(xiàn)通過自定義腳本動態(tài)設(shè)置規(guī)則


        • whistle.vase:提供靈活強大的mock能力


        • whistle.inspect:方便快速注入vConsole、eruda等頁面調(diào)試工具


        • whistle.sni-callback:自定義證書插件


        其它插件例子參見:https://github.com/whistle-plugins


        Whistle是如何實現(xiàn)插件功能?主要遵循以下三個設(shè)計原則:


        • 完備性


        確保所有功能點都可擴展,如:請求鑒權(quán)、生成證書、獲取抓包、設(shè)置規(guī)則、請求處理等。


        • 穩(wěn)定性


        插件內(nèi)部異常不影響其它功能,Whistle的每個插件獨立進(jìn)程,插件與Whistle之間通過HTTP協(xié)議交互。


        Whistle是使用npm包pfork來啟動插件進(jìn)程,進(jìn)程間的交換是直接通過Node的http模塊實現(xiàn)的),方便開發(fā)者利用http的生態(tài)開發(fā)插件。


        • 易用性


        方便用戶開發(fā)及使用。


        開發(fā):結(jié)構(gòu)簡單 (npm包) + 腳手架lack;


        使用:安裝npm包即可,用法跟內(nèi)置協(xié)議一樣,且可內(nèi)置交互界面。


        有關(guān)插件的更多細(xì)節(jié)參見https://wproxy.org/whistle/plugins.html


        事實上,Whistle除了支持插件擴展,還可以同時作為獨立模塊引入項目使用;除了本地開發(fā)使用,也可以基于Whistle開發(fā)出支持多人使用的開發(fā)聯(lián)調(diào)協(xié)作工具,比如后面會給大家介紹其實現(xiàn)原理的:


        • 基于Whistle實現(xiàn)的多人多環(huán)境遠(yuǎn)程抓包調(diào)試工具


        Nohost:https://github.com/Tencent/nohost


        • 基于Whistle和Nohost實現(xiàn)的分布式遠(yuǎn)程抓包調(diào)試工具TDE等


        TDE目前只在騰訊內(nèi)部使用,后續(xù)后逐步對外開源。


        參考資料:

        1.Github倉庫:https://github.com/avwo/whistle

        2.官方插件倉庫:https://github.com/whistle-plugins

        3.詳細(xì)文檔:https://wproxy.org/whistle/



        ?作者簡介


        吳文斌(avenwu)

        騰訊前端高級工程師

        騰訊前端高級工程師,Whistle、Nohost作者,目前主要負(fù)責(zé)團隊的Node服務(wù)框架及效率工具的開發(fā)維護工作。



        ?推薦閱讀


        它來了,關(guān)于Golang并發(fā)編程的超詳細(xì)教程!

        有的放矢,遠(yuǎn)程操控中實時音視頻的優(yōu)化之道

        TVP三周年:聚力成長,共赴新篇!

        代碼質(zhì)量第5層-只是實現(xiàn)了功能




        瀏覽 96
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            国产一级毛片a | 国产丝袜一区二区三区免费观看 | 男男互操网站 | 啊轻点灬太粗嗯太深了在线视频 | 露脸Tp极品美女嘘嘘 | 欧美视频色 | 成人片免费无码 | 18禁黄暴视频 | 91黄色大片 | 久操国产|