Default to XorCsrfChannelInterceptor in XML configuration

Change WebSocketMessageBrokerSecurityBeanDefinitionParser to use
XorCsrfChannelInterceptor by default, so WebSocket XML configuration
matches the default Xor-based configuration already in
WebSocketMessageBrokerSecurityConfiguration.

Issue gh-17260

Signed-off-by: Matt Magoffin <matt@solarnetwork.net>
This commit is contained in:
Matt Magoffin 2025-06-21 07:20:46 +12:00
parent 20a2213e11
commit 8aa15bb2d5
No known key found for this signature in database
GPG Key ID: DC00E6714BC94956
2 changed files with 12 additions and 4 deletions

View File

@ -69,7 +69,7 @@ import org.springframework.security.messaging.context.SecurityContextChannelInte
import org.springframework.security.messaging.util.matcher.MessageMatcher; import org.springframework.security.messaging.util.matcher.MessageMatcher;
import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher; import org.springframework.security.messaging.util.matcher.SimpDestinationMessageMatcher;
import org.springframework.security.messaging.util.matcher.SimpMessageTypeMatcher; import org.springframework.security.messaging.util.matcher.SimpMessageTypeMatcher;
import org.springframework.security.messaging.web.csrf.CsrfChannelInterceptor; import org.springframework.security.messaging.web.csrf.XorCsrfChannelInterceptor;
import org.springframework.security.messaging.web.socket.server.CsrfTokenHandshakeInterceptor; import org.springframework.security.messaging.web.socket.server.CsrfTokenHandshakeInterceptor;
import org.springframework.util.AntPathMatcher; import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -364,7 +364,7 @@ public final class WebSocketMessageBrokerSecurityBeanDefinitionParser implements
ManagedList<Object> interceptors = new ManagedList(); ManagedList<Object> interceptors = new ManagedList();
interceptors.add(new RootBeanDefinition(SecurityContextChannelInterceptor.class)); interceptors.add(new RootBeanDefinition(SecurityContextChannelInterceptor.class));
if (!this.sameOriginDisabled) { if (!this.sameOriginDisabled) {
interceptors.add(new RootBeanDefinition(CsrfChannelInterceptor.class)); interceptors.add(new RootBeanDefinition(XorCsrfChannelInterceptor.class));
} }
interceptors.add(registry.getBeanDefinition(this.inboundSecurityInterceptorId)); interceptors.add(registry.getBeanDefinition(this.inboundSecurityInterceptorId));
BeanDefinition inboundChannel = registry.getBeanDefinition(CLIENT_INBOUND_CHANNEL_BEAN_ID); BeanDefinition inboundChannel = registry.getBeanDefinition(CLIENT_INBOUND_CHANNEL_BEAN_ID);

View File

@ -20,6 +20,7 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import java.util.Base64;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -97,6 +98,13 @@ public class WebSocketMessageBrokerConfigTests {
private static final String CONFIG_LOCATION_PREFIX = "classpath:org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests"; private static final String CONFIG_LOCATION_PREFIX = "classpath:org/springframework/security/config/websocket/WebSocketMessageBrokerConfigTests";
/*
* Token format: "token" length random pad bytes + "token" (each byte UTF8 ^= 1).
*/
private static final byte[] XOR_CSRF_TOKEN_BYTES = new byte[] { 1, 1, 1, 1, 1, 117, 110, 106, 100, 111 };
private static final String XOR_CSRF_TOKEN_VALUE = Base64.getEncoder().encodeToString(XOR_CSRF_TOKEN_BYTES);
public final SpringTestContext spring = new SpringTestContext(this); public final SpringTestContext spring = new SpringTestContext(this);
@Autowired(required = false) @Autowired(required = false)
@ -125,7 +133,7 @@ public class WebSocketMessageBrokerConfigTests {
public void sendWhenAnonymousMessageWithConnectMessageTypeThenPermitted() { public void sendWhenAnonymousMessageWithConnectMessageTypeThenPermitted() {
this.spring.configLocations(xml("NoIdConfig")).autowire(); this.spring.configLocations(xml("NoIdConfig")).autowire();
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT); SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT);
headers.setNativeHeader(this.token.getHeaderName(), this.token.getToken()); headers.setNativeHeader(this.token.getHeaderName(), XOR_CSRF_TOKEN_VALUE);
this.clientInboundChannel.send(message("/permitAll", headers)); this.clientInboundChannel.send(message("/permitAll", headers));
} }
@ -197,7 +205,7 @@ public class WebSocketMessageBrokerConfigTests {
public void sendWhenAnonymousMessageWithConnectMessageTypeThenAuthorizationManagerPermits() { public void sendWhenAnonymousMessageWithConnectMessageTypeThenAuthorizationManagerPermits() {
this.spring.configLocations(xml("NoIdAuthorizationManager")).autowire(); this.spring.configLocations(xml("NoIdAuthorizationManager")).autowire();
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT); SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT);
headers.setNativeHeader(this.token.getHeaderName(), this.token.getToken()); headers.setNativeHeader(this.token.getHeaderName(), XOR_CSRF_TOKEN_VALUE);
this.clientInboundChannel.send(message("/permitAll", headers)); this.clientInboundChannel.send(message("/permitAll", headers));
} }