關於網路那些事...

網路行銷,SEO,網路趨勢,教學文章,網頁設計,生活時事

Content Security Policy 內容安全策略

| Comments

https://www.smashingmagazine.com/2016/09/content-security-policy-your-future-best-friend/
http://www.ruanyifeng.com/blog/2016/09/csp.html

Content Security Policy - 簡稱 CSP,是一個瀏覽器安全保護使用者的策略。

主要用於降低 cross-site scripting (XSS) 的風險。

網站傳送Header時﹑夾帶 CSP header 告訴瀏覽器哪些是合法的內容,哪些是不合法的。

在基本的規則中,Header meta name 命名為 Content-Security-Policy
接下來就可以定義規則
定義的方式可以依照你使用的環境及語法而定
首先可以直接使用HTML meta的方式來定義
例如:

<meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:">

也可以透過 HTTP 的header訊息 : Content-Security-Policy
這裡主要會針對PHP header的方式來定義
這裡是一個PHP範例:

<?php
    header("Content-Security-Policy: <your directives>");
?>

通常,在定義CSP規則時,可以定義合法的圖片來源、script 來源、css來源、iframe來源
當然,也可以直接讓本文的script合法,但不建議這樣處理。例如,我們會再本頁HTML中用

這裡,做一個演示
index.php

<?php
    header("Content-Security-Policy: 
      default-src 'self' ;
      script-src 'self' www.google.com.tw; 
      style-src 'self' data: ;
      img-src 'self' www.google.com.tw ;
      frame-src 'self' ;");
?><!DOCTYPE html>
<html>
<head>
  <title>CSP</title>
  <meta charset="utf-8">
</head>
<body>

  <h1>允許本地及Google.com.tw來源</h1>
  <p>
    <h2>Google 圖片</h2>
    <img src="https://www.google.com.tw/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png">
  </p>
  <p>
    <h2>Yahoo 圖片(不合法)</h2>
    <img src="https://s1.yimg.com/rz/d/yahoo_frontpage_zh-Hant-TW_s_f_p_bestfit_frontpage_2x.png">
  </p>

  <script>console.log('這是不合法的');</script>
  
  <script type="text/javascript" src="script.js"></script>

</body>
</html>

在上面範例中,本地的js 引用 script.js,內容為:
script.js

console.log('from script.js ,合法');

規則說明

CSP 有分為Level 1及Level 2,底下將分別介紹

default-src

可以套用 'self' 設定, # self = same port, same domain name, same protocol => OK

script-src 'self' www.google-analytics.com ;
style-src

可以套用 data: ,表示在css中,允許崁入的內容,讓我們在CSS中設定的一些來源(例如圖片或字體)可以被允許

style-src 'self' data: ;

CSP Level 1的規則

這裡可以查詢第一級的瀏覽器支援狀況 http://caniuse.com/#feat=contentsecuritypolicy

img-src

設定允許的圖片來源

connect-src

允許 XMLHttpRequest (AJAX), WebSocket 或者 EventSource 來源

font-src

允許的字體來源

object-src

允許一些plugin來源(例如: <object>, <embed>, <applet>)

media-src

允許的 <audio><video> 來源

CSP Level 2 規則

這裡可以查詢到第二級瀏覽器支援情況 http://caniuse.com/#feat=contentsecuritypolicy2

child-src

可以定義一些 <frame><iframe>的授權內容,這個設定取代了第一級的frame-src(已被棄用)

form-action

可以定義 <form> 的有效來源

frame-ancestors

可以用來定義這些崁入外部資源的標籤的授權內容: <frame>, <iframe>, <object>, <embed><applet>

upgrade-insecure-requests

只示 user agents 重寫

由於Level 2 在目前ie11還無法支援,因此,為了有更好的向下兼容(backwards-compatibility),會建議同時寫Level 1及Level 2規則,例如,將 child-src 的內容複製一份,並貼在 frame-src 中。

在Level 1 規則中,只允許以網址來建立白名單(whitelisted),例如: www.foo.com 。在Level 2規則中,則開放更詳細的路徑可以被列在白名單中,例如: www.foo.com/some/folder

用firefox查詢CSP設定

firefox可以查詢出你設定的內容
在開發者模式中(F12),同時按 Shift + F2,並且輸入 security csp,就可以列出指令跟設定內容。

如何執行 inline script

假設在一些情況,一定要用inline script (在本頁中直接寫js),可以直接在script-src 中以 'nonce-名稱' 來定義授權的範圍,接著script標籤中宣告 nonce='名稱' 為合法inline script
範例如下:

<?php

header("Content-Security-Policy: 
      default-src 'self' ;
      script-src 'self' 'nonce-wozaaaaa';
      style-src 'self' data: ;
      img-src 'self' ;
      frame-src 'self' ;");
?><!DOCTYPE html>
<html>
<head>
  <title>CSP</title>
  <meta charset="utf-8">
  <script nonce="wozaaaaa">alert('Hello');</script>
</head>

線上使用的建議

將CSP實際拿來應用時,會讓人產生一些疑慮,因為CSP是直接透過header來激活,並且毫無彈性,如果你忘了授權一些來源,將會導致該來源地引用項目都被阻擋在外。

幸好,有兩種方式可以更彈性的解決這個問題

REPORT-URI

CSP 可以透過 report-uri 告訴瀏覽器,將錯誤提示以JSON的格式傳送傳送到指定的位置。
例如,這裡指定傳送到csp-parser.php中

<?php report-uri /csp-parser.php ;?>

因此,在csp-parser.php中,可以接收到瀏覽器傳送過來的訊息。
這裡做一個範例,接收到訊息之後,以email的形式傳送(實際使用時,不建議用email。會讓你的信箱爆炸)

<?php
$data = file_get_contents('php://input');

    if ($data = json_decode($data, true)) {
     $data = json_encode(
      $data,
      JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES
      );
     mail(EMAIL, SUBJECT, $data);
    }?>

或者,也可以透過其他方式,例如記錄在一個log文件、或透過第三方平台來協助記錄這些訊息
可以參考這裡,有提供一些範例:
https://github.com/nico3333fr/CSP-useful/tree/master/report-uri

REPORT-ONLY

第一次決定將它用在實際案例時,你可能會擔心一些無法預期的意外,因此,CSP提供了一項 REPORT-ONLY功能,就如字義所述,只要回報即可。讓你可以告訴瀏覽器,當有不合法的來源或事件發生時,只要通知我,不必真的阻擋。
格式如下:

<?php
    header("Content-Security-Policy-Report-Only: <your directives>");
?>

因此,你可以先在線上環境使用report-only 及 report-uri,當測試一段時間後,沒有問題,就能正式啟用。

最後

我們可以清楚知道,CSP 對於造訪你網站的使用者而言,是一個相當重要的設定,他可以有效地阻擋XSS攻擊,避免一些未經授權的來源被執行。

另一方面,開發者透過CSP的設定,你會非常清楚你用了哪些東西,對front-end的架構更佳的了解,讓你可以用更好的方式重構。

仍有一些地方需要留意,再一些主流瀏覽器中,使用CSP可能會造成書籤無法產生。
但是,仍建議不要再CSP中設定成允許小書籤(bookmarkets),雖然這個bug可能會對你造成不方便,現在各家瀏覽器廠商也正在思考怎麼解決這個問題,在這之前,如果這個bug不影響你,仍然相當建議你可以開始使用CSP。


最後,如果你喜歡這篇文章,請幫忙點個讚



最新文章推薦

討論

comments powered by Disqus