博客 / 詳情

返回

springboot~傳統WEB應用開啓CSRF

CSRF 是什麼?

CSRF(Cross-Site Request Forgery,跨站請求偽造) 是一種常見的Web安全漏洞。攻擊者利用受害者已經登錄的合法會話,誘使受害者執行非本意的操作。

簡單比喻:

想象你在咖啡店會員卡里有錢,你每次消費只需要説“用會員卡支付”。攻擊者偽裝成服務員,在你面前説“用會員卡轉賬100元到XXX賬户”。因為你已經在咖啡店的系統中“登錄”了(身份已認證),系統就會執行這個操作。

CSRF攻擊原理:

攻擊流程:

  1. 用户登錄:用户登錄正常的網站A(如銀行網站),獲得登錄憑證(Cookie/Session)
  2. 用户訪問惡意網站:用户在同一個瀏覽器中訪問了攻擊者的網站B
  3. 惡意請求:網站B通過隱藏表單、圖片src、AJAX等方式,向網站A發送請求
  4. 自動攜帶憑證:瀏覽器會自動攜帶網站A的Cookie
  5. 網站A執行請求:網站A看到合法Cookie,誤以為是用户的自願操作

攻擊示例:

<!-- 惡意網站上的代碼 -->
<img src="https://your-bank.com/transfer?to=hacker&amount=10000" width="0" height="0" />

<!-- 或隱藏表單 -->
<form action="https://your-bank.com/change-email" method="POST">
  <input type="hidden" name="email" value="hacker@evil.com">
</form>
<script>document.forms[0].submit();</script>

為什麼有時要禁用CSRF保護?

適用禁用場景:

  1. 純API服務(無瀏覽器交互)

    # 移動App通過API訪問後端
    # 使用Token認證(JWT/OAuth),而不是Session
    Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
    
  2. 僅提供非狀態改變的操作

    GET /api/users          # 只讀操作,通常不需要CSRF
    POST /api/transfer      # 寫操作,需要CSRF
    
  3. 微服務內部通信

    # 服務間調用使用服務憑證,而不是用户會話
    service-to-service: true
    
  4. 某些特殊框架/場景

    // GraphQL通常使用token而不是session
    // 或某些實時通信應用
    

具體框架中的禁用示例:

Spring Security:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()  // 禁用CSRF
            .authorizeRequests()
            .anyRequest().authenticated()
            .and()
            .httpBasic();  // 使用HTTP Basic認證
    }
}

Django:

# settings.py
CSRF_COOKIE_SECURE = False  # 禁用CSRF
# 或針對特定視圖
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def api_view(request):
    pass

CSRF保護機制對比:

保護機制 工作原理 適用場景
CSRF Token 服務器生成Token,表單/請求必須攜帶 傳統Web應用
SameSite Cookie Cookie僅在同站請求中發送 現代瀏覽器支持
雙重Cookie驗證 客户端讀取Cookie並附加到請求 兼容性較好
Referer檢查 檢查請求來源 簡單但不可靠
無(禁用) 不驗證 純API、內部服務

何時應該啓用/禁用CSRF?

應該啓用CSRF的場景:

  • ✅ 傳統的基於Session的Web應用
  • ✅ 用户通過瀏覽器訪問的表單提交
  • ✅ 需要用户交互的操作(轉賬、修改數據)
  • ✅ 使用Cookie/Session進行身份認證

可以禁用CSRF的場景:

  • ✅ 純REST API,使用JWT/OAuth Token認證
  • ✅ 僅限移動App訪問的後端服務
  • ✅ 微服務間的內部通信
  • ✅ 只讀的公共API
  • ✅ 使用其他認證方式(API Key、HMAC簽名)

禁用CSRF後的替代安全方案:

# 替代方案示例:

1. JWT Token認證:
   每次請求攜帶: Authorization: Bearer <token>
   
2. API Key + Secret:
   請求籤名: X-Signature: sha256(api_secret + request_data)
   
3. OAuth 2.0:
   使用Access Token進行授權
   
4. CORS限制:
   Access-Control-Allow-Origin: https://trusted-domain.com
   
5. Rate Limiting:
   限制請求頻率防止濫用

最佳實踐建議:

// 在Spring中,可以針對不同端點配置不同的CSRF策略
public class SecurityConfig {
    protected void configure(HttpSecurity http) {
        http
            // 對Web頁面啓用CSRF
            .csrf(csrf -> csrf
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .csrfTokenRequestHandler(new CsrfTokenRequestAttributeHandler())
            )
                .requireCsrfProtectionMatcher(
                    new RequestMatcher() {
                        public boolean matches(HttpServletRequest request) {
                            // 僅對特定路徑啓用CSRF
                            return request.getRequestURI().startsWith("/web/");
                        }
                    })
            .and()
            // API端點使用無狀態認證
            .authorizeRequests()
                .antMatchers("/api/**").authenticated()
                .and()
            .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS); // API無狀態
    }
}

驗證 CSRF 是否生效

  1. 檢查 Cookie:登錄後查看瀏覽器是否有 XSRF-TOKEN Cookie
  2. 測試請求
    • 直接發送 POST 請求應該被拒絕(403 錯誤)
    • 攜帶正確的 CSRF Token 的請求應該成功
  3. 檢查響應頭:某些配置下,響應頭會包含 CSRF Token
# 使用 curl 測試
# 1. 先獲取 CSRF Token(從登錄後的 Cookie 或響應頭)
# 2. 發送帶 CSRF Token 的請求
curl -X POST http://localhost:8080/api/test \
  -H "Content-Type: application/json" \
  -H "X-XSRF-TOKEN: YOUR_CSRF_TOKEN" \
  -H "Cookie: XSRF-TOKEN=YOUR_CSRF_TOKEN" \
  -d '{"data": "test"}'

總結:

禁用CSRF的前提條件:

  1. 應用不使用Cookie/Session進行身份認證
  2. 請求來源可控(如僅限移動App、內部服務)
  3. 已實施同等或更強的安全措施替代
  4. 確認攻擊面不會因此擴大

黃金法則:

如果用户通過瀏覽器訪問你的網站,並且網站使用了Cookie/Session,那麼永遠不要禁用CSRF保護。只有在完全理解風險並有替代方案時,才考慮為API服務禁用CSRF。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.