Java 无法验证提供的 CSRF 令牌,因为在 Spring Security 中找不到您的会话

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38004035/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 19:54:16  来源:igfitidea点击:

Could not verify the provided CSRF token because your session was not found in spring security

javaspring-securitycsrfspring-restcontroller

提问by Haseeb Wali

I am using spring security along with java config

我正在使用 spring 安全性和 java 配置

@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());

I am using PostMan for testing my REST services. I get 'csrf token' successfully and I am able to login by using X-CSRF-TOKENin request header. But after login when i hit post request(I am including same token in request header that i used for login post request) I get the following error message:

我正在使用 PostMan 来测试我的 REST 服务。我成功获得了“csrf 令牌”,并且可以通过X-CSRF-TOKEN在请求标头中使用来登录。但是登录后,当我点击发布请求(我在用于登录发布请求的请求标头中包含相同的令牌)时,我收到以下错误消息:

HTTP Status 403 - Could not verify the provided CSRF token because your session was not found.

HTTP 状态 403 - 无法验证提供的 CSRF 令牌,因为未找到您的会话。

Can any one guide me what I am doing wrong.

任何人都可以指导我我做错了什么。

回答by kungyu

I have solved it by adding the last attribute in my login page,maybe it will do yo a favor.

我已经通过在我的登录页面中添加最后一个属性来解决它,也许它会帮你一个忙。

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"  isELIgnored="false"%>

回答by Freelancer

According to spring.io:

根据 spring.io :

When should you use CSRF protection? Our recommendation is to use CSRF protection for any request that could be processed by a browser by normal users. If you are only creating a service that is used by non-browser clients, you will likely want to disable CSRF protection.

什么时候应该使用 CSRF 保护?我们的建议是对普通用户可以由浏览器处理的任何请求使用 CSRF 保护。如果您仅创建供非浏览器客户端使用的服务,您可能希望禁用 CSRF 保护。

So to disable it:

所以要禁用它:

@Configuration
public class RestSecurityConfig extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable();
  }
}

Note:CSRF protection is enabled by default with Java Configuration

注意:Java 配置默认启用 CSRF 保护

回答by Dario Seidl

Disabling CSRF protection is a bad idea.

禁用 CSRF 保护是一个坏主意。

Spring will automatically generate a new CSRF token after each request, and you need to include it in all HTTP requests with side-effects (PUT, POST, PATCH, DELETE).

Spring会在每次请求后自动生成一个新的CSRF token,需要将其包含在所有有副作用的HTTP请求中 (PUT, POST, PATCH, DELETE).

In Postman you can use a test in each request to store the CSRF token in a global, e.g. when using CookieCsrfTokenRepository

在 Postman 中,您可以在每个请求中使用测试来将 CSRF 令牌存储在全局中,例如在使用时 CookieCsrfTokenRepository

pm.globals.set("xsrf-token", postman.getResponseCookie("XSRF-TOKEN").value);

And then include it as a header with key X-XSRF-TOKENand value {{xsrf-token}}.

然后将其作为带有 keyX-XSRF-TOKEN和 value的标头包含在内{{xsrf-token}}

回答by GuoJunjun

try this: @Override protected boolean sameOriginDisabled() { return true;}

尝试这个: @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;
    }
}

source: WebSocket Security: Disable CSRF within WebSockets

来源:WebSocket 安全性:在 WebSockets 中禁用 CSRF

回答by Dmitri Algazin

Came to same error just with POST methods, was getting 403 Forbidden "Could not verify the provided CSRF token because your session was not found."

仅使用 POST 方法就出现相同的错误,得到 403 Forbidden “无法验证提供的 CSRF 令牌,因为未找到您的会话。”

After exploring some time found solution by adding @EnableResourceServer annotation to config.

通过在配置中添加@EnableResourceServer 注释,探索了一段时间后找到了解决方案。

Config looks like that (spring-boot.version -> 1.4.1.RELEASE, spring-security.version -> 4.1.3.RELEASE, spring.version -> 4.3.4.RELEASE)

配置看起来像这样(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();
}

}

回答by George Siggouroglou

I get this error message (HTTP Status 403 - Could not verify the provided CSRF token because your session was not found.) when I do a JS fetchAJAX call without using the credentials: "same-origin"option.

HTTP Status 403 - Could not verify the provided CSRF token because your session was not found.当我在不使用该选项的情况下执行 JS fetchAJAX 调用时,我收到此错误消息 ( ) credentials: "same-origin"

Wrong way

错误的方法

fetch(url)
.then(function (response) { return response.json(); })
.then(function (data) { console.log(data); })

Correct way

正确方式

fetch(url, {
    credentials: "same-origin"
})
.then(function (response) { return response.json(); })
.then(function (data) { console.log(data); })

回答by Parthanaux

This is an old question but this might help someone. I had the similar issue and this is how I was able to resolve it.

这是一个老问题,但这可能对某人有所帮助。我遇到了类似的问题,这就是我能够解决它的方法。

In order for the CSRF to work with the REST API you need to obtain a CSRF token via API before every single call and use that token. Token is different every time and cannot be re-used.

为了让 CSRF 与 REST API 一起工作,您需要在每次调用之前通过 API 获取 CSRF 令牌并使用该令牌。Token每次都不一样,不能重复使用。

Here is the controller to get the CSRF token:

这是获取 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());
    }

Additionally, you might consider configuring your Spring app to disable the CSRF for the REST API endpoints. To quote an article I've read somewhere:

此外,您可能会考虑将 Spring 应用程序配置为禁用 REST API 端点的 CSRF。引用我在某处读过的一篇文章:

I'm very certain that CSRF tokens on a REST endpoint grant zero additional protection. As such, enabling CSRF protection on a REST endpoint just introduces some useless code to your application, and I think it should be skipped.

我非常确定 REST 端点上的 CSRF 令牌授予零额外保护。因此,在 REST 端点上启用 CSRF 保护只会为您的应用程序引入一些无用的代码,我认为应该跳过它。

Hope this helps.

希望这可以帮助。