當你只是簡單地設置了一個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;
這邊提到的也很可能並不是全部資安風險。手段漏洞層出不窮,在這個資訊時代,其實不單是開發維運人員,使用者也應該多加留意相關知識。
本文同時發表於我的隨筆