环境项目结构在禁用 CSRF 防护的情况下,使用 POST 请求在启用 CSRF 防护的情况下,使用 POST 请求参考
Spring Security 默认启用 CSRF (Cross Site Request Forgery) 防护。如果你需要提交一个 POST 请求,那么,你需要在请求中携带 CSRF 值,或者禁用 CSRF 防护。
操作系统:
Windows 10 x64
集成开发环境:
Spring Tool Suite 4 Version: 4.14.0.RELEASE Build Id: 202203131612
Postman(客户端):
Postman for Windows Version 7.36.7 win32 10.0.19044 / x64项目结构
参考:
- Spring Security - 11 允许匿名访问某些资源Spring Security - 12 模拟 JDBC 获取用户信息进行认证
假设在应用中存在一个用于用户注册的接口,如下(第 23 ~ 32 行):
package com.mk.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import lombok.extern.slf4j.Slf4j;
@Controller
@Slf4j
public class HelloController {
// 其他...
@PostMapping(path = "register")
@ResponseBody
public Map register(String username, String password) {
Map map = new HashMap<>();
map.put("username", username);
map.put("password", password);
return map;
}
}
为了使匿名用户也能访问这个接口,我们需要在 WebSecurityConfigurer 配置类中做一些简单的配置,添加匿名访问的路径(第 21 ~ 24 行):
package com.mk.security.config.annotation.web.configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
//@Configuration
@EnableWebSecurity
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
// 其他...
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin(); // Specifies to support form based authentication.
http.authorizeRequests(customizer -> {
String anonymous[] = { "/register" };
// Specify that URLs are allowed by anyone.
customizer.antMatchers(anonymous).permitAll();
// Any request are allowed by any authenticated user.
customizer.anyRequest().authenticated();
});
}
}
在没有禁用 CSRF 防护的情况下,使用 Postman 提交一个 POST 请求,我们将得到这样的返回信息:
这是因为 Spring Security 默认启用 CSRF 防护。如果你需要提交一个 POST 请求,那么,你需要在请求中携带 CSRF 值,或者禁用 CSRF 防护。
想要禁用 CSRF 防护,只需在 WebSecurityConfigurer 配置类的 configure(HttpSecurity) 方法中,添加如下配置即可(第 10 ~ 12 行):
@EnableWebSecurity
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
// 其他...
@Override
protected void configure(HttpSecurity http) throws Exception {
// 其他...
http.csrf(customizer -> {
customizer.disable();
});
}
}
重启应用之后,使用 Postman 提交一个 POST 请求,我们将得到预期的返回信息:
在启用 CSRF 防护的情况下,使用 POST 请求在启用 CSRF 防护的情况下,使用 POST 请求,需要额外提交一个 CSRF 值。
想要获取 CSRF 值,只需在应用中添加一个控制器类,通过 Spring 注入 CsrfToken 参数,然后返回即可(第 19 ~ 22 行):
package com.mk.security.controller;
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CsrfController {
@GetMapping("/csrf")
public CsrfToken csrf(CsrfToken token) {
return token;
}
}
此外,我们需要允许用户能够匿名访问这个接口,修改 WebSecurityConfigurer 配置类,添加允许匿名访问的路径(第 21 ~ 24 行):
package com.mk.security.config.annotation.web.configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
//@Configuration
@EnableWebSecurity
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
// 其他...
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin(); // Specifies to support form based authentication.
http.authorizeRequests(customizer -> {
String anonymous[] = { "/csrf", "/register" };
// Specify that URLs are allowed by anyone.
customizer.antMatchers(anonymous).permitAll();
// Any request are allowed by any authenticated user.
customizer.anyRequest().authenticated();
});
// http.csrf(customizer -> {
// customizer.disable();
// });
}
}
重启应用之后,使用 Postman 访问 http://127.0.0.1:8080/csrf 获取 CSRF 值:
记住 CSRF 值,然后在访问 http://127.0.0.1:8080/register 时,一起提交这个 CSRF 值,我们将得到预期的返回信息:
参考Spring Security / Features / Protection Against Exploits / CSRF
Spring Security / Servlet Applications / Protection Against Exploits / Cross Site Request Forgery (CSRF) for Servlet Environments



