之前介紹過 CSP 1.0 時,有提到目前部分瀏覽器有支援 CSP 2.0
支援度如下圖:
在 CSP level2 新增了部分的 directives 及屬性(如 web worker 針對 外部資源載入的 child-src) ,更多關於 CSP level2 的詳細內容.
這篇僅介紹 CSP level2 針對 inline 程式碼所規範的 hash
與 nonce
,讓 inline 程式碼能較安全且彈性的執行.
我們先來看一個普通的 CSP demo 頁面
header(“Content-Security-Policy: script-src *;”);print “<h1>CSP demo</h1><script src=’https://code.jquery.com/jquery-3.2.1.slim.min.js’></script><script>var my_script = document.createElement(‘script’);my_script.setAttribute(‘src’,’https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore.js’);document.head.appendChild(my_script);</script>”;
實際執行的畫面:
可以看到設置了 CSP script-src *
,預設還是會擋掉 inline script ,在錯誤的訊息中,透露出可以設定 unsafe-inline, hash 及 nonce 來解決這個問題.
- unsafe-inline 解法:
若設置 unsafe-inline 就變成允許所有的 inline 程式碼,這也意味著可以注入 inline 程式碼至頁面上面執行,可能會有 XSS 的疑慮,實務上就會變得較不安全. unsafe-inline 的寫法可以參考這篇. - hash:利用一串產生的 hash 值,類似簽證.來指定符合此 hash 值的外部資源才可以載入.
支援SHA-256
SHA-384
SHA-512
演算法所產生的值,經過base64
編碼後結果.
來看看實際使用 php 的例子吧~<?php $script = "alert('test1') ;"; $hash = hash('sha256', $script, true); $hash = base64_encode($hash); header("Content-Security-Policy: script-src 'sha256-".$hash."'"); print " <h1>CSP demo</h1> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%3E%22.%24script.%22%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" /> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%3Ealert('test2')%3B%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" />"; ?>
可以看到上面利用 php 將
alert('test1');
先做 sha256 hash(記得要輸出 binary data,script 中的空白也都要列入計算),再將 hash 值做一次 base64 編碼.將以上結果輸出至 header CSP policy 中.
以上例子執行後會得到alert('test1');
,然而alert('test2');
則會被瀏覽器阻擋載 - nonce:用法與 hash 類似,但比較簡單,利用一段字串決定是否載入此 inline script 程式碼,來看看以下 php 的例子吧~
<?php $hash = hash('sha256', rand(0, 1000)); header("Content-Security-Policy: script-src 'nonce-".$hash."'"); print " <h1>CSP demo</h1> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%C2%A0nonce%3D%5C%22%22.%24hash.%22%5C%22%3Ealert('test1')%3B%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" /> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%3Ealert('test2')%3B%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" />"; ?>
上面這個例子,每次會產生不同的識別字串(簡單利用隨機值做 hash),讓惡意程式碼不能輕易仿造此
nonce
執行惡意程式碼.
以上介紹針對 hash
與 nonce
這兩個在 CSP level2 所新增對於 inline script 的進階過濾,讓防止 XSS 之餘也能進一步過濾惡意 inline 程式碼.
ps. 若瀏覽器支援 CSP level2,當設置 hash
或 nonce
時會忽略 unsafe-inline
的設置
參考資料:
https://imququ.com/post/content-security-policy-level-2.html