【流量劫持】SSLStrip 的未來 —— HTTPS 前端劫持
前言
在之前介紹的流量劫持文章裡,曾提到一種『HTTPS 向下降級』的方案 —— 將頁面中的 HTTPS 超連結全都替換成 HTTP 版本,讓使用者始終以明文的形式進行通訊。
看到這,也許大家都會想到一個經典的中間人攻擊工具 —— SSLStrip,通過它確實能實現這個效果。
不過今天講解的,則是完全不同的思路,一種更有效、更先進的解決方案 —— HTTPS 前端劫持。
後端的缺陷
在過去,流量劫持基本通過後端來實現,SSLStrip 就是個典型的例子。
類似其他中間人工具,純後端的實現只能操控最原始的流量資料,這嚴重阻礙了向更高層次的發展,面臨眾多難以解決的問題。
動態元素怎麼辦?
如何處理資料包分片?
效能消耗能否降低?
......
動態元素
在 Web 剛出現的年代裡,SSLStrip 這樣的工具還是大有用武之地的。那時的網頁都以靜態為主,結構簡單層次清晰。在流量上進行替換,完全能夠勝任。
然而,如今的網頁日益複雜,指令碼所佔比重越來越多。如果僅僅從流量上著手,顯然力不從心。
var protocol = 'https';
document.write('<a href="' + protocol + '://www.alipay.com/">Login</a>');
即使非常簡單的動態元素,後端也毫無招架之力。
分片處理
分塊傳輸的道理大家都明白。對於較大的資料,一口氣是無法傳完的。客戶端依次收到各個資料塊,最終才能合併成一個完整的網頁。
由於每次收到的都是殘缺的碎片,這給連結替換帶來很大的麻煩。加上不少頁面並非標準的 UTF-8 編碼,因此更是難上加難。
為了能順利進行,中間人通常先收集資料,等到頁面接收完整,才開始替換。
如果把資料比作水流,這個代理就像大壩一樣,攔截了源源不斷往下流的水,直到蓄滿了才開始釋放。因此,下游的人們需忍受很久的乾旱,才能等到水源。
效能消耗
由於 HTML 相容眾多歷史遺留規範,因此替換工作並非是件輕鬆事。
各種複雜的正則表示式,消耗著不少的 CPU 資源。儘管使用者最終點選的只是其中一兩個連結,但中間人並不知道將會是哪個,因此仍需分析整個頁面。這不得不說是個悲哀。
前端的優勢
如果我們的中間人能打入到頁面的前端,那麼情況會不會有所改善呢?
分片處理
首先,要派一名間諜到頁面裡。這是非常容易辦到的:
不像超連結遍佈在頁面各處,指令碼插入到頭部即可運行了。所以我們根本不用整個頁面的資料,只需改造下第一個 chunk 就可以,後續的資料仍然交給系統轉發。
因此,整個代理的時間幾乎不變!
動態元素
很好,我們輕易滲透到頁面裡。但接著又如何發起進攻?
既然到了前端裡,方法就相當多了。最簡單的,就是遍歷超連結元素,將 https 的都替換成 http 版本。
這個想法確實不錯,但仍停留在 SSLStrip 思維模式上。還是『替換』這條路,只是從後端搬到前端而已。
儘管這個方法能勝任大多場合,但仍然不是最完美的。我們並不知道動態元素何時會新增進來,因此需要開啟定時器不斷的掃描。這顯然是個很挫的辦法。
效能優化
事實上,超連結無論是誰產生的、何時新增進來的,只要不點選,都是不起作用的。所以,我們只需關心何時去點選就可以 —— 如果我們的程式,能在點選產生的第一時間裡控制住現場,那麼之後的流程就可由我們決定了。
聽起來似乎很玄乎,不過在前端,這只是小菜一碟的事。點選,不過個事件而已。既然是事件,我們用最基礎的事件捕獲機制,即可將其輕鬆拿下:
document.addEventListener('click', function(e) {
// ...
}, true);
DOM-3-Event 是個非常有意義的事件模型。之前用它來實現『內聯 XSS 攔截』,如今同樣也可以用來劫持連結。
我們捕獲全域性的點選事件,如果發現有落在 https 超連結上,果斷將其......攔截?
如果真把它攔截了,那新頁面就不會出現了。當然你會說,可以自己 window.open 彈一個,反正點選事件裡是可以彈窗的。
不過,請別忘了,並非所有的超連結都是彈窗,也有不少是直接跳轉的。你也會說可以修改 location 來實現。
但要識別是『彈窗』還是『跳轉』,並不簡單。除了超連結的 target
屬性,頁面裡的 <base>
元素也會有影響。當然,這些相信你都能處理好。
然而,現實未必都是那麼簡單的。有些超連結本身就綁定了 onclick 事件,甚至在其中 return false 或 preventDefault,遮蔽了預設行為。如果我們不顧及這些,仍然模擬跳轉或彈窗,那就違背頁面的意願了。
事實上,有一個非常簡單的辦法:當我們的捕獲程式執行時,新頁面還遠沒出現,這時仍有機會修改超連結的 href。待事件冒泡完成、執行預設行為時,瀏覽器才讀取 href 屬性,作為最終的結果。
因此,我們只需捕獲點選事件,修改超連結地址就可以了。至於是跳轉、彈窗、還是被遮蔽,根本不用我們關心。
就那麼簡單。因為我們是在使用者點下去之後才修改,所以瀏覽器狀態列裡,顯示的仍是原先 https !
當然,點過一次之後,再把滑鼠放到超連結上,狀態列裡顯示的就是修改後的了。
為了能繼續忽悠,我們在修改 href 之後的下個執行緒週期裡,把它改回來。因為有了一定延時,新頁面並不受影響。
var url = link.href; // 儲存原始地址
link.href = url.replace('https://', 'http://'); // 暫時換成 http 的
setTimeout(function() {
link.href = url; // 新頁面開啟後,還原回來
}, 0);
這樣,頁面裡的超連結始終都是正常的 —— 只有使用者點下的瞬間,才臨時偽裝一下。
更多攔截
除了通過超連結,還有其他方式訪問頁面,我們應儘可能多的進行監控。例如:
- 表單提交
- window.open 彈窗
- 框架頁面
- .....
表單提交
表單提交和超連結非常類似,都具有事件,只是將 click
換成 submit
,href
換成 action
而已。
指令碼彈窗
函式呼叫的最簡單了,只需一個小鉤子即可搞定:
var raw_open = window.open;
window.open = function(url) {
// FIX: null, case insensitive
arguments[0] = url.replace('https://', 'http://');
raw_open.apply(this, arguments);
}
框架頁面
因為我們把主頁面降級成 http 了,但裡面的框架地址仍是原先的。由於協議不同,這會產生跨域問題,導致頁面無法正常工作。
所以我們還要把頁面裡的框架,也都轉型成 http 版本,確保能和主頁面融為一致。
但框架和之前的那些不同,因為它是自動載入的,而且也沒有一個即將載入的事件。如果等到框架載入完了再去處理,說不定已經開始報跨域錯誤了。而且還會白白的浪費一次載入流量。
因此,我們必須讓框架一出現,就立即替換掉地址。
這在過去是個很棘手的問題,然而 HTML5 時代給我們帶來了新希望 —— MutationEvent
。用它即可實時監控頁面元素,之前也嘗試過一些試驗。
當然,即使 MutationEvent,偶爾也會有延時遺漏。為了能徹底避免出現 https 框架頁,我們繼續使用 HTML5 帶來的一項新技術 —— Content Security Policy,由於它是瀏覽器原生支援的,因此實施的非常徹底。
在我們的代理返回頭中,加上如下 HTTP 頭部,即可完美攔截 https 框架頁了:
Content-Security-Policy: default-src * data: 'unsafe-inline' 'unsafe-eval'; frame-src http://*
解決了框架頁的問題,我們就能成功劫持支付寶登入頁的賬號框 IFrame 了!
後端配合
通過前端的 XSS 指令碼,我們輕易解決了過去各種棘手的問題。但挑戰並未就此結束,我們仍面臨著眾多難題。
如何告訴代理
儘管在前端上面,我們已經避開了各種進入 https 的途徑,讓請求以明文的形式交給代理。但代理又如何決定,這個請求用 https 還是 http 轉發呢?
傳統的後端劫持之所以能正確轉發,那是在替換超連結的時候,已經做下記錄。當出現記錄中的請求,就走 https 的轉發。
而我們的劫持在前端,並且只發生在點選的一瞬間。即使馬上去告訴中間人,某個 URL 是 https 的,這時也來不及了。
告訴中間人是必須的。但我們可以用一個巧妙的方法,不必單獨傳送訊息 —— 我們只需在轉型後的 URL 裡,做個小記號就可以了。
當代理髮現請求的 URL 裡有這個記號,它自然就懂了,直接走 https!
由於把頁面從 https 降級到了 http,因此相關請求的referer
也變成 http 版了。所以,中間人應儘量把 referer 也修正回來,避免被伺服器察覺。
隱藏偽裝
不過,在 URL 里加標記的方法,也有很大的缺陷。
因為頁面的 URL 會在位址列裡顯示出來,所以使用者會看見我們的記號。當然,我們可以使用一些迷惑性的字元,例如 ?zh_cn
、?utf_8
,?from_baidu
等等,更好的欺騙使用者。
當然,如果你覺得還是不滿意,也有辦法讓這些礙眼標記儘快消失:
if url has symbol
history.replaceState(..., clear_symbol(url) )
HTML5 為我們提供了修改位址列的能力,並且無需重新整理。這些強悍的功能,如今都可以在前端利用起來了。
重定向劫持
當然,光靠前端的劫持,還是遠遠不夠的。現實中,還有另一種很常見的方式,那就是重定向到安全頁面。
仔細回想下,平時我們是怎樣進入想上的網站的。例如支付寶,除非你有收藏,否則就得自己敲入 www.alipay.com 或 www.zhifubao.com,當你回車進入時,瀏覽器又如何知道這是個 HTTPS 的網站呢?
顯然,第一個請求仍是普通的 HTTP 協議。當然,這個 HTTP 版的支付寶的確存在,它的唯一功能就將使用者重定向到 HTTPS 版本。
當我們的中間人一旦發現有重定向到 HTTPS 網站的,當然不希望使用者走這條不受自己控制的路。於是攔下這個重定向,然後以 HTTPS 的方式,獲取重定向後的內容,最後再以 HTTP 明文的方式,回覆給使用者。
因此在使用者看來,始終處於 HTTP 網站上。
不過,如今的 Web 裡增加一個新的安全標準:HTTP Strict Transport Security。如果客戶端收到這個頭部,之後一段時間內訪問該站點,就始終通過 HTTPS 的方式。
所以我們的中間人一旦發現有這個欄位,就得果斷將其刪除。
當然,使用者直接敲網址的並不常見。大多都是搜尋引擎,然後直接從第一個結果裡進來了。
比較悲劇的是,國內的搜尋引擎幾乎都是 HTTP 的。在使用者訪問搜尋頁面的時候,我們的 XSS 早已潛伏在其中了,因此從中點出來的任何一條結果,都是進不到官方的 HTTPS 裡的:)
除了搜尋頁面,不少類似 hao123 之類的網址大全,大多也未開啟 HTTPS。因此從中導流的網站,都面臨著被中間人劫持的風險。
防範措施
介紹了攻擊方法,接著講解防禦措施。
指令碼跳轉
事實上,無論是前端劫持還是後端過濾,仍有不少的網站無法成功。例如京東的登入:
它是通過指令碼跳轉到 HTTPS 地址的。而瀏覽器的 location
是個及其特殊的屬性,它可以被遮蔽,但無法被重寫。因此我們難以控制頁面的跳轉情況。
如果非要劫持京東頁面,我們只能使用白名單的方式,特殊對待該站點。但這樣就大幅增加了攻擊成本。
混淆明文
當然,不難發現京東的登入腳本里,URL 是以最直白的明文出現的。所以我們利用 SSLStrip 的方式,對腳本里的 https://
的文字進行替換,也能起到一定的作用,畢竟大多指令碼都對此毫無防備。
但對於稍微複雜一點的指令碼,例如通過字串拼接而成的 URL,那麼就難以實施了。
所以在安全需要較高的場合,不妨把一些重要的地址進行簡單的處理,中間人就無法使用通用的方式來攻擊。而必須針對站點進行特殊對待,從而提高攻擊成本。
儘可能多的 HSTS
之前提到 HSTS
頭。只要這個欄位出現過一次,瀏覽器在很長時間裡都會只用 HTTPS 訪問站點。因此,我們儘可能多的開啟 HSTS。
現實中的劫持並非都是 100% 成功的,上述提到,使用指令碼跳轉很容易出現遺漏。所以,只要逮住使用者一次遺漏,HSTS 就可以讓之後的頁面降級徹底失效了。
攻擊演示
因為是前端劫持,所以 Demo 有兩個檔案:一個前端程式碼,另一個後端指令碼(NodeJS)。
相比之前寫的流量劫持演示,這裡功能更為專一,不再提供額外的劫持途徑(例如 DNS 等)。
想測試其實非常簡單,只需配置瀏覽器代理,即可模擬 HTTP 的劫持:
不嫌麻煩的話,也可以在 Linux 核心的系統上測試,轉發 80 到本機即可。原理都是一樣的。
我們隨便找一個 HTTP -> HTTPS
網站做測試。
得益於前端指令碼的優勢,我們把滑鼠放到登入超連結上,狀態列顯示的仍是原始 URL:
在我們點選的瞬間,暗藏頁面中的 XSS 鉤子觸發了,成功把我們帶到中間人虛擬的 HTTP 登入頁面裡。
當然,由於 URL 引數很多,位址列裡的那個記號看不到了。
慶幸的是,淘寶的登入頁面未進行地址判斷,被降級後的頁面仍然能登入成功!
當然之前也說了,並非所有的頁面都能劫持成功。
如今越來越多的網站都已重視,因此前端的安全性檢測也隨之而生。僅僅通過一個工具,實現大規模通用化的劫持,未來會更加困難。
但先比傳統的純後端實現,前後結合的方案能夠帶來更大的發揮空間。
相關推薦
【流量劫持】SSLStrip 的未來 —— HTTPS 前端劫持
前言 在之前介紹的流量劫持文章裡,曾提到一種『HTTPS 向下降級』的方案 —— 將頁面中的 HTTPS 超連結全都替換成 HTTP 版本,讓使用者始終以明文的形式進行通訊。 看到這,也許大家都會想到一個經典的中間人攻擊工具 —— SSLStrip,通過它確實能實現這個效果。 不過今天講解的,則是完全不同的思
【小程序】搭建本地https服務器(windows)
inf link title windows logs ews 事業部 巴巴 SM (一)用json-server搭建簡單的服務器 (搭建出來的服務器地址為localhonst:3000) 1.新建Mockjson文件夾,進入該文件夾目錄,運行命令
【nginx學習】nginx反向代理前端跨域問題
本地ip name str host jsonp 註意 access origin 跨域問題 * 跨域簡介: 跨域是指a頁面想獲取b頁面資源,如果a、b頁面的協議、域名、端口、子域名不同,所進行的訪問行動都是跨域的,而瀏覽器為了安全問題一般都限制了跨域訪問,也就是不允許跨域
【備忘】Spring Boot從前端到後臺打造企業級部落格全棧實戰視訊
第1章 Spring Boot 簡介 第2章 開啟 Spring Boot 的第一個 Web 專案 第3章 一個Hello World專案 第4章 開發環境的搭建 第5章 整合Thymeleaf模版引擎 第6章 資料持久化Spring Data
【視訊分享】尚矽谷HTML5前端視訊_React視訊
React 是當前最火的 JS 庫!本套視訊基於最新版本 React 錄製,涵蓋
【中介軟體】TOMCAT8支援HTTPS協議
預設情況下,Tomcat是不支援HTTPS協議的,當然該功能TOMCAT是有的 HTTPS協議的配置方法如下,參考網上文件完成,但是網上部分文件有錯誤或者版本不匹配的問題,改過程我是在TOMCAT8上做的,其他版本請自行試驗。 引用:http://blog.csdn.ne
【面經】2018金山WPS前端筆試題 & 面試題
Q: 通過鍵名訪問物件的成員 下面程式碼輸出了什麼? var a={}, b={key:'b'}, c={key:'c'}; a[b]=123; a[c]=456; console.log(a[b]); A 答案為456,因為鍵名只能為字串,傳入
mapreduce【流量統計】求和——自定義資料型別
需求:統計一下檔案中,每一個使用者所耗費的總上行流量,總下行流量,總流量 1363157985066 13726230503
【nodeJS爬蟲】前端爬蟲系列
取數 能夠 bsp blank 介紹 數據 ports exports 時間段 寫這篇 blog 其實一開始我是拒絕的,因為爬蟲爬的就是cnblog博客園。搞不好編輯看到了就把我的賬號給封了:)。 言歸正傳,前端同學可能向來對爬蟲不是很感冒,覺得爬蟲需要用偏後端的語言,
前端頁面重構技巧總結TIP【持續更新...】
code lock 項目 居中 經驗 ade 布局 baidu round 本文均為項目實戰經驗,要求兼容至IE8,所以以下內容均為兼容代碼,歡迎各位小夥伴批評指教。其實重構頁面是一門學問,看似簡單,卻暗藏很多學問。實際項目中頁面的重構有以下幾點最基本需求: 1.需要使用
【已解決】Https請求——基礎連接已經關閉 發送時發生錯誤
自己 服務器 poi make 手動 default 比較 man 消息 本人在做商用項目的推送消息功能時,借助第三方推送服務。這裏避免有打廣告的嫌疑,就不報名字了。由於是通過調用API接口,所以Post方法是自己寫的,但是在開發環境是可以正常推送的,但是一上線就出各種問題
前端【響應式】開發詳細解析
響應式設計 針對 標簽 ipad rem img ons 微信公眾 dev 一、響應式設計需要解決的問題是什麽? 針對目前大家常見的固定布局、自適應布局都是一種反應遲鈍的web設計,當Web頁面需要在各種顯示屏顯示時,他們就顯得力不從心了。因此,我們就需要相應設計。 優勢:
【gulp】前端自動化工具---gulp的使用(一)------【凡塵】
app 一起 dex 前端自動化 指定 sass css 文件的 等待 什麽是gulp? 基於node的自動化構建工具 擴展:開發的時候分為2個節點一個是開發階段 另一個是部署階段 開發階段:源文件不會被壓縮
【bird-front】前端框架介紹
lan 查看 後臺管理 gpo mas button 圖片 blank div bird前端項目,基於react、antd、antd-admin,封裝常用數據組件,細粒度權限解決方案。 bird-front是基於react的後臺管理系統前端項目,框架構建部分嚴重借鑒於ant
【HAVENT原創】前端跨域一站式登錄實現 ( iframe + window.name )
不同的 rip 控制臺 tool 數據信息 als 前端 reat proxy 從網上搜集了一些資料,window.name 傳輸技術,關於window.name的這樣一個特性:name 值在不同的頁面(甚至不同域名)加載後依舊存在,並且可以支持非常長的 name 值(2M
web前端【第一篇】HTML基礎一(標簽)
lpad 百度 合並單元格 div gpo a標簽 適合 code words 一、初始html 1.web服務本質 import socket sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) sock.bin
web前端【第二篇】HTML基礎二(表單、div)
ebe add 渲染 efi end 文件 ctype 發送 type 一、表單 功能:表單用於向服務器傳輸數據,從而實現用戶與Web服務器的交互 表單能夠包含input系列標簽,比如文本字段、復選框、單選框、提交按鈕等等。 表單還可以包含text
【總結整理】http-https
log 整理 消息 cer 基本原理 ati 公鑰加密 簽名 如何 上面這種加密消息的方式就是對稱加密,你知道如何加密,也知道如何解碼。然後李雷跟韓梅梅用的字母表偏移的加密方法叫 Caesar cipher, 凱撒加密。現實世界中用的加密算法會更復雜,但是基本原理相同。 上
【h5+c3】web前端實戰項目、快裝webapp手機案例源碼
src strong ont 下拉 效果 實例 項目 12px img 快裝WebApp項目(Web移動端開發案例)webapp移動端項目源碼、html5+css3實戰案例分享、微信端H5實例開發 簡介快裝WebApp是一個面向移動端的快速裝修app,此項目為手機端;使用H
file_get_contents采集https報錯【解決辦法】
原因 file cto sch error col com ont doc OpenSSL Error messages: error:14090086:SSL routines:ssl3_get_server_certific 原因:cacert.pem證書失效,需要更