iT邦幫忙

2022 iThome 鐵人賽

DAY 27
0
Modern Web

這些那些你可能不知道我不知道的Web技術細節系列 第 27

你可能不知道的CSS Injection

前言

當你只是簡單地設置了一個CSP以後:

Content-Security-Policy: defalut-src 'self';

會發現誒~為什麼inline-script也不工作了?

<script type="text/javascript">console.log('Hello, World');</script>

要解決這個問題,同樣必須計算腳本雜湊值,然後設置新的內容安全政策:

Content-Security-Policy: defalut-src 'self';script-src 'sha256-2cq9aRSFdLqAC0FNx8cqcUjxA2Bmk5ZjlSvbIPQ1x/U=';

當然不止這種做法,還可以設置nonce等方式。

因為JavaScript腳本相對可以取得更多的資源,禁止執行不確定的腳本蠻合理的。不過你會發現inline-style,也就是CSS,也被禁止了:

  <style type="text/css" media="screen">
   h1 {
       color: yellow;
       background-color: blue;
   }
  </style>

同樣可以用設置新的內容安全政策處理:

Content-Security-Policy: defalut-src 'self';script-src 'sha256-2cq9aRSFdLqAC0FNx8cqcUjxA2Bmk5ZjlSvbIPQ1x/U=';style-src 'sha256-8j4F2Pm6diktYuw618QVgnj57dHdVprLADb9s3N2NCI='

資訊安全的三個面向

破壞完整性

在談談為什麼要封鎖inline-style之前,先來說說資訊安全的三個主要面向:機密性、完整性、可用性。


之前變更串改了頁面顯示內容,這是破壞了資料的完整性。可能會想說那時引用外部資源才會遇到的資源,跟自己寫的inline-style又有什麼關係?然而,inline-style真的是自己寫的...嗎?下面是一段我之前為了釐清嘗試的程式碼片段:

<h1>hello</h1>

<button onclick="onclick1()">click me</button>

HTML內容很簡單,就只是一個h1標題和按鈕而已。如果點擊按鈕會觸發onclick1(),而onclick1()

function onclick1() {
  let style = document.createElement('style')

  style.innerText = `
h1 {
  color: blue;
}
`

  document.body.appendChild(style)
  let button = document.createElement('button')
  button.innerText = 'click me';
  button.setAttribute('onclick', "onclickBtn()");
  let script = document.createElement('script')
  script.innerText = `
  function onclickBtn() {
   console.log('hello');
  }
  `;
  document.body.append(button, script);
 }

對於JavaScript能夠操作DOM並不稀奇,建立新元素也不是什麼罕見的事情。不同的是建立了一個style元素區塊,並使用.innerText寫入inline-style。不僅如此,當這個元素區塊被加入的DOM之後,inline-style的申明規則還可以發揮作用!同樣的inline-script也可以用類似方式建立發揮作用,而且這或許不是唯一手法。

在了解這些以後,也就不難理解為什麼設置了內容安全政策,瀏覽器預設也會阻擋inline-style和inline-script。

破外機密性

CSS注入(CSS Injection)並不是只有這樣的風險。在CSS可以用@import匯入其他CSS檔案:

@import url;

或是使用url()載入影像作為元素背景等等:

border-image: url(https://example.com/images/myImg.jpg) 30 fill / 30px / 30px space;

關於前者已經有粗略了解了,但對於後者可能會很懷疑,圖片載入不是算簡單請求嗎?有什麼安全風險?

要知道瀏覽器請求可能帶有Referer的資訊,就可以知道從哪裡來,這麼一來就有可能洩漏瀏覽行為。

信件中夾帶的外部圖片資源也是同樣道理:寄件者先準備一個獨一無二讀取極小圖片的唯一連接,當你開啟信件讀取圖片,就會發送一個請求到這個唯一端點,那麼寄件者就可以透過是否有過請求,進而來判斷收件者是否已經閱讀信件。這也是為什麼有些信箱工具預設會阻擋外部資源請求。像這類作用通稱為Beacon。Beacon不全都是惡意的,對於開發者就是會有這樣的需求,後來也出現了相關的API

但不光是如此,若沒有正確設置Cookies,這個請求就有可能連同Cookie也跨站送出,讓不該收到的收到,這樣同樣有可能偽造瀏覽狀態的問題。

這也是為什麼,啟用內容安全政策以後,圖片外部資源也被阻擋了下來,甚至不能自己寫:

<img src="http://b.127.0.0.1.nip.io:8000/1.jpg" alt="" />

如果需要就必須在內容安全政策添加圖片允許來源:

Content-Security-Policy: defalut-src 'self';script-src 'sha256-2cq9aRSFdLqAC0FNx8cqcUjxA2Bmk5ZjlSvbIPQ1x/U=';style-src 'sha256-8j4F2Pm6diktYuw618QVgnj57dHdVprLADb9s3N2NCI=';img-src http://b.127.0.0.1.nip.io:8000;

這邊提到的也很可能並不是全部資安風險。手段漏洞層出不窮,在這個資訊時代,其實不單是開發維運人員,使用者也應該多加留意相關知識。

參考資料

本文同時發表於我的隨筆


上一篇
你可能不知道的內容安全策略(Content-Security-Policy, CSP)
下一篇
你可能不知道的Web API -- postMessage
系列文
這些那些你可能不知道我不知道的Web技術細節33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言