簡體   English   中英

無法驗證提供的CSRF令牌,因為在spring security中找不到您的會話

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

我正在使用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 token',我可以在請求標頭中使用X-CSRF-TOKEN登錄。 但登錄后我點擊發布請求(我在請求標題中包含相同的令牌,我用於登錄發布請求)我收到以下錯誤消息:

HTTP狀態403 - 無法驗證提供的CSRF令牌,因為找不到您的會話。

任何人都可以指導我做錯了什么。

根據spring.io:

什么時候應該使用CSRF保護? 我們的建議是對普通用戶可以由瀏覽器處理的任何請求使用CSRF保護。 如果您只創建非瀏覽器客戶端使用的服務,則可能需要禁用CSRF保護。

所以要禁用它:

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

注意: Java配置默認啟用CSRF保護

試試這個: @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:在WebSockets中禁用CSRF

禁用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}}的標題包含{{xsrf-token}}

獲得了與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();
}

}

我收到此錯誤消息( HTTP Status 403 - Could not verify the provided CSRF token because your session was not found. )當我在不使用credentials: "same-origin"執行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); })

這是一個老問題,但這可能對某人有所幫助。 我有類似的問題,這就是我能夠解決它的方式。

為了使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保護只會為您的應用程序引入一些無用的代碼,我認為應該跳過它。

希望這可以幫助。

我已經通過在我的登錄頁面中添加最后一個屬性來解決它,也許它會幫到你。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM