使用 security 是 3.3.2 版本
1、 启用 CSRF ,security 自带功能
1 @Bean 2 public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { 3 // 禁用默认的登录和退出 4 httpSecurity.formLogin(AbstractHttpConfigurer::disable); 5 httpSecurity.logout(AbstractHttpConfigurer::disable); 6 //开启 CSRF 7 httpSecurity.csrf(csrf -> csrf 8 .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())); 9 httpSecurity.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); 10 // 配置拦截规则 11 httpSecurity.authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests 12 // 放行白名单 13 .requestMatchers(CollUtil.isEmpty(ignoreWhiteProperties.getWhites()) ? new String[0] : 14 ignoreWhiteProperties.getWhites().toArray(new String[0])).permitAll() 15 // 需要鉴权认证 16 .anyRequest().authenticated()); 17 18 // 添加过滤器 19 httpSecurity.addFilterBefore(authTokenFilter(), UsernamePasswordAuthenticationFilter.class); 20 21 // 异常时认证处理流程 22 httpSecurity.exceptionHandling( 23 exceptionHandlingConfigurer -> exceptionHandlingConfigurer.authenticationEntryPoint( 24 authenticationEntryPoint()).accessDeniedHandler(accessDeniedHandler())); 25 return httpSecurity.build(); 26 }
2、 spring gateway 中添加过滤器先进行添加36位 空字符,再进行 base64 编码,重新写入请求头中
1 package com.changan.gateway.filter; 2 3 import org.springframework.cloud.gateway.filter.GatewayFilterChain; 4 import org.springframework.cloud.gateway.filter.GlobalFilter; 5 import org.springframework.stereotype.Component; 6 import org.springframework.web.server.ServerWebExchange; 7 import reactor.core.publisher.Mono; 8 9 import java.nio.charset.StandardCharsets; 10 import java.util.Base64; 11 12 /** 13 * CSRF 在头信息中额外生成36个空字符,使其校验通过 14 */ 15 @Component 16 public class CsrfGlobalFilter implements GlobalFilter { 17 18 private final StringBuffer preHead = new StringBuffer(); 19 20 public CsrfGlobalFilter(){ 21 // 生成36位随机数 22 preHead.append("\u0000".repeat(36)); 23 } 24 25 @Override 26 public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { 27 //获取前端传递的 X-Xsrf-Token 头信息 28 String headerValue = exchange.getRequest().getHeaders().getFirst("X-Xsrf-Token"); 29 //在 X-Xsrf-Token 头信息之前添加 36 位空字符 30 headerValue = preHead + headerValue; 31 //base64 加密 32 String encodedValue = Base64.getEncoder().encodeToString(headerValue.getBytes(StandardCharsets.UTF_8)); 33 34 exchange.getRequest().mutate() 35 .header("X-Xsrf-Token", encodedValue) 36 .build(); 37 38 return chain.filter(exchange); 39 } 40 41 }
总结:
Security 自带 CSRF 功能,他会在第一次 POST 请求后会在 cookie 中存储一个 csrf_token 值,前端有的框架会自动识别,下次请求会自动携带上,就可以防止 CSRF 攻击
注意:
按常理是这样的,可是 3.3.2 版本跟进源码发现,需要有一个 36 位 前缀随机数,但是后续需要异或运算= csrf_token 本身才放行。这里应该是要通过计算得出。
上述为了能实现功能,暂时直接用 “空字符” 也能成功
标签:csrf,Spring,36,filter,CSRF,import,Security,httpSecurity From: https://www.cnblogs.com/hylr/p/18539798