完整閲讀本文大約需要5分鐘。
開始閲讀之前,先上一道面試題:
CSRF攻擊和XSS攻擊之間,有什麼聯繫?
什麼是CSRF攻擊
CSRF攻擊即Cross-site request forgery,跨站請求偽造,直白來説就是惡意網站偽裝成用户,向被害網站發起操作請求。
為了方便理解,做了一張圖,攻擊流程如下:
- 用户登錄受害網站,瀏覽器把獲取的身份憑證保存在本地cookie中;
- 用户被誘導打開黑客網站,黑客網站向受害網站服務器發起一個惡意請求,由於cookie的取用規則,這時瀏覽器會自動帶上第一步中的身份憑證;
- 受害網站服務端對惡意請求校驗,發現有身份憑證,惡意請求被成功受理;
如果黑客的操作是將用户的錢轉到自己的賬户,那麼這時,他已經卷款跑路了。
如何發起CSRF攻擊
-
誘導用户跳轉到黑客網站,網站的HTML中有一個自動提交的隱藏表單,只要用户打開頁面,就會發起轉賬請求;
<form action="http://bank/transfer" method=POST> <input type="hidden" name="account" value="user" /> <input type="hidden" name="amount" value="10000" /> <input type="hidden" name="for" value="hacker" /> </form> <script> document.forms[0].submit(); </script> -
在受害網站的評論區放置一個a標籤,點擊跳轉時發起偽造請求;
<a href="http://bank/transfer?amount=10000&for=hacker" taget="_blank"> 大八卦 <a/> -
在受害網站的評論區發表偽裝的圖片,實際是一個惡意請求,瀏覽過評論區的用户都會被黑客攻擊;

怎麼預防CSRF攻擊
CSRF攻擊有兩個特點:
- CSRF攻擊的來源通常是黑客網站(外域),因為更好控制;
- CSRF攻擊無法獲取用户的身份憑證,只能是冒用;
所以可以想到以下幾個方法:
檢驗請求來源
HTTP 請求頭中有兩個字段會標識請求的來源:origin和referer。這兩個字段不受前端控制,會誠實地告訴服務器請求來自哪裏。
origin是請求來源的域名部分,但是在302重定向、以及IE11上不會顯示。
所以還需要referer輔助,它是一個完整的url路徑,但可靠性不如origin。
SameSite cookie
CSRF攻擊能成功,正是所有向受害網站發起的請求,都會被自動帶上cookie。
Chrome意識到這個問題後起草了一份協議:向瀏覽器注入cookie時,開發者可以標註哪些請求才會帶上。
被標註為strict的cookie只有本域的請求才能帶上。
被標註為lax的cookie在跳轉到新頁面時可以帶上。因為如果全部設置為strict,在百度搜索並打開淘寶,默認是沒有登錄的,用户體驗會很差。
CSRF Token
在本站發起的請求中,加一個攻擊者無法獲取的token,也可以區別出正常請求和惡意請求。這個token和瀏覽器自動攜帶的cookie不一樣,是需要前端手動帶上的。
但這種方案對服務器壓力較大,需要維護一個session對收到的token做校驗。
雙重cookie
相較於與token,雙重cookie不需要服務器做額外擴容。只需要在請求中加一個額外的字段,其值和cookie一致。因為上文提到過,攻擊者沒法獲取到cookie,只是在發起請求時會攜帶。
在服務端收到請求時,如果沒有和cookie值一樣的額外字段,就可以認為是來自惡意網站。
其他通用方式
CSRF攻擊大多來自第三方網站,但就像上文提到過的鏈接跳轉和圖片偽裝,本站的請求也可能造成威脅。所以我們還需要對UGC內容做一些過濾。
- 當前用户打開其他用户填寫的鏈接時,需告知風險;
- 不直接使用用户上傳的圖片,先在自己的服務器轉存;
結語
回到開頭提出的問題:
XSS攻擊的核心是注入代碼,獲取用户信息;CSRF攻擊的核心是藉助身份憑證,偽裝用户發起操作請求。
兩者往往是前後出現的:黑客會先通過XSS攻擊獲取到用户的身份憑證,上傳到黑客網站,然後就可以利用它偽裝成用户,發起操作請求。