我正在使用spring security和java config
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/*").hasRole("ADMIN")
.and()
.addFilterAfter(new CsrfTokenResponseHeaderBindingFilter(), CsrfFilter.class)
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.formLogin()
.successHandler(authenticationSuccessHandler)
.failureHandler(new SimpleUrlAuthenticationFailureHandler());
我正在使用PostMan来测试我的REST服务。我得到了csrf令牌'成功,我可以在请求标头中使用X-CSRF-TOKEN
登录。但登录后,当我点击发布请求(我在请求标题中包含相同的令牌,我用于登录发布请求)时,我收到以下错误消息:
HTTP状态403 - 无法验证提供的CSRF令牌,因为找不到您的会话。
任何人都可以指导我做错了什么。
答案 0 :(得分:72)
根据spring.io:
什么时候应该使用CSRF保护?我们的建议是使用CSRF 保护浏览器可以处理的任何请求 普通用户。如果您只是创建使用的服务 非浏览器客户端,您可能希望禁用CSRF保护。
所以要禁用它:
@Configuration
public class RestSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
}
}
注意:默认情况下,使用Java配置启用CSRF保护
答案 1 :(得分:2)
禁用CSRF保护是一个坏主意。
Spring会在每次请求后自动生成一个新的CSRF令牌,您需要将其包含在所有带有副作用的HTTP请求中(PUT, POST, PATCH, DELETE).
在Postman中,您可以在每个请求中使用测试将CSRF令牌存储在全局中,例如使用CookieCsrfTokenRepository
pm.globals.set("xsrf-token", postman.getResponseCookie("XSRF-TOKEN").value);
然后将其包含为包含密钥X-XSRF-TOKEN
和值{{xsrf-token}}
的标头。
答案 2 :(得分:2)
尝试:@Override protected boolean sameOriginDisabled() { return true;}
@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
...
// Determines if a CSRF token is required for connecting. This protects against remote
// sites from connecting to the application and being able to read/write data over the
// connection. The default is false (the token is required).
@Override
protected boolean sameOriginDisabled() {
return true;
}
}
答案 3 :(得分:0)
仅使用POST方法,就遇到相同的错误,得到403 Forbidden“因为找不到您的会话,所以无法验证提供的CSRF令牌。”
在探索了一段时间后,通过在配置中添加@EnableResourceServer批注找到了解决方案。
Config看起来像这样(spring-boot.version-> 1.4.1.RELEASE,spring-security.version-> 4.1.3.RELEASE,spring.version-> 4.3.4.RELEASE)
@Configuration
@EnableWebSecurity
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends ResourceServerConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(inMemoryUserDetailsManager()).passwordEncoder(passwordEncoder());
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.httpBasic();
http.sessionManagement().sessionCreationPolicy(STATELESS);
http.csrf().disable();
http.authorizeRequests().anyRequest()
.permitAll();
}
private InMemoryUserDetailsManager inMemoryUserDetailsManager() throws IOException {
// load custom properties
Properties properties = new Properties();
return new InMemoryUserDetailsManager(properties);
}
private PasswordEncoder passwordEncoder() {
return new TextEncryptorBasedPasswordEncoder(textEncryptor());
}
private TextEncryptor textEncryptor() {
return new OpenSslCompatibleTextEncryptor();
}
}
答案 4 :(得分:0)
我在不使用HTTP Status 403 - Could not verify the provided CSRF token because your session was not found.
选项的情况下执行JS 获取 AJAX调用时收到此错误消息(credentials: "same-origin"
。
错误的方式
fetch(url)
.then(function (response) { return response.json(); })
.then(function (data) { console.log(data); })
正确的方式
fetch(url, {
credentials: "same-origin"
})
.then(function (response) { return response.json(); })
.then(function (data) { console.log(data); })
答案 5 :(得分:0)
这是一个古老的问题,但这可能会对某人有所帮助。我遇到了类似的问题,这就是我能够解决的问题。
为了使CSRF与REST API一起使用,您需要在每次调用之前通过API获取CSRF令牌并使用该令牌。令牌每次都不同,因此无法重复使用。
这是获取CSRF令牌的控制器:
@RequestMapping(value = "/csrf", method = RequestMethod.GET)
public ResponseEntity<CSRFDTO> getCsrfToken(HttpServletRequest request) {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
return ResponseEntity.ok(CSRFDTO.builder()
.headerName(csrf.getHeaderName())
.token(csrf.getToken())
.build());
}
此外,您可能会考虑将Spring应用程序配置为禁用REST API端点的CSRF。引用我在某处阅读的文章:
我非常确定REST端点上的CSRF令牌会给予零附加保护。因此,在REST端点上启用CSRF保护只会向您的应用程序引入一些无用的代码,我认为应该跳过这些代码。
希望这会有所帮助。
答案 6 :(得分:-4)
我已经通过在我的登录页面中添加最后一个属性来解决它,也许它会帮到你。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" isELIgnored="false"%>