淺析Spring?Security如何防止CSRF攻擊
一、CSRF 攻擊簡介
CSRF(Cross-Site Request Forgery)攻擊,即跨站請求偽造攻擊,是一種利用用戶已登錄的身份,在用戶不知情的情況下,強制其執(zhí)行非預(yù)期操作的攻擊方式。攻擊者通常會通過偽造的請求,誘使用戶在已登錄的應(yīng)用程序中執(zhí)行惡意操作,例如轉(zhuǎn)賬、修改個人信息等。
二、Spring Security 防止 CSRF 攻擊的機制
1. 默認(rèn)啟用 CSRF 保護
從 Spring Security 4.0 開始,默認(rèn)情況下會啟用 CSRF 保護。這意味著對于 PATCH、POST、PUT 和 DELETE 方法的請求,Spring Security 會自動進行 CSRF 驗證。
2. CSRF 令牌的生成與驗證
Spring Security 通過生成唯一的 CSRF 令牌(Token)來防止 CSRF 攻擊。具體流程如下:
- 生成 CSRF 令牌:服務(wù)器在處理請求時,會生成一個唯一的 CSRF 令牌,并將其存儲在用戶的會話(HttpSession)或 Cookie 中。
- 客戶端提交 CSRF 令牌:客戶端在提交表單或發(fā)送 AJAX 請求時,需要將 CSRF 令牌包含在請求中。通常,這個令牌會作為表單的一個隱藏字段或請求頭的一部分發(fā)送。
- 服務(wù)器驗證 CSRF 令牌:服務(wù)器在接收到請求后,會從請求中提取 CSRF 令牌,并與存儲在會話或 Cookie 中的令牌進行比較。如果兩者一致,則認(rèn)為請求是合法的;如果不一致,則認(rèn)為是 CSRF 攻擊,服務(wù)器會拒絕該請求。
3. 配置與自定義
開啟或關(guān)閉 CSRF 保護:可以通過配置來開啟或關(guān)閉 CSRF 保護。例如,在基于 Java 配置的項目中,可以通過以下代碼關(guān)閉 CSRF 保護:
http.csrf().disable();
或者在基于 XML 配置的項目中,使用以下代碼:
<security:csrf disabled="true"/>
自定義 CSRF 令牌存儲方式:Spring Security 提供了 CsrfTokenRepository
接口,開發(fā)者可以實現(xiàn)該接口來自定義 CSRF 令牌的存儲和獲取方式。默認(rèn)實現(xiàn)是 HttpSessionCsrfTokenRepository
,它將 CSRF 令牌存儲在 HttpSession 中。
4. 在請求中包含 CSRF 令牌
表單提交:在 HTML 表單中,可以通過 Thymeleaf 等模板引擎自動包含 CSRF 令牌。例如:
<form action="/submit" method="POST"> <input type="hidden" name="_csrf" value="${_csrf.token}" /> <button type="submit">Submit</button> </form>
AJAX 請求:在使用 AJAX 提交請求時,需要手動將 CSRF 令牌添加到請求頭中。例如,使用 jQuery 時可以這樣操作:
$.ajax({ url: '/submit', type: 'POST', headers: { 'X-CSRF-TOKEN': $('meta[name="_csrf"]').attr('content') }, data: { // Your data here }, success: function(response) { console.log(response); }, error: function(xhr, status, error) { console.error('Error:', error); } });
在 HTML 中,需要包含 CSRF 令牌的 meta 標(biāo)簽:
<meta name="_csrf" content="${_csrf.token}" />
三、最佳實踐
- 始終啟用 CSRF 保護:除非有充分的理由,否則應(yīng)始終啟用 CSRF 保護,以確保應(yīng)用程序的安全性。
- 使用 HTTPS:通過使用 HTTPS,可以防止攻擊者攔截和篡改請求,從而提高應(yīng)用程序的安全性。
- 限制 CSRF 令牌的作用域:可以配置 CSRF 令牌僅對特定的端點有效,從而減少潛在的安全風(fēng)險。
- 定期更新依賴:及時更新 Spring Security 和其他相關(guān)依賴,以修復(fù)已知的安全漏洞。
四、方法補充
Spring Security 防止 CSRF 攻擊
使用 security 是 3.3.2 版本
1、 啟用 CSRF ,security 自帶功能
@Bean public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { // 禁用默認(rèn)的登錄和退出 httpSecurity.formLogin(AbstractHttpConfigurer::disable); httpSecurity.logout(AbstractHttpConfigurer::disable); //開啟 CSRF httpSecurity.csrf(csrf -> csrf .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())); httpSecurity.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); // 配置攔截規(guī)則 httpSecurity.authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests // 放行白名單 .requestMatchers(CollUtil.isEmpty(ignoreWhiteProperties.getWhites()) ? new String[0] : ignoreWhiteProperties.getWhites().toArray(new String[0])).permitAll() // 需要鑒權(quán)認(rèn)證 .anyRequest().authenticated()); // 添加過濾器 httpSecurity.addFilterBefore(authTokenFilter(), UsernamePasswordAuthenticationFilter.class); // 異常時認(rèn)證處理流程 httpSecurity.exceptionHandling( exceptionHandlingConfigurer -> exceptionHandlingConfigurer.authenticationEntryPoint( authenticationEntryPoint()).accessDeniedHandler(accessDeniedHandler())); return httpSecurity.build(); }
2、 spring gateway 中添加過濾器先進行添加36位 空字符,再進行 base64 編碼,重新寫入請求頭中
package com.changan.gateway.filter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import java.nio.charset.StandardCharsets; import java.util.Base64; /** * CSRF 在頭信息中額外生成36個空字符,使其校驗通過 */ @Component public class CsrfGlobalFilter implements GlobalFilter { private final StringBuffer preHead = new StringBuffer(); public CsrfGlobalFilter(){ // 生成36位隨機數(shù) preHead.append("\u0000".repeat(36)); } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { //獲取前端傳遞的 X-Xsrf-Token 頭信息 String headerValue = exchange.getRequest().getHeaders().getFirst("X-Xsrf-Token"); //在 X-Xsrf-Token 頭信息之前添加 36 位空字符 headerValue = preHead + headerValue; //base64 加密 String encodedValue = Base64.getEncoder().encodeToString(headerValue.getBytes(StandardCharsets.UTF_8)); exchange.getRequest().mutate() .header("X-Xsrf-Token", encodedValue) .build(); return chain.filter(exchange); } }
總結(jié):
Security 自帶 CSRF 功能,他會在第一次 POST 請求后會在 cookie 中存儲一個 csrf_token 值,前端有的框架會自動識別,下次請求會自動攜帶上,就可以防止 CSRF 攻擊
注意:
按常理是這樣的,可是 3.3.2 版本跟進源碼發(fā)現(xiàn),需要有一個 36 位 前綴隨機數(shù),但是后續(xù)需要異或運算= csrf_token 本身才放行。這里應(yīng)該是要通過計算得出。
上述為了能實現(xiàn)功能,暫時直接用 “空字符” 也能成功
五、總結(jié)
Spring Security 提供了強大的 CSRF 防護機制,通過生成和驗證 CSRF 令牌,有效防止了 CSRF 攻擊。開發(fā)者可以通過配置和自定義來滿足不同的安全需求,同時遵循最佳實踐,確保應(yīng)用程序的安全性。
到此這篇關(guān)于淺析Spring Security如何防止CSRF攻擊的文章就介紹到這了,更多相關(guān)Spring Security防CSRF攻擊內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
教你如何精準(zhǔn)統(tǒng)計出你的接口"QPS"
今天小編就為大家分享一篇關(guān)于QPS的精準(zhǔn)計算方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2021-08-08java阿拉伯?dāng)?shù)字轉(zhuǎn)中文數(shù)字
這篇文章主要為大家詳細介紹了java實現(xiàn)阿拉伯?dāng)?shù)字轉(zhuǎn)換為中文數(shù)字,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-04-04Spring?Boot實現(xiàn)JWT?token自動續(xù)期的實現(xiàn)
本文主要介紹了Spring?Boot實現(xiàn)JWT?token自動續(xù)期,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-12-12