CSRF 攻擊

Python喵發表於2024-10-05

CSRF (Cross-Site Request Forgery) 保護機制。CSRF 攻擊是指攻擊者透過偽裝成使用者嚮應用傳送惡意請求,而這些請求是使用者在不知情的情況下發起的。例如,如果使用者在一個銀行網站上登入,然後訪問了一個惡意網站,該惡意網站可能包含一個自動提交的表單,這個表單會向銀行網站傳送請求來轉賬,因為使用者的瀏覽器會自動附加上之前從銀行網站獲取的認證資訊(如 cookie),所以這個請求會被視為合法的。

為了防止 CSRF 攻擊,Django 提供了 CsrfViewMiddleware 中介軟體,該中介軟體預設是啟用的。它是如何工作的呢?

  1. 生成 CSRF Token:當使用者訪問需要 CSRF 保護的頁面時(通常是 POST 表單所在的頁面),Django 會在響應中設定一個名為 csrftoken 的 cookie,並且在 HTML 表單中插入一個隱藏欄位 <input type="hidden" name="csrfmiddlewaretoken" value="...">,其值與 cookie 中的值相同。

  2. 驗證 CSRF Token:當使用者提交表單時,Django 會檢查請求中的 csrfmiddlewaretoken 欄位的值是否與 csrftoken cookie 中的值匹配。只有當兩者匹配時,請求才會被認為是有效的,否則將返回一個 HTTP 403 錯誤。

在 Django 應用中使用 CSRF 保護非常簡單:

  • 表單中新增 CSRF 令牌:如果你正在建立一個 HTML 表單,確保使用 {% csrf_token %} 模板標籤來自動插入 CSRF 令牌。

    html
    深色版本
    <form method="post">
        {% csrf_token %}
        <!-- 其他表單欄位 -->
    </form>

Django REST Framework (DRF) 主要用於構建 Web API,與傳統的 Django 檢視相比,API 更多的是面向機器而非直接面向使用者的互動。因此,在 DRF 中,預設情況下 CSRF 驗證是被禁用的,這是因為:

  1. API 設計原則:RESTful API 通常設計為無狀態的,這意味著伺服器不應該儲存任何關於客戶端的狀態資訊。CSRF 保護依賴於 session 或 cookie 來追蹤使用者狀態,這與 REST 的無狀態性相沖突。

  2. 認證機制:DRF 常常使用 token 認證、OAuth2 等更安全的認證機制,這些機制本身就能有效防止未授權的請求。例如,一個 API 客戶端在每次請求時都需要提供一個有效的認證 token,這種 token 通常比基於 cookie 的認證更難以被竊取或濫用。

  3. 使用場景:DRF 構建的 API 通常不是直接由瀏覽器訪問的,而是由移動應用、桌面應用或其他後端服務呼叫。這些客戶端通常不會共享瀏覽器的 cookie,因此它們不受 CSRF 攻擊的影響。

  4. 靈活性:在某些情況下,你可能確實希望為特定的 API 檢視啟用 CSRF 保護。DRF 提供了足夠的靈活性來實現這一點。你可以透過在檢視或檢視集中使用 @csrf_protect 裝飾器或 SessionAuthentication 類來啟用 CSRF 保護。

雖然 DRF 預設不啟用 CSRF 保護,但這並不意味著在所有情況下都不需要考慮 CSRF 防護。如果你的應用涉及到透過瀏覽器直接訪問的 API 端點(例如,單頁應用或傳統的 Web 應用),那麼你可能需要重新考慮 CSRF 保護。在這種情況下,可以考慮以下方法來增強安全性:

  • 啟用 SessionAuthentication:在 DRF 的檢視或檢視集中使用 SessionAuthentication,這樣可以啟用 CSRF 保護。
  • 自定義認證:根據你的需求自定義認證類,結合使用 token 和 CSRF 保護。
  • 教育使用者:提醒使用者不要在公共計算機上登入敏感應用,並定期更改密碼。

總之,DRF 不強制要求 CSRF 保護,但開發者應根據具體的應用場景和安全需求來決定是否以及如何實施 CSRF 保護。

相關文章