Web 安全以內容安全策略(Content-Security-Policy,CSP)詳解

1.CSP 簡介

內容安全策略(Content Security Policy,簡稱CSP)是一種以可信白名單做機制,來限制網站是否能夠包含某些來源內容,緩解普遍的內容注入漏洞,好比 XSS。 簡單來講,就是咱們可以規定,咱們的網站只接受咱們指定的請求資源。默認配置下不容許執行內聯代碼(<script>塊內容,內聯事件,內聯樣式),以及禁止執行eval() , newFunction() , setTimeout([string], …) 和setInterval([string], …) 。javascript

2.CSP 使用方式

CSP能夠由兩種方式指定: HTTP Header 和 HTML。php

  • 經過定義在HTTP header 中使用:css

    "Content-Security-Policy:" 策略集
  • 經過定義在 HTML meta標籤中使用:html

    <meta http-equiv="content-security-policy" content="策略集">

策略是指定義 CSP 的語法內容。java

若是 HTTP 頭 與 meta 標籤同時定義了 CSP,則會優先採用 HTTP 頭的 。git

定義後,凡是不符合 CSP策略的外部資源都會被阻止加載。github

3.CSP 語法

3.1 策略

每一條策略都是指令與指令值組成:web

Content-Security-Policy:指令1 指令值1

策略與策略之間用分號隔開,例如:ajax

Content-Security-Policy:指令1 指令值1;指令2 指令值2;指令3 指令值3

在一條策略中,若是一個指令中有多個指令值,則指令值之間用空號隔開:json

Content-Security-Policy:指令a 指令值a1 指令值a2

3.2 CSP 指令

  • default-src : 定義針對全部類型(js/image/css/font/ajax/iframe/多媒體等)資源的默認加載策略,若是某類型資源沒有單獨定義策略,就使用默認的。
  • script-src : 定義針對 JavaScript 的加載策略。
  • style-src : 定義針對樣式的加載策略。
  • img-src : 定義針對圖片的加載策略。
  • font-src : 定義針對字體的加載策略。
  • media-src : 定義針對多媒體的加載策略,例如:音頻標籤<audio>和視頻標籤<video>
  • object-src : 定義針對插件的加載策略,例如:<object><embed><applet>
  • child-src :定義針對框架的加載策略,例如: <frame>,<iframe>
  • connect-src : 定義針對 Ajax/WebSocket 等請求的加載策略。不容許的狀況下,瀏覽器會模擬一個狀態爲400的響應。
  • sandbox : 定義針對 sandbox 的限制,至關於 <iframe>的sandbox屬性。
  • report-uri : 告訴瀏覽器若是請求的資源不被策略容許時,往哪一個地址提交日誌信息。
  • form-action : 定義針對提交的 form 到特定來源的加載策略。
  • referrer : 定義針對 referrer 的加載策略。
  • reflected-xss : 定義針對 XSS 過濾器使用策略。

3.3 CSP 指令值

指令值 說明
* 容許加載任何內容
'none' 不容許加載任何內容
'self' 容許加載相同源的內容
www.a.com 容許加載指定域名的資源
*.a.com 容許加載 a.com 任何子域名的資源
https://a.com 容許加載 a.com 的 https 資源
https: 容許加載 https 資源
data: 容許加載 data: 協議,例如:base64編碼的圖片
'unsafe-inline' 容許加載 inline 資源,例如style屬性、onclick、inline js、inline css等
'unsafe-eval' 容許加載動態 js 代碼,例如 eval()

4.CSP 例子

  • 例子1

    全部內容均來自網站的本身的域:

    Content-Security-Policy:default-src 'self'
  • 例子2

    全部內容都來自網站本身的域,還有其餘子域(假如網站的地址是:a.com):

    Content-Security-Policy:default-src 'self' *.a.com
  • 例子3

    網站接受任意域的圖像,指定域(a.com)的音頻、視頻和多個指定域(a.com、b.com)的腳本

    Content-Security-Policy:default-src 'self';img-src *;media-src a.com;script-src a.com b.com
  • 在線 CSP編寫的網址:http://cspisawesome.com/

5.CSP 默認特性

  • 阻止內聯代碼執行

    CSP除了使用白名單機制外,默認配置下阻止內聯代碼執行是防止內容注入的最大安全保障。
    這裏的內聯代碼包括:<script>塊內容,內聯事件,內聯樣式。

    (1) script代碼,<script>……<scritp>

    對於<script>塊內容是徹底不能執行的。例如:

    <script>getyourcookie()</script>

    (2) 內聯事件。

    <a href="" onclick="handleClick();"></a> 
    <a href="javascript:handleClick();"></a>

    (3) 內聯樣式

    <div style="display:none"></div>

    雖然CSP中已經對script-src和style-src提供了使用」unsafe-inline」指令來開啓執行內聯代碼,但爲了安全起見仍是慎用」unsafe-inline」。

  • EVAL相關功能被禁用

    用戶輸入字符串,而後通過eval()等函數轉義進而被看成腳本去執行。這樣的攻擊方式比較常見。因而乎CSP默認配置下,eval() , newFunction() , setTimeout([string], …) 和setInterval([string], …)都被禁止運行。
    好比:

    alert(eval("foo.bar.baz"));
    window.setTimeout("alert('hi')", 10); window.setInterval("alert('hi')", 10); 
    new Function("return foo.bar.baz");

    若是想執行能夠把字符串轉換爲內聯函數去執行。

    alert(foo && foo.bar && foo.bar.baz);
    window.setTimeout(function() { alert('hi'); }, 10);
    window.setInterval(function() { alert('hi'); }, 10);
    function() { return foo && foo.bar && foo.bar.baz };

    一樣CSP也提供了」unsafe-eval」去開啓執行eval()等函數,但強烈不建議去使用」unsafe-eval」這個指令。

6.CSP 分析報告

能夠用report-uri指令使瀏覽器發送HTTP POST請求把攻擊報告以JSON格式傳送到你指定的地址。接下來給你們介紹你的站點如何配置來接收攻擊報告。

  • 啓用報告

    默認狀況下,違規報告不會發送。爲了能使用違規報告,你必須使用report-uri指令,並至少提供一個接收地址。

    Content-Security-Policy: default-src self; report-uri http://reportcollector.example.com/collector.cgi

    若是想讓瀏覽器只彙報報告,不阻止任何內容,能夠改用Content-Security-Policy-Report-Only頭。

  • 違規報告語法

    該報告JSON對象包含如下數據:

    blocked-uri:被阻止的違規資源
    document-uri:攔截違規行爲發生的頁面
    original-policy:Content-Security-Policy頭策略的全部內容
    referrer:頁面的referrer
    status-code:HTTP響應狀態
    violated-directive:違規的指令
  • 違規報告例子

    http://example.com/signup.html 中CSP 規定只能加載cdn.example.com的CSS樣式。

    Content-Security-Policy: default-src 'none'; style-src cdn.example.com; report-uri /test/csp-report.php

    signup.html中的代碼相似與這樣:

    <!DOCTYPE html>
    <html>
     <head>
       <title>Sign Up</title>
       <link rel="stylesheet" href="css/style.css">
     </head>
     <body>
       ... Content ...
     </body>
    </html>

    你能從上面的代碼找出錯誤嗎?策略是隻容許加載cdn.example.com中的CSS樣式。但signup.html試圖加載本身域的style.css樣式。這樣違反了策略,瀏覽器會向 http://example.com/test/csp-report.php 發送POST請求提交報告,發送格式爲JSON格式。

    {
      "csp-report": {
        "document-uri": "http://example.com/signup.html",
        "referrer": "",
        "blocked-uri": "http://example.com/css/style.css",
        "violated-directive": "style-src cdn.example.com",
        "original-policy": "default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports",
      }
    }

    你從上面能夠看到blocked-uri給出了詳細的阻斷地址 http://example.com/css/style.css,但也並非每次都是這樣。好比試圖從 http://anothercdn.example.com/stylesheet.css 加載CSS樣式時,瀏覽器將不會傳送完整的路徑,只會給出 http://anothercdn.example.com/ 這個地址。這樣作是爲了防止泄漏跨域的敏感信息。

    服務端csp-report.php代碼能夠這樣寫:

    <?php 
    $file = fopen('csp-report.txt', 'a');
    $json = file_get_contents('php://input');
    $csp = json_decode($json, true);
    foreach ($csp['csp-report'] as $key => $val) {
        fwrite($file, $key . ': ' . $val . "
    ");
    }
    fwrite($file, 'End of report.' . "
    ");
    fclose($file);
    ?>

7.參考連接

相關文章
相關標籤/搜索