【全棧修煉】CORS和CSRF修煉寶典

CORS-CSRF.png

《全棧修煉》系列

  1. 《【全棧修煉】OAuth2修煉寶典》

CORS 和 CSRF 太容易混淆了,看完本文,你就清楚了。php

1、CORS 和 CSRF 區別

先看下圖:html

CORS 和 CSRF 區別

二者概念徹底不一樣,另外經常咱們也會看到 XSS ,這裏一塊兒介紹:前端

  1. CORS : Cross Origin Resourse-Sharing 跨站資源共享
  2. CSRF : Cross-Site Request Forgery 跨站請求僞造
  3. XSS : Cross Site Scrit 跨站腳本攻擊(爲與 CSS 區別,因此在安全領域叫 XSS)

2、CORS

1. 概念

跨來源資源共享(CORS),亦譯爲跨域資源共享,是一份瀏覽器技術的規範,提供了 Web 服務從不一樣網域傳來沙盒腳本的方法,以避開瀏覽器的同源策略,是 JSONP 模式的現代版。與 JSONP 不一樣,CORS 除了 GET 請求方法之外也支持其餘的 HTTP 請求。用 CORS 可讓網頁設計師用通常的 XMLHttpRequest,這種方式的錯誤處理比 JSONP 要來的好。另外一方面,JSONP 能夠在不支持 CORS 的老舊瀏覽器上運做。現代的瀏覽器都支持 CORS。
—— 維基百科

核心知識: CORS是一個W3C標準,它容許瀏覽器向跨源服務器,發出XMLHttpRequest 請求,從而克服 AJAX 只能同源使用的限制。git

所以,實現 CORS 通訊的關鍵是服務器。只要服務器實現了 CORS 接口,就能夠跨源通訊,即爲了解決跨域問題github

2. CORS 請求類型

瀏覽器將 CORS 請求分紅兩類:簡單請求(simple request)和非簡單請求(not-so-simple request)。json

簡單請求通常包括下面兩種狀況:segmentfault

狀況 描述
請求方法 請求方法爲:HEADGETPOST
HTTP 頭信息 HTTP 頭信息不超出如下幾種字段:Accept<br/>Accept-Language<br/>Content-Language<br/>Last-Event-ID<br/>Content-Type:只限於三個值 application/x-www-form-urlencodedmultipart/form-datatext/plain

凡是不一樣時知足上面兩個條件,就屬於非簡單請求api

3. 簡單請求的 CORS 流程

當瀏覽器發現咱們的 AJAX 請求是個簡單請求,便會自動在頭信息中,增長一個 Origin 字段。跨域

Origin 字段用來講明本次請求的來源(包括協議 + 域名 + 端口號),服務端根據這個值來決定是否贊成這次請求。瀏覽器

簡單請求的 CORS 流程

Origin 指定的源不在許可範圍,服務器會返回一個正常的 HTTP 迴應,但瀏覽器會在響應頭中發現 Access-Control-Allow-Origin 字段,便拋出異常。

Origin 指定的源在許可範圍,服務器返回的響應頭中會多出幾個頭信息字段:

簡單請求的 CORS 流程

除了上面圖中的頭信息,通常會有如下三個相關頭信息:

  1. Access-Control-Allow-Origin

該字段是必須的。表示許可範圍的域名,一般有兩種值:請求時 Origin 字段的值或者 *(星號)表示任意域名。

  1. Access-Control-Allow-Credentials

該字段可選。布爾值,表示是否容許在 CORS 請求之中發送 Cookie 。若不攜帶 Cookie 則不須要設置該字段。

當設置爲 trueCookie 包含在請求中,一塊兒發送給服務器。還須要在 AJAX 請求中開啓 withCredentials 屬性,不然瀏覽器也不會發送 Cookie

let xhr = new XMLHttpRequest();
xhr.withCredentials = true;

注意: 若是前端設置 Access-Control-Allow-Credentialstrue 來攜帶 Cookie 發起請求,則服務端 Access-Control-Allow-Origin 不能設置爲 *

  1. Access-Control-Expose-Headers

該字段可選。能夠設置須要獲取的字段。由於默認 CORS 請求時,XMLHttpRequest 對象的getResponseHeader()方法只能拿到如下 6 個基本字段:

Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma

4. 非簡單請求的 CORS 流程

非簡單請求狀況如:請求方法是 PUT / DELETE 或者 Content-Type:application/json 類型的請求。

在非簡單請求發出 CORS 請求時,會在正式通訊以前增長一次 「預檢」請求(OPTIONS方法),來詢問服務器,本次請求的域名是否在許可名單中,以及使用哪些頭信息。

「預檢」請求 經過之後,纔會正式發起 AJAX 請求,不然報錯。

4.1 預檢請求

OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
User-Agent: Mozilla/5.0...
...

「預檢」請求 信息中包含兩個特殊字段:

  1. Access-Control-Request-Method

該字段是必須的,用來列出瀏覽器的 CORS 請求會用到哪些 HTTP 方法,上例是 PUT

  1. Access-Control-Request-Headers

指定瀏覽器 CORS 請求額外發送的頭信息字段,上例是 X-Custom-Header

4.2 預檢響應

HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
Connection: Keep-Alive
...

當預檢請求經過之後,在預檢響應頭中,會返回 Access-Control-Allow- 開頭的信息,其中 Access-Control-Allow-Origin 表示許可範圍,值也能夠是 *

當預檢請求拒絕之後,在預檢響應頭中,不會返回 Access-Control-Allow- 開頭的信息,並在控制檯輸出錯誤信息。

3、CSRF

1. 概念

跨站請求僞造(英語:Cross-site request forgery),也被稱爲 one-click attack 或者 session riding,一般縮寫爲 CSRF 或者 XSRF, 是一種挾制用戶在當前已登陸的Web應用程序上執行非本意的操做的攻擊方法。跟跨網站腳本(XSS)相比,XSS 利用的是用戶對指定網站的信任,CSRF 利用的是網站對用戶網頁瀏覽器的信任。
—— 維基百科

核心知識: 跨站點請求僞造請求。

簡單理解: 攻擊者盜用你的身份,以你的名義發送惡意請求。

常見場景:以你名義發送郵件,發消息,盜取你的帳號,甚至於購買商品,虛擬貨幣轉帳等等。

形成影響:我的隱私泄露以及財產安全。

2. CSRF 攻擊流程

CSRF 攻擊流程

上面描述了 CSRF 攻擊的流程,其中受害者完成兩個步驟:

  1. 登陸受信任網站 A ,並在本地生成保存Cookie;
  2. 在不登出 A 狀況下,訪問病毒網站 B;

能夠理解爲:若以上兩個步驟沒有都完成,則不會受到 CSRF 攻擊。

3. 服務端防護 CSRF 攻擊

服務端防護的方式有不少,思想相似,都是在客戶端頁面增長僞隨機數

3.1 Cookie Hashing(全部表單都包含同一個僞隨機數)

最簡單有效方式,由於攻擊者理論上沒法獲取第三方的Cookie,因此表單數據僞造失敗。以 php 代碼爲例:

<?php
    //構造加密的Cookie信息
    $value = "LeoDefenseSCRF";
    setcookie("cookie", $value, time()+3600);
?>

在表單裏增長Hash值,以認證這確實是用戶發送的請求。

<?php
    $hash = md5($_COOKIE['cookie']);
?>
<form method="POST" action="transfer.php">
  <input type="text" name="toBankId">
  <input type="text" name="money">
  <input type="hidden" name="hash" value="<?=$hash;?>">
  <input type="submit" name="submit" value="Submit">
</form>

而後在服務器端進行Hash值驗證。

<?php
    if(isset($_POST['check'])) {
       $hash = md5($_COOKIE['cookie']);
       if($_POST['check'] == $hash) {
            doJob();
        } else {
     //...
      }
    } else {
      //...
    }
?>

這個方法我的以爲已經能夠杜絕99%的CSRF攻擊了,那還有1%呢....因爲用戶的 Cookie 很容易因爲網站的 XSS 漏洞而被盜取,這就另外的1%。

通常的攻擊者看到有須要算Hash值,基本都會放棄了,某些除外,因此若是須要100%的杜絕,這個不是最好的方法。

3.2 驗證碼

思路是:每次用戶提交都須要用戶在表單中填寫一個圖片上的隨機字符串,這個方案能夠徹底解決CSRF,但易用性差,而且驗證碼圖片的使用涉及 MHTML 的Bug,可能在某些版本的微軟IE中受影響。

3.3 One-Time Tokens(不一樣的表單包含一個不一樣的僞隨機值)

須要注意「並行會話的兼容」。若是用戶在一個站點上同時打開了兩個不一樣的表單,CSRF保護措施不該該影響到他對任何表單的提交。考慮一下若是每次表單被裝入時站點生成一個僞隨機值來覆蓋之前的僞隨機值將會發生什麼狀況:用戶只能成功地提交他最後打開的表單,由於全部其餘的表單都含有非法的僞隨機值。必須當心操做以確保CSRF保護措施不會影響選項卡式的瀏覽或者利用多個瀏覽器窗口瀏覽一個站點。

php 實現以下:

  1. 先是 Token 令牌生成函數(gen_token())和 Session 令牌生成函數(gen_stoken()):
<?php
    function gen_token() {
        $token = md5(uniqid(rand(), true));
        return $token;
    }
  function gen_stoken() {
    $pToken = "";
    if($_SESSION[STOKEN_NAME]  == $pToken){
      $_SESSION[STOKEN_NAME] = gen_token();
    }    
    else{ }
  }
?>
  1. WEB表單生成隱藏輸入域的函數: 
<?php
    function gen_input() {
        gen_stoken();
        echo "<input type=\"hidden\" name=\"" . FTOKEN_NAME . "\"
            value=\"" . $_SESSION[STOKEN_NAME] . "\"> ";
  }
?>
  1. WEB表單結構:
<?php
    session_start();
    include("functions.php");
?>
<form method="POST" action="transfer.php">
    <input type="text" name="toBankId">
    <input type="text" name="money">
    <? gen_input(); ?>
    <input type="submit" name="submit" value="Submit">
</FORM>
  1. 服務端覈對令牌

這一步很簡單,不作詳細介紹。

4、XSS

注意: 本文簡單介紹 XSS 知識,具體詳細能夠閱讀 FEWY 寫的 《跨站腳本攻擊—XSS》https://segmentfault.com/a/11...

1. 概念

跨站腳本(英語:Cross-site scripting,一般簡稱爲:XSS)是一種網站應用程序的安全漏洞攻擊,是代碼注入的一種。它容許惡意用戶將代碼注入到網頁上,其餘用戶在觀看網頁時就會受到影響。這類攻擊一般包含了HTML以及用戶端腳本語言。
—— 維基百科

XSS 攻擊,通常是指攻擊者經過在網頁中注入惡意腳本,當用戶瀏覽網頁時,惡意腳本執行,控制用戶瀏覽器行爲的一種攻擊方式。

常見 XSS 危害有:

  • 竊取用戶Cookie,獲取用戶隱私,盜取用戶帳號。
  • 劫持用戶(瀏覽器)會話,從而執行任意操做,例如進行非法轉帳、強制發表日誌、發送電子郵件等。
  • 強制彈出廣告頁面,刷流量,傳播跨站腳本蠕蟲,網頁掛馬等。
  • 結合其餘漏洞,如 CSRF 漏洞,實施進一步的攻擊。

2. XSS 分類

XSS 分類

3. XSS 防護

3.1 方法1:瀏覽器自帶防護 (X-XSS-Protection )

現今主流瀏覽器(Internet Explorer,Chrome 和 Safari)帶有 HTTP X-XSS-Protection 響應頭,當檢測到跨站腳本攻擊(XSS)時,瀏覽器將中止加載頁面。

X-XSS-Protection 響應頭有如下 4 個值:

  • X-XSS-Protection: 0

禁止XSS過濾。

  • X-XSS-Protection: 1

啓用XSS過濾(一般瀏覽器是默認的)。 若是檢測到跨站腳本攻擊,瀏覽器將清除頁面(刪除不安全的部分)。

  • X-XSS-Protection: 1; mode=block

啓用XSS過濾。 若是檢測到攻擊,瀏覽器將不會清除頁面,而是阻止頁面加載。

  • X-XSS-Protection: 1; report=<reporting-uri>

啓用XSS過濾。 若是檢測到跨站腳本攻擊,瀏覽器將清除頁面並使用CSP report-uri指令的功能發送違規報告。

注意:

這並不能徹底防止反射型 XSS,並且也並非全部瀏覽器都支持 X-XSS-Protection,存在兼容性問題。

它只對反射型 XSS 有必定的防護力,其原理也只是檢查 URL 和 DOM 中元素的相關性。

3.2 方法2:轉義

即將經常使用特殊字符進行轉義,避免攻擊者使用構造特殊字符來注入腳本。須要在客戶端和服務端,都對用戶輸入的數據進行轉義。

常見須要轉義的特殊字符如 <>&"'

轉義方法:

function escapeHTML(str) {
    if (!str) return '';
    str = str.replace(/&/g, "&amp;");
    str = str..replace(/</g, "&lt;");
    str = str..replace(/>/g, "&gt;");
    str = str..replace(/"/g, "&quot;");
    str = str..replace(/'/g, "&#39;");
    return str;
};

3.3 方法3:過濾

常見於富文本內容,由於其須要保留 HTML,因此不能直接使用轉義方法,而能夠經過使用白名單,來容許特定的 HTML 標籤及屬性,來抵禦 XSS 攻擊。

3.4 方法4:內容安全策略(CSP)

內容安全策略(Content Security Policy,CSP),實質就是白名單制度,開發者明確告訴客戶端,哪些外部資源能夠加載和執行,大大加強了網頁的安全性。

兩種方法能夠啓用 CSP。

  1. 經過 HTTP 頭信息的 Content-Security-Policy 的字段:
Content-Security-Policy: script-src 'self'; 
                         object-src 'none';
                         style-src cdn.example.org third-party.org; 
                         child-src https:
  1. 經過網頁的 <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:">

上面代碼中,CSP 作了以下配置:

  • 腳本: 只信任當前域名
  • <object>標籤: 不信任任何 URL,即不加載任何資源
  • 樣式表: 只信任 cdn.example.org third-party.org
  • 頁面子內容,如 <frame><iframe>: 必須使用HTTPS協議加載
  • 其餘資源: 沒有限制
  • 啓用後,不符合 CSP 的外部資源就會被阻止加載。

參考文章

  1. 《跨域資源共享 CORS 詳解》
  2. 《CSRF & CORS》
  3. 《淺談CSRF攻擊方式》
  4. 《跨站腳本攻擊—XSS》

關於我

本文首發在 pingan8787我的博客,如需轉載請聯繫本人。
Author 王平安
E-mail pingan8787@qq.com
博 客 www.pingan8787.com
微 信 pingan8787
每日文章推薦 https://github.com/pingan8787...
ES小冊 js.pingan8787.com

微信公衆號

bg

相關文章
相關標籤/搜索