MissingCsrfTokenException:无法验证提供的 CSRF 令牌,因为找不到您的会话
Posted
技术标签:
【中文标题】MissingCsrfTokenException:无法验证提供的 CSRF 令牌,因为找不到您的会话【英文标题】:MissingCsrfTokenException: Could not verify the provided CSRF token because your session was not found 【发布时间】:2018-10-08 10:42:42 【问题描述】:我正在阅读 spring 文档:Adding CSRF to Stomp Header
我尝试将 stom 标头添加到连接事件,但我在客户端收到错误:
>>> CONNECT
XSRF-TOKEN:f86232c1-e877-46e9-b4e6-7427c3d89940
accept-version:1.1,1.0
heart-beat:10000,10000
<<< ERROR
message:Failed to send message to ExecutorSubscribableChannel[clientInboundChannel]; nested exception is org.springframework.security.web.csrf.MissingCsrfTokenException\c Could not verify the provided CSRF token because your session was not found.
content-length:0
客户端代码:
<script type="text/javascript" src="/webjars/js-cookie/js.cookie.js"></script>
var headers = ;
var headerName = "XSRF-TOKEN";
var token = Cookies.get('XSRF-TOKEN')
headers[headerName] = token;
stompClient.connect(headers, function (frame) ....);
websocket 安全配置:
@Configuration
public class WebSocketAuthorizationSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer
@Override
protected void configureInbound(final MessageSecurityMetadataSourceRegistry messages)
// You can customize your authorization mapping here.
messages.anyMessage().authenticated();
messages.simpDestMatchers("/app/hello").authenticated()//.hasRole("ADMIN")
.simpSubscribeDestMatchers("/user/queue/**").hasRole("ADMIN")
.simpSubscribeDestMatchers("/topic/greetings").authenticated();
// TODO: For test purpose (and simplicity) i disabled CSRF, but you should re-enable this and provide a CRSF endpoint.
@Override
protected boolean sameOriginDisabled()
return false; //! I do it especially
弹簧安全配置:
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
private static final String SECURE_ADMIN_PASSWORD = "rockandroll";
@Override
protected void configure(HttpSecurity http) throws Exception
http
.csrf().disable()
.formLogin()
.loginPage("/index.html")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/sender.html")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/index.html")
.permitAll()
.and()
.authorizeRequests()
.antMatchers("/js/**", "/lib/**", "/images/**", "/css/**", "/index.html", "/","/*.css","/webjars/**", "/*.js").permitAll()
.antMatchers("/websocket").hasRole("ADMIN")
.requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ADMIN")
.anyRequest().authenticated();
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception
auth.authenticationProvider(new AuthenticationProvider()
@Override
public boolean supports(Class<?> authentication)
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException
UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication;
List<GrantedAuthority> authorities = SECURE_ADMIN_PASSWORD.equals(token.getCredentials()) ?
AuthorityUtils.createAuthorityList("ROLE_ADMIN") : null;
return new UsernamePasswordAuthenticationToken(token.getName(), token.getCredentials(), authorities);
);
也许我的 csrf 令牌标头名称错误?
附言
【问题讨论】:
您是否将 CSRF Cookie 与您的请求一起发送?如果我不发送 cookie,我会收到该错误。它必须具有正确的域才能让您的浏览器发送它。 @Will M,我该如何检查? 这取决于您使用什么来发送请求。如果它来自浏览器,通过网站,那么您应该使用该浏览器的开发人员工具。如果你是通过邮递员或其他工具制作的,它应该有一种内置的方式来查看你的 cookie 是什么 我无法编辑这篇文章,因为它主要是代码,不会让我编辑,如果其他人可以,请用这个完整的链接替换 Adding CSRF to Stomp Header。 【参考方案1】:这个问题不在 Spring Framework 中。更新到 Spring-Boot(2.5.0,war+Tomcat 9 实现,OAuth2)后,我遇到了同样的问题。
它对我有用:
第 1 步(为 Websockets 添加安全配置 - 您需要禁用 SCRF Websocket Protection)
导入 org.springframework.context.annotation.Configuration; 导入 org.springframework.messaging.simp.SimpMessageType; 导入 org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry; 导入 org.springframework.security.config.annotation.web.socket.AbstractSecurityWebSocketMessageBrokerConfigurer;
@配置 公共类 SocketSecurityConfig 扩展 AbstractSecurityWebSocketMessageBrokerConfigurer
@Override
protected boolean sameOriginDisabled()
return true;
@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages)
messages
.simpTypeMatchers(SimpMessageType.CONNECT, SimpMessageType.HEARTBEAT, SimpMessageType.UNSUBSCRIBE, SimpMessageType.DISCONNECT).permitAll()
.anyMessage().permitAll()
.simpDestMatchers("/**").permitAll()
;
第 2 步(在 Web 安全配置中添加对 Websockets 和 Stomp 的访问):
导入 lombok.RequiredArgsConstructor; 导入 lombok.extern.slf4j.Slf4j; 导入 org.springframework.beans.factory.annotation.Autowired; 导入 org.springframework.context.annotation.ComponentScan; 导入 org.springframework.context.annotation.Configuration; 导入 org.springframework.security.config.annotation.web.builders.HttpSecurity; 导入 org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 导入 org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 导入 org.springframework.security.config.http.SessionCreationPolicy;
@Slf4j @EnableWebSecurity @ComponentScan("com.example.your.project.package.name") @配置 @RequiredArgsConstructor(onConstructor = @__(@Autowired)) 公共类 OAuth2LoginSecurityConfig 扩展 WebSecurityConfigurerAdapter
private static final String[] OPEN_URIS =
"/**/*.woff",
"/**/*.woff2",
"/**/*.ttf",
"/webjars/**",
"/login",
"/login/*",
"/login/*/**",
"/resources/**",
"/error",
"/error/*",
"/error/*/**",
"/oauth2/authorization/**",
"/**/*.png",
"/**/*.css",
"/**/*.js",
"/style.css",
"/favicon.ico",
"/wicket",
"/wicket/resource/",
"/wicket/resource/*",
"/wicket/resource/*/**",
"/wicket/resources/**",
"/wicket/resources/*/**",
"/wicket/*",
"/wicket/page/*",
"/wicket/page/*/**",
"/webjars",
"/webjars/*",
"/webjars/*/**",
"/webservices/websocket/",
"/webservices/websocket/*",
"/webservices/websocket/*/**",
"/webservices/websocketHandlerEndpoint",
"/webservices/websocketHandlerEndpoint/*",
"/webservices/websocketHandlerEndpoint/*/**"
;
/////---Here some Configuration (not showed)------------ /////
@Override
protected void configure(HttpSecurity http) throws Exception
http.csrf().disable()
.headers()
.frameOptions().sameOrigin()
.httpStrictTransportSecurity().disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
.and()
.authorizeRequests(authorize -> authorize.antMatchers(OPEN_URIS).permitAll())
// (Optional : )
.oauth2Login(oauth2 ->
oauth2.permitAll() // <-- actually not real, but here must be code
//....`enter code here`..
//
)
//.....
.logout()
// ...
;
//another part of Configuration .....
注意: 1)"/webservices/websocket/..." - 是 Stomp 端点 2) "/webservices/websocketHandlerEndpoint..." - 是 Websocket 处理程序端点
【讨论】:
以上是关于MissingCsrfTokenException:无法验证提供的 CSRF 令牌,因为找不到您的会话的主要内容,如果未能解决你的问题,请参考以下文章