吃透瀏覽器安全(同源限制/XSS/CSRF/中間人攻擊)

前言

隨著互聯(lián)網(wǎng)的高速發(fā)展,信息安全問題已經(jīng)成為企業(yè)最為關(guān)注的焦點之一,而前端又是引發(fā)企業(yè)安全問題的高危據(jù)點。在移動互聯(lián)網(wǎng)時代,特別是前端人員除了傳統(tǒng)的 XSS、CSRF 等安全問題之外,又時常遭遇網(wǎng)絡劫持、非法調(diào)用 Hybrid API 等新型安全問題。當然,瀏覽器自身也在不斷在進化和發(fā)展,不斷引入 CSP、SameSite、HttpOnly、Cookies 等新技術(shù)來增強安全性,但是仍存在很多潛在的威脅,這需要我們不斷進行“查漏補缺”

瀏覽器安全可以分為三大塊:Web頁面安全、瀏覽器網(wǎng)絡安全、瀏覽器系統(tǒng)安全

Web頁面安全主要就是同源策略限制

什么是同源策略

同源指的是我們訪問站點的:協(xié)議域名、端口號必須一至,才叫同源。

瀏覽器默認同源之間的站點是可以相互訪問資源和操作DOM的,而不同源之間想要互相訪問資源或者操作DOM,那就需要加一些安全策略的限制,俗稱同源策略

同源策略主要限制了三個方面:

  1. DOM層面:不同源站點之間不能相互訪問和操作DOM
  2. 數(shù)據(jù)層面:不能獲取不同源站點的Cookie、LocalStorage、indexDB等數(shù)據(jù)
  3. 網(wǎng)絡層面:不能通過XMLHttpRequest向不同源站點發(fā)送請求

當然同源策略限制也不是絕對隔離不同源的站點,比如link、img、script標簽都沒有跨域限制,這讓我們開發(fā)更靈活了,但是也同樣帶來了一些安全問題,也就是瀏覽器網(wǎng)絡安全問題,最典型的就是XSS攻擊和CSRF攻擊

說一下XSS攻擊

XSS攻擊是一種代碼注入攻擊,通過惡意注入腳本在瀏覽器運行,然后盜取用戶信息

造成XSS攻擊其實本質(zhì)上還是因為網(wǎng)站沒有過濾惡意代碼,與正常代碼混在一起之后,瀏覽器沒有辦法分辨哪些是可信的,然后導致惡意代碼也被執(zhí)行。然后可能導致以下情況:

  • 頁面數(shù)據(jù)或用戶信息被竊取,如DOM、Cookie、LocalStorage
  • 修改DOM,比如偽造登錄窗口或在頁面生成浮窗廣告
  • 監(jiān)聽用戶行為,比如在登錄或銀行等站點用 addEventListener 監(jiān)聽鍵盤事件,竊取賬號密碼等信息
  • 流量被劫持向其他網(wǎng)站

XSS攻擊有三種類型:存儲型、反射型、DOM型

  1. 存儲型:是在有發(fā)貼評論等帶有數(shù)據(jù)保存功能的網(wǎng)站的input、textarea將惡意代碼提交到網(wǎng)站數(shù)據(jù)庫中,如<script src="http://惡意網(wǎng)站"></script> ,然后比如在顯示評論的頁面就會從數(shù)據(jù)獲取,并直接執(zhí)行這個script標簽里的惡意代碼

  2. 反射型:是攻擊者將惡意JS腳本作為用戶發(fā)送給網(wǎng)站請求中的一部分,然后網(wǎng)站又把惡意腳本返回給用戶,這時候就會在頁面中被執(zhí)行。比如打開包含帶惡意腳本的鏈接,當打開后會向服務器請求后,服務器會獲取URL中的數(shù)據(jù)然后拼接在HTML上返回,然后執(zhí)行。它和存儲型不同的是不會儲存在服務器里

  3. 基于DOM型:就是攻擊者通過一些劫持手段,在頁面資源傳輸過程中劫持并修改頁面的數(shù)據(jù),插入惡意代碼

怎么防范XSS攻擊,有什么解決辦法?

  • 就是對輸入框的內(nèi)容進行過濾或使用轉(zhuǎn)義符進行轉(zhuǎn)碼

    字符 轉(zhuǎn)義后的字符
    < &lt;
    > &gt;
    " &quot;
    ' &#x27;
    / &#x2F
    & &amp;
  • 使用CSP,就是白名單,告訴瀏覽器哪些外部資源可以加載執(zhí)行,讓即使插入進來惡意代碼的也不會執(zhí)行,或者可以向哪些第三方站點提交數(shù)據(jù)。開啟白名單的方式有兩種:

    • 使用 meta 標簽 <meta http-equiv="Content-Security-Policy">
    • 設置http頭部的 Content-Security-Policy
  • 對一些敏感信息進行保護,在Cookie信息中添加httpOnly,告訴瀏覽器在保存Cookie,且不要對客戶端腳本開放訪問權(quán)限,然后就不能通過document.cookie獲取cookie了

Set-Cookie: widget_session=123456; httpOnly
  • 使用驗證碼,避免腳本偽裝成用戶執(zhí)行一些操作

說一下CSRF攻擊

就是跨站請求偽造攻擊,主要就是利用用戶的登錄狀態(tài)發(fā)起跨站請求,比如郵箱里的亂七八糟的鏈接,打開鏈接的時候郵箱肯定是處于登錄狀態(tài),然后黑客就可以用這個登錄狀態(tài),偽造帶有正確 Cookie 的 http 請求,直接繞過后臺的登錄驗證,然后冒充用戶執(zhí)行一些操作

發(fā)起CSRF攻擊有三個必要條件:

  1. 目標網(wǎng)站一定要有CSRF漏洞
  2. 用戶登錄過目標網(wǎng)站,并且瀏覽器保存了登錄狀態(tài)
  3. 需要用戶主動打開第三方站點

本質(zhì)是利用cookie在同源請求中攜帶發(fā)送給服務器的特點,來實現(xiàn)冒充用戶

CSRF攻擊也有三種類型:GET類型、POST類型、鏈接型

  • 自動發(fā)GET類型:比如imgiframe標簽等,當用戶打開這個網(wǎng)站時會自動發(fā)起帶Cookie的資源請求
<img src="http://惡意網(wǎng)址" >
  • 自動發(fā)POST類型:比如整一個隱藏的表單,在用戶進入頁面的時候自動提交表單
<form id="hack" action="https://惡意網(wǎng)址" method="post">
    ...
</form>
<script>document.getElementById('hack').submit()</script>
  • 誘導鏈接型:就是誘導用戶主動點擊鏈接,比如a標簽
<a href="https://惡意網(wǎng)址">點擊領(lǐng)取大禮包</a>
<a href="https://惡意網(wǎng)址">點擊下載美女視頻</a>

怎么防范CSRF攻擊,有什么解決辦法?

  1. 在Cookie信息中添加SameSite屬性,這個屬性有三個值:

    • strict嚴格模式,完全禁止使用Cookie
    • lax寬松模式,允許部分情況使用Cookie,跨域的都行,a標簽跳轉(zhuǎn),link標簽,GET提交表單
    • none:任何情況下都會發(fā)送Cookie,但必須同時設置Secure屬性,意思是需要安全上下文,Cookie 只能通過https發(fā)送,否則無效

    Chrome 80之前默認值是none,之后是lax

Set-Cookie: widget_session=123456; SameSite=None; Secure
  1. 驗證請求來源:服務器根據(jù)http請求頭中的OriginReferer屬性判斷是否為允許訪問的站點,從而對請求進行過濾。優(yōu)先判斷Origin,如果兩個都不存在的話就直接阻止。
  • Referer:記錄了請求是從哪個鏈接跳過來的并且包含了路徑信息,也就是來源地址。不過這家伙不太可靠,所以后來又新增了Origin屬性
Referer: https://juejin.cn/editor/drafts/xxxx
  • origin:記錄了域名信息,沒有具體的URL路徑
Origin: https://juejin.cn
  1. Token驗證:服務器向用戶返回一個隨機數(shù)Token,再次請求時在請求頭中以參數(shù)的形式添加入這個Token,然后服務器驗證這個Token,如果沒有或者內(nèi)容不正確,就拒絕請求。缺點是

    • 每個請求都得添加比較繁瑣
    • 單方面驗證Cookie可能會被冒用,
    • 如果網(wǎng)站不止一臺服務器,通過負載均衡轉(zhuǎn)到了其他服務器的話,其他所有服務器中的Session中都得保留Token,不然就驗證不了了
  2. 雙重驗證Cookie:利用攻擊者只能利用Cookie,不能獲取Cookie的特點,用戶訪問頁面時,服務器向請求域名添加一個Cookie隨機字符串,然后,用戶再次請求時從Cookie中取出這個字符串,添加到URL參數(shù)中,然后服務器通過對Cookie中的數(shù)據(jù)和參數(shù)中的數(shù)據(jù)對比驗證,不一樣就拒絕請求。

    缺點是如果網(wǎng)站存在XSS漏洞,這法子就會失效,而且不能做到子域名的隔離

瀏覽器系統(tǒng)安全 - 安全沙箱

首先,我們設想一下,如果我們下載了一個惡意程序,但是沒有執(zhí)行它,對我們有沒有影響?

那肯定沒有,而瀏覽器也是一樣的

瀏覽器可以安全地下載各種網(wǎng)絡資源,但是執(zhí)行的時候就需要謹慎了。比如解析HTML、CSS、執(zhí)行JS等操作,一不小心黑客就會利用這些操作對有漏洞的瀏覽器發(fā)起攻擊

所以需要在渲染進程和操作系統(tǒng)之間建一堵墻,有這堵墻在擋著,黑客能黑進來,也只能獲取渲染進的操作權(quán)限(如下圖),不會影響到外面,而這隔離操作系統(tǒng)和渲染進程的一堵墻就是安全沙箱

安全沙箱最小的保護單位是進程,并且能限制進程對操作系統(tǒng)資源的訪問和修改,這就意味著,安全沙箱所在的進程不能有讀寫操作系統(tǒng)的功能,比如讀寫本地文件、發(fā)起網(wǎng)絡請求,調(diào)用GPU接口等

安全沙箱怎么影響各個模塊功能

  • 持久存儲
    • 存儲Cookie的讀寫,瀏覽器內(nèi)核會維護一個存放所有Cookie的Cookie數(shù)據(jù)庫,在渲染進程通過JS讀取Cookie時,渲染進程會通過IPC將讀取Cookie的信息發(fā)送給內(nèi)核,瀏覽器內(nèi)核讀取Cookie之后再將內(nèi)容通過IPC返回給渲染進程
    • 緩存文件的讀寫也是由瀏覽器內(nèi)核實現(xiàn)
  • 網(wǎng)絡訪問:渲染進程不能直接訪問網(wǎng)絡,也需要通過瀏覽器內(nèi)核,而瀏覽器內(nèi)核在處理URL請求之前,會檢查渲染進程有沒有權(quán)限請求該URL,比如有沒有跨域
  • 用戶交互
    • 輸入時:操作系統(tǒng)會將輸入事件傳給瀏覽器內(nèi)核,內(nèi)核判斷如果是地址欄輸入事件就直接在內(nèi)核處理,如果是頁面里的就轉(zhuǎn)發(fā)給渲染進程
    • 渲染時:渲染進程渲染出位圖后,需要將生成好的位圖發(fā)送給瀏覽器內(nèi)核,再由內(nèi)核將位圖復制到屏幕上顯示

站點隔離你知道嗎

我們知道一個標簽頁會有一個渲染進程,假如這個標簽頁里面有多個不同站點的 iframe 呢? 這就會導致多個不同站點的內(nèi)容運行在同一個渲染進程中,這肯定不行

所有操作系統(tǒng)中都存在兩個A級漏洞:幽靈(Spectre)和熔毀(Meltdown),這是處理器架構(gòu)導致的,很難修補

如果銀行頁面中有一個惡意 iframe ,這個惡意站點利用兩個A級漏洞入侵渲染進程,那惡意程序就可以讀取銀行站點渲染進程內(nèi)所有內(nèi)容了,這對用戶來說風險就很大了,如果沒有沙箱保護,甚至還可以對操作系統(tǒng)發(fā)起攻擊

所以后來Chrome對渲染進程進行重構(gòu),將標簽級的渲染進程改成 iframe 級渲染進程,就是說一個標簽頁內(nèi)可能運行多個渲染進程,并且相互隔離,這樣惡意 iframe 就無法訪問頁面中其他的內(nèi)容了,也就無法攻擊其他站點了,這就是站點隔離

中間人攻擊

在 http 數(shù)據(jù)提交給 TCP 層之后,會經(jīng)過用戶電腦、路由器、運營商、服務器,這中間每一個環(huán)節(jié),都不是安全的

一句話就是:在 http 傳輸過程中容易被中間人竊取、偽造、篡改,這種攻擊方式稱為中間人攻擊

那怎么讓數(shù)據(jù)可以更安全的傳輸呢?

就是使用 https ,利用 https 安全層對數(shù)據(jù)進行加解密操作,以保證數(shù)據(jù)安全。

關(guān)于 https性能優(yōu)化、版本、優(yōu)缺點、SSL/TLS、握手(RSA、TLS1.2、TLS1.3)三個版本及優(yōu)化等等,文章太長這里就不展開了,可以看我另一篇文章有詳細介紹

那么 https 是如何對數(shù)據(jù)加解密的呢?這要先說一下它的算法

對稱加密算法

就是加密和解密使用同一個密鑰。如AES、DES。加解密過程:

  1. 瀏覽器給服務器并發(fā)送一個隨機數(shù)client-random加密套件(一個支持的加密方法列表)
  2. 服務器生成給瀏覽器返回另一個隨機數(shù)server-random加密套件
  3. 兩邊分別返回確認消息。然后兩者用加密方法將兩個隨機數(shù)混合生成密鑰,這就是通信雙上加解密的密鑰

有了密鑰之后就可以對數(shù)據(jù)進行加密傳輸了

問題是client-randomserver-random都是明文的,雙方如何安全的傳遞兩個隨機數(shù)和加密方法呢?直接傳給客戶端,那過程中就很可能被竊取,中間人還是能解密拿到數(shù)據(jù),往下看

不對稱加密算法

就是一對密鑰,有公鑰(public key)和私鑰(private key),其中一個密鑰加密后的數(shù)據(jù),只能用另一個密鑰進行解密。如RSA、ECDHE。加解密過程:

  1. 瀏覽器給服務器發(fā)送加密套件
  2. 服務器選好支持的加密方法公鑰(明文) 傳給瀏覽器
  3. 兩邊分別返回確認消息。然后瀏覽器用公鑰對數(shù)據(jù)進行加密,這個密鑰只能用私鑰解密

這是不是看上去很完美了

其實還存在很嚴重的問題

  1. 使用公鑰反推出私鑰是非常困難,但不是做不到,隨著計算機運算能力提高,非對稱密鑰至少要2048位才能保證安全性,這就導致加解密速度慢,效率太低
  2. 無法保證服務器發(fā)送給瀏覽器的數(shù)據(jù)安全。因為瀏覽器可以用公鑰來加密,而瀏覽器就只能用私鑰加密,公鑰是明文傳輸?shù)?,中間人可以獲取到,這樣服務器端的數(shù)據(jù)安全就得不到保證了

所以!

混合加密

TLS實際用的是兩種算法的混合加密。通過 非對稱加密算法 交換 對稱加密算法 的密鑰,交換完成后,再使用對稱加密進行加解密傳輸數(shù)據(jù)。這樣就保證了會話的機密性。過程如下

  1. 瀏覽器給服務器發(fā)送一個隨機數(shù)client-random、對稱和非對稱加密套件
  2. 服務器把另一個隨機數(shù)server-random、加密套件、公鑰傳給瀏覽器
  3. 瀏覽器又生成另一個隨機數(shù)pre-random,并用公鑰對 pre-random 加密后傳給服務器
  4. 服務器再用私鑰解密,得到pre-random,并返回確認消息
  5. 這樣瀏覽器和服務器都有三個隨機數(shù)了,然后各自將三個隨機數(shù)用加密方法混合生成最終的對稱密鑰

然后開始數(shù)據(jù)加密傳輸

這樣即便被截持,中間人沒有私鑰就拿不到pre-random,就無法生成最終密鑰

這樣就安全了嗎?

emmmm......還沒

因為問題又來了,如果一開始DNS就被中間人劫持,那么請求被中間人截獲,中間人把他自己的服務器公鑰給了瀏覽器,瀏覽器收到公鑰就把信息發(fā)給中間人了,中間人解密拿到數(shù)據(jù),并干了一些見不得人的勾當之后,再請求實際服務器,拿到服務器公鑰,再把加密處理過后的數(shù)據(jù)發(fā)給服務器

這樣不知不覺間信息就被人竊取了,所以在結(jié)合對稱和非對稱加密的基礎上,還需要服務器向瀏覽器證明身份,那怎么證明呢?

所以數(shù)字證書來了,往下看

如何保證數(shù)據(jù)是否被篡改?

數(shù)字證書(數(shù)字簽名)

它可以幫我們驗證服務器身份,而且數(shù)字證書里包含了公鑰,而數(shù)字證書需要向有權(quán)威的認證機構(gòu)(CA)獲取授權(quán)給服務器。

相比之前就變成了

  • 服務器不直接返回公鑰給瀏覽器,而是返回數(shù)字證書,而公鑰就在數(shù)字證書中
  • 瀏覽器這邊多了一步證書驗證,驗證成功才能繼續(xù)后續(xù)流程

那么如何申請數(shù)字證書呢?

  • 首先,服務器準備一套公鑰私鑰,私鑰留著自己用
  • 服務器將公鑰和站點等信息提交給CA認證,這個是要錢
  • CA驗證服務器提供的信息
  • 審核通過后簽發(fā)認證的數(shù)字證書,包含了公鑰、CA信息有效時間、證書序列等這些都是明文的,還有一個CA生成的簽名

CA的簽名過程

  • CA也有一套公鑰私鑰
  • CA使用摘要算法計算服務器提交的明文信息并得出信息摘要
  • 然后CA再用它的私鑰和特定的算法對信息摘要加密,生成簽名
  • 簽名、服務器公鑰等信息打包放入數(shù)字證書,并返回給服務器
  • 服務器配置好證書,以后瀏覽器連接服務器,都先把證書發(fā)給客戶端驗證

摘要算法:主要用于保證信息的完整性。常見的MD5算法、散列函數(shù)、hash函數(shù)都屬于這類算法,其特點就是單向性無法反推原文

瀏覽器如何驗證數(shù)字證書

  • 瀏覽器連接服務器,都先把證書發(fā)給客戶端驗證
  • 使用CA公鑰和聲明的簽名算法對CA中的簽名進行解密,得到服務器的摘要內(nèi)容和服務器公鑰
  • 再用摘要算法對證書里的服務器公鑰生成摘要,再把這個摘要和上一步得到的摘要對比
  • 然后將兩個信息摘要對比,如果是一致的,就說明證書是合法的,即證明了服務器自己,否則就是非法的

證書認證又分為單向認證雙向認證

單向認證:服務器發(fā)送證書,客戶端驗證證書
雙向認證:服務器和客戶端分別提供證書給對方,并互相驗證對方的證書

不過大多數(shù)https服務器都是單向認證,如果服務器需要驗證客戶端的身份,一般通過用戶名、密碼、手機驗證碼等之類的憑證來驗證。只有更高級別的要求的系統(tǒng),比如大額網(wǎng)銀轉(zhuǎn)賬等,就會提供雙向認證的場景,來確保對客戶身份提供認證性

另外在申請和使用證書的過程中,需要注意

  • 申請數(shù)字證書是不需要提供私鑰的,要確保私鑰永遠只能由服務器掌握
  • 數(shù)字證書最核心的是CA使用它的私鑰生成的數(shù)字簽名
  • 內(nèi)置CA對應的證書稱為根證書,根證書是最權(quán)威的機構(gòu),它們自己為自己簽名,這稱為自簽名證書

有了這些之后就安全了嗎?

emmmmm.....沒有

雖然不是絕對安全,但是現(xiàn)行架構(gòu)下最安全的解決文案了,大大增加了中間人的攻擊成本

結(jié)語

點贊支持、手留余香、與有榮焉

參考

瀏覽器工作原理與實踐

HTTPS:網(wǎng)絡安全攻堅戰(zhàn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容