Disable SpEL selector support in WebSocket messaging by default
This commit disables support for evaluating SpEL expressions from untrusted sources by default. Specifically, this applies to the SpEL-based 'selector' header support in WebSocket messaging, which includes the DefaultSubscriptionRegistry and the classes used to configure the 'selector' header name (SimpleBrokerMessageHandler and SimpleBrokerRegistration). The selector header support remains in place but will have to be explicitly enabled beginning with Spring Framework 6.1. For example, a custom implementation of WebSocketMessageBrokerConfigurer can override the configureMessageBroker() method and configure the selector header name as follows. registry.enableSimpleBroker().setSelectorHeaderName("selector"); Closes gh-30550
This commit is contained in:
parent
75466fee8d
commit
5bc80fc094
|
@ -54,9 +54,11 @@ import org.springframework.util.StringUtils;
|
|||
* in memory and uses a {@link org.springframework.util.PathMatcher PathMatcher}
|
||||
* for matching destinations.
|
||||
*
|
||||
* <p>As of 4.2, this class supports a {@link #setSelectorHeaderName selector}
|
||||
* header on subscription messages with Spring EL expressions evaluated against
|
||||
* the headers to filter out messages in addition to destination matching.
|
||||
* <p>This class also supports an optional <em>selector</em> header on subscription
|
||||
* messages with Spring Expression Language (SpEL) expressions evaluated against
|
||||
* the headers to filter out messages in addition to destination matching. As of
|
||||
* Spring Framework 6.1, the SpEL support is disabled by default, but it can be
|
||||
* enabled by setting a {@linkplain #setSelectorHeaderName selector header name}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sebastien Deleuze
|
||||
|
@ -79,7 +81,7 @@ public class DefaultSubscriptionRegistry extends AbstractSubscriptionRegistry {
|
|||
private int cacheLimit = DEFAULT_CACHE_LIMIT;
|
||||
|
||||
@Nullable
|
||||
private String selectorHeaderName = "selector";
|
||||
private String selectorHeaderName;
|
||||
|
||||
private volatile boolean selectorHeaderInUse;
|
||||
|
||||
|
@ -130,9 +132,11 @@ public class DefaultSubscriptionRegistry extends AbstractSubscriptionRegistry {
|
|||
* <pre style="code">
|
||||
* headers.foo == 'bar'
|
||||
* </pre>
|
||||
* <p>By default this is set to "selector". You can set it to a different
|
||||
* name, or to {@code null} to turn off support for a selector header.
|
||||
* @param selectorHeaderName the name to use for a selector header
|
||||
* <p>By default the selector header name is set to {@code null} which disables
|
||||
* this feature. You can set it to {@code "selector"} or a different name to
|
||||
* enable support for a selector header.
|
||||
* @param selectorHeaderName the name to use for a selector header, or {@code null}
|
||||
* or blank to disable selector header support
|
||||
* @since 4.2
|
||||
*/
|
||||
public void setSelectorHeaderName(@Nullable String selectorHeaderName) {
|
||||
|
|
|
@ -61,7 +61,7 @@ public class SimpleBrokerMessageHandler extends AbstractBrokerMessageHandler {
|
|||
private Integer cacheLimit;
|
||||
|
||||
@Nullable
|
||||
private String selectorHeaderName = "selector";
|
||||
private String selectorHeaderName;
|
||||
|
||||
@Nullable
|
||||
private TaskScheduler taskScheduler;
|
||||
|
@ -172,11 +172,13 @@ public class SimpleBrokerMessageHandler extends AbstractBrokerMessageHandler {
|
|||
* <pre style="code">
|
||||
* headers.foo == 'bar'
|
||||
* </pre>
|
||||
* <p>By default this is set to "selector". You can set it to a different
|
||||
* name, or to {@code null} to turn off support for a selector header.
|
||||
* <p>By default the selector header name is set to {@code null} which disables
|
||||
* this feature. You can set it to {@code "selector"} or a different name to
|
||||
* enable support for a selector header.
|
||||
* <p>Setting this property has no effect if the underlying SubscriptionRegistry
|
||||
* is not an instance of {@link DefaultSubscriptionRegistry}.
|
||||
* @param selectorHeaderName the name to use for a selector header
|
||||
* @param selectorHeaderName the name to use for a selector header, or {@code null}
|
||||
* or blank to disable selector header support
|
||||
* @since 4.3.17
|
||||
* @see #setSubscriptionRegistry
|
||||
* @see DefaultSubscriptionRegistry#setSelectorHeaderName(String)
|
||||
|
|
|
@ -38,7 +38,7 @@ public class SimpleBrokerRegistration extends AbstractBrokerRegistration {
|
|||
private long[] heartbeat;
|
||||
|
||||
@Nullable
|
||||
private String selectorHeaderName = "selector";
|
||||
private String selectorHeaderName;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -90,9 +90,11 @@ public class SimpleBrokerRegistration extends AbstractBrokerRegistration {
|
|||
* <pre style="code">
|
||||
* headers.foo == 'bar'
|
||||
* </pre>
|
||||
* <p>By default this is set to "selector". You can set it to a different
|
||||
* name, or to {@code null} to turn off support for a selector header.
|
||||
* @param selectorHeaderName the name to use for a selector header
|
||||
* <p>By default the selector header name is set to {@code null} which disables
|
||||
* this feature. You can set it to {@code "selector"} or a different name to
|
||||
* enable support for a selector header.
|
||||
* @param selectorHeaderName the name to use for a selector header, or {@code null}
|
||||
* or blank to disable selector header support
|
||||
* @since 4.3.17
|
||||
*/
|
||||
public void setSelectorHeaderName(@Nullable String selectorHeaderName) {
|
||||
|
|
|
@ -253,7 +253,7 @@ class DefaultSubscriptionRegistryTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void registerSubscriptionWithSelectorHeaderEnabledByDefault() {
|
||||
void registerSubscriptionWithSelectorHeaderEnabled() {
|
||||
String sessionId1 = "sess01";
|
||||
String sessionId2 = "sess02";
|
||||
String sessionId3 = "sess03";
|
||||
|
@ -264,6 +264,9 @@ class DefaultSubscriptionRegistryTests {
|
|||
String selector1 = "headers.foo == 'bar'";
|
||||
String selector2 = "headers.foo == 'enigma'";
|
||||
|
||||
// Explicitly enable selector support
|
||||
this.registry.setSelectorHeaderName("selector");
|
||||
|
||||
// Register subscription with matching selector header
|
||||
this.registry.registerSubscription(subscribeMessage(sessionId1, subscriptionId1, destination, selector1));
|
||||
// Register subscription with non-matching selector header
|
||||
|
@ -297,7 +300,7 @@ class DefaultSubscriptionRegistryTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void registerSubscriptionWithSelectorHeaderDisabled() {
|
||||
void registerSubscriptionWithSelectorHeaderDisabledByDefault() {
|
||||
String sessionId1 = "sess01";
|
||||
String sessionId2 = "sess02";
|
||||
String sessionId3 = "sess03";
|
||||
|
@ -308,9 +311,6 @@ class DefaultSubscriptionRegistryTests {
|
|||
String selector1 = "headers.foo == 'bar'";
|
||||
String selector2 = "headers.foo == 'enigma'";
|
||||
|
||||
// Explicitly disable selector header support
|
||||
this.registry.setSelectorHeaderName(null);
|
||||
|
||||
// Register subscription with matching selector header
|
||||
this.registry.registerSubscription(subscribeMessage(sessionId1, subscriptionId1, destination, selector1));
|
||||
// Register subscription with non-matching selector header
|
||||
|
|
|
@ -165,8 +165,8 @@ class WebSocketMessageBrokerConfigurationSupportTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void selectorHeaderEnabledByDefault() {
|
||||
ApplicationContext context = createContext(TestChannelConfig.class, TestConfigurer.class);
|
||||
void selectorHeaderEnabled() {
|
||||
ApplicationContext context = createContext(TestChannelConfig.class, SelectorHeaderConfigurer.class);
|
||||
SimpleBrokerMessageHandler simpleBrokerMessageHandler = simpleBrokerMessageHandler(context);
|
||||
|
||||
assertThat(simpleBrokerMessageHandler.getSubscriptionRegistry())
|
||||
|
@ -176,8 +176,8 @@ class WebSocketMessageBrokerConfigurationSupportTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void selectorHeaderDisabled() {
|
||||
ApplicationContext context = createContext(TestChannelConfig.class, SelectorHeaderConfigurer.class);
|
||||
void selectorHeaderDisabledByDefault() {
|
||||
ApplicationContext context = createContext(TestChannelConfig.class, TestConfigurer.class);
|
||||
SimpleBrokerMessageHandler simpleBrokerMessageHandler = simpleBrokerMessageHandler(context);
|
||||
|
||||
assertThat(simpleBrokerMessageHandler.getSubscriptionRegistry())
|
||||
|
@ -282,8 +282,8 @@ class WebSocketMessageBrokerConfigurationSupportTests {
|
|||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerRegistry registry) {
|
||||
// Explicitly disable selector header support
|
||||
registry.enableSimpleBroker().setSelectorHeaderName(null);
|
||||
// Explicitly enable selector header support
|
||||
registry.enableSimpleBroker().setSelectorHeaderName("selector");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -320,7 +320,7 @@ class StompWebSocketIntegrationTests extends AbstractWebSocketIntegrationTests {
|
|||
@Override
|
||||
public void configureMessageBroker(MessageBrokerRegistry configurer) {
|
||||
configurer.setApplicationDestinationPrefixes("/app");
|
||||
configurer.enableSimpleBroker("/topic", "/queue");
|
||||
configurer.enableSimpleBroker("/topic", "/queue").setSelectorHeaderName("selector");
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
|
Loading…
Reference in New Issue