「每日一題」CSRF 是什麼?

先從一個故事說起(故事純屬虛構,惡意模仿後果自負):

小谷最近遭遇電信詐騙被騙的傾家蕩產,於是他想到了報復社會。在知乎上狂點800個沒有幫助1000個舉報後,他決定做點正事干票撈錢的生意。

「很多視頻網站都有贈送禮品的功能,假如所有人都贈送我個禮物,我再轉賣掉,不就發財啦」小谷尋思著。

說干就敢,經過一番折騰測試,小谷發現視頻網站贈送禮物的介面是:

https://xxxx.com/gift/send?target=someone&giftId=ab231n

, 原來只要用戶在登錄狀態下請求這個地址,就能給名為someone的用戶贈送禮品ab231。

那如何才能讓其他用戶請求這個介面呢?其實只要用戶點擊就行,「色誘是最好的陷阱」回想起自己被騙的經過,小谷猥瑣狠狠的打了一行文字 ——「想要的都在這裡,今夜註定讓你無眠~~ 飢人谷-最有愛的前端學習社區」,然後在各個群組裡回復。

經過一天等待,有幾個上鉤的,但遠遠達不到預期,「有沒有更自動的辦法,讓用戶只要看到即使不點也能上鉤呢?」。小谷開始對整個網站功能逐一過濾,突然他眼前一亮,在用戶評論編輯框內看到了上傳外鏈圖片的功能。「如果把這個 url 作為圖片填進去,上傳後會在評論區創建一個img 標籤,src 對應的就是這個地址。當用戶打開頁面後這個 img 就會自動載入圖片也就是發送這個請求,這樣一來凡是打開這個頁面的人不論是不是點擊這個鏈接都會給贈送禮物,perfect!」 小谷為自己的聰明才智驚嘆。

又過了一天,果然源源不斷的禮物送了過來。這個時候小谷隱隱有些擔心起來,雖然禮物送的都很小,但贈送都是有歷史記錄的,用戶查看歷史記錄肯定會起疑心,能不能幫用戶刪除這條贈送記錄呢?經過測試,發現刪除贈送記錄的介面地址是

https://xxxx.com/gift/deleteRecordn

, 介面類型為POST,請求參數為 { giftId:"ab231"}。 用戶無法通過點擊一個鏈接在不知情的情況下發送 POST 請求,怎麼辦呢?於是,小谷構造了一個頁面:

<body>n哈哈,給你開了個玩笑,莫生氣~n<iframe name="hiddenIframe" stylex="display:none"></iframe>n<form action="https://xxxx.com/gift/deleteRecord" id="form" method="post" stylex="visibility:hidden" target="hiddenIframe">nt<input type="text" name="giftId" value="ab231">n</form>n<script>ntdocument.getElementById(form).submit();ntlocation.href = "http://xxxx.com";n</script>n</body>n

當用戶點開這個頁面的鏈接後,會自動發送 POST 請求,然後跳轉到原始首頁。這樣用戶既在不知情的情況下贈送了禮品,又在不知情的情況下刪除了贈送記錄。大功告成後,小谷購買了個廣告機在各大論壇狂發....

一周之後,警察??叔叔來敲門了,咚????

上面小谷的攻擊流程就是典型的 CSRF (Cross Site Request Forgery)攻擊,中文名:跨站請求偽造。其原理是攻擊者構造網站後台某個功能介面的請求地址,誘導用戶去點擊或者用特殊方法讓該請求地址自動載入。用戶在登錄狀態下這個請求被服務端接收後會被誤以為是用戶合法的操作。對於 GET 形式的介面地址可輕易被攻擊,對於 POST 形式的介面地址也不是百分百安全,攻擊者可誘導用戶進入帶 Form 表單可用POST方式提交參數的頁面。

後續......

xxxx視頻網站不斷接到用戶舉報,自己的禮品莫名丟失。經過排查發現有攻擊者利用 CSRF 進行攻擊,報警後趕緊讓公司的安全部門的小飢來修復漏洞。

小飢梳理了一遍公司網站所有的介面,發現很多介面都存在這個問題。於是採用了anti-csrf-token的方案。 具體方案如下:

  1. 服務端在收到路由請求時,生成一個隨機數,在渲染請求頁面時把隨機數埋入頁面(一般埋入 form 表單內,<input type="hidden" name="_csrf_token" value="xxxx">)
  2. 服務端設置setCookie,把該隨機數作為cookie或者session種入用戶瀏覽器

  3. 當用戶發送 GET 或者 POST 請求時帶上_csrf_token參數(對於 Form 表單直接提交即可,因為會自動把當前表單內所有的 input 提交給後台,包括_csrf_token)

  4. 後台在接受到請求後解析請求的cookie獲取_csrf_token的值,然後和用戶請求提交的_csrf_token做個比較,如果相等表示請求是合法的。

(上圖是某電商網站的真實設置,這裡頁面上設置的 token和session里設置的token 雖然不直接相等,但 md5(1474357164624) === 4bd4e512b0fbd9357150649adadedd4e,後台還是很好計算的)

安全部的Leader 看了看小飢的方案,「方案出的很贊, 不過還有幾點需要注意一下」:

  1. Token 保存在 Session 中。假如 Token 保存在 Cookie 中,用戶瀏覽器開了很多頁面。在一些頁面 Token 被使用消耗掉後新的Token 會被重新種入,但那些老的 Tab 頁面對應的 HTML 里還是老 Token。這會讓用戶覺得為啥幾分鐘前打開的頁面不能正常提交?
  2. 盡量少用 GET。假如攻擊者在我們的網站上傳了一張圖片,用戶在載入圖片的時候實際上是向攻擊者的伺服器發送了請求,這個請求會帶有referer表示當前圖片所在的頁面的 url。 而如果使用 GET 方式介面的話這個 URL 就形如:

    https://xxxx.com/gift?giftId=aabbcc&_csrf_token=xxxxxn

    ,那相當於攻擊者就獲取了_csrf_token,短時間內可以使用這個 token 來操作其他 GET 介面。

「這個項目,就由你來推動實施,晚上加加班爭取這兩天搞定~」

作者:若愚,本文為作者辛苦原創,轉載需私信向作者申請

快快加入前端技術交流 QQ6群:108801207,加群密碼:js funs 。這裡有

  • 嚴格的審核制度,杜絕廣告、推銷。尊重、有愛、互助,任何水平的前端愛好者都能找到歸宿
  • 每日一題,每周資源推薦,精彩博客推薦,工作、筆試、面試經驗交流解答,免費直播課,群友輕分享... ,數不盡的福利免費送

推薦閱讀:

從零學習前端開發·HTML
你可能不知道的 css 內容塊
Webpack 速成
[翻譯]React還是Vue:你該如何選擇?

TAG:前端开发 | 前端入门 | 前端工程师 |