小議 CSRF 攻擊

CSRF(Cross-site request forgery),即跨站請求僞造,本質就是攻擊者僞造你的身份發送請求。

攻擊流程

在 Google 上找了一張流程圖:

在這裏插入圖片描述

  1. 用戶訪正常登錄訪問 mybank.com 網站,登錄成功後,mybank 服務端會產生 Cookie 信息給瀏覽器;
  2. 在用戶不登出 mybank.com 的情況下訪問攻擊網站 attacker.com 的攻擊鏈接,此鏈接會直接訪問 mybank.com,此時會攜帶着 mybank 的 Cookie,從而執行惡意腳本;

首先這裏不能只侷限於 Cookie,比如 Token,也是可以通過抓包分析獲取的。也就是說 CSRF 的本質就是攻擊者僞造你的身份發送請求,那麼身份用什麼體現呢,就是 Cookie 或者 Token。

示例

先看一個簡單的模擬例子:

用戶登錄頁面:
在這裏插入圖片描述

<form action="/login" method="post" enctype="multipart/form-data">
    <p> 用戶名:<input type="text" name="username">
    <p> 密碼:<input type="text" name="password">
        <input type="submit" value="提交">
</form>

後臺代碼:

    @RequestMapping("login")
    public Object login(@RequestParam("username")String username, @RequestParam("password")String password, HttpServletResponse response){
        Cookie cookie = new Cookie("8080Cookie", "123456");
        cookie.setPath("/");
        response.addCookie(cookie);
        return "OK";
    }

用戶登錄成功後這裏會生成一個 Cookie:

在這裏插入圖片描述
攻擊頁面:

在這裏插入圖片描述

<h2>attack</h2>
<form action="http://localhost:8080/pay" method="post" enctype="multipart/form-data">
    <input type="text" name="money" value = "1000" style="visibility: hidden;">

    <input type="submit" value="恭喜你中獎了">
</form>

這裏可以做成比如超鏈接等,如果用戶點擊了這個按鈕,那麼實際會攜帶着用戶的 Cookie 信息去訪問之前的系統,即“僞造你的身份發送請求”:

在這裏插入圖片描述

後端代碼:

    @RequestMapping("pay")
    public Object pay(@RequestParam("money")Integer money, HttpServletRequest request){
        System.out.printf("獲取了 Cookie:%s",
                Stream.of(request.getCookies()).collect(Collectors.toMap(Cookie::getName, Cookie::getValue)).get("8080Cookie"));
        return String.format("扣掉了 %d 元錢",money);
    }

這樣會出現跨站請求成功:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-XhgrC04Z-1586873711619)(./6.png)]

如果無法獲取 Cookie 的話,後端代碼會拋出 NPE 異常。

防禦方式

總得來說沒有絕對的防禦方式,其實將破解過程設置的越複雜,也算是一種成功的防禦。

通過 HTTP 請求頭中的 Referer 和 Origin 屬性

這兩種方式其實並不算可靠,這裏借用一篇博客中的描述(相關鏈接在文末):

  • referer屬性

記錄了該http請求的來源地址,但有些場景不適合將來源URL暴露給服務器,所以可以設置不用上傳,並且referer屬性是可以修改的,所以在服務器端校驗referer屬性並沒有那麼可靠

  • origin屬性

通過XMLHttpRequest、Fetch發起的跨站請求或者Post方法發送請求時,都會帶上origin,所以服務器可以優先判斷Origin屬性,再根據實際情況判斷是否使用referer判斷。

CSRF Token

這種應該是常用的一種方式,就是瀏覽器向服務器發送請求後,服務器端生成一個隨機的 Token,然請求的時候就攜帶這個 Token,服務器端再進行校驗,關於這個可以參看這兩篇博客:

  • https://blog.csdn.net/Dongguabai/article/details/81150989
  • https://blog.csdn.net/Dongguabai/article/details/81151035

設置 SameSite 屬性

Chrome 51 開始,瀏覽器的 Cookie 新增加了一個 SameSite 屬性,用來防止 CSRF 攻擊和用戶追蹤。

關於 SameSite 屬性,可以參看:

  • http://www.ruanyifeng.com/blog/2019/09/cookie-samesite.html

但是在動靜分離的情況下,這時候靜態資源會單獨部署,這時候 SameSite 屬性限制比較大。所以最常見的還是基於 Token 的方式去處理。

References

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章