And*_*rew 5 stomp spring-security websocket sockjs spring-boot
早上好,
我创建了一个简单的Spring Boot WebSocket应用程序。现在,我想为其设置一些安全性。我正在尝试一些示例,但无法使其正常工作。我收到错误消息:
网页浏览器:
>>> CONNECT
${_csrf.headerName}:${_csrf.token}
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
Run Code Online (Sandbox Code Playgroud)
登录STS:
Failed to send client message to application via MessageChannel in session cc25e1mw. Sending STOMP ERROR to client.
Run Code Online (Sandbox Code Playgroud)
堆栈跟踪:
org.springframework.messaging.MessageDeliveryException: Failed to send message to ExecutorSubscribableChannel[clientInboundChannel]; nested exception is org.springframework.security.web.csrf.MissingCsrfTokenException: Could not verify the provided CSRF token because your session was not found.
at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:127) ~[spring-messaging-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:104) ~[spring-messaging-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.web.socket.messaging.StompSubProtocolHandler.handleMessageFromClient(StompSubProtocolHandler.java:299) ~[spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.web.socket.messaging.SubProtocolWebSocketHandler.handleMessage(SubProtocolWebSocketHandler.java:306) [spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.web.socket.handler.WebSocketHandlerDecorator.handleMessage(WebSocketHandlerDecorator.java:75) [spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.web.socket.handler.LoggingWebSocketHandlerDecorator.handleMessage(LoggingWebSocketHandlerDecorator.java:56) [spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.web.socket.handler.ExceptionWebSocketHandlerDecorator.handleMessage(ExceptionWebSocketHandlerDecorator.java:58) [spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession.delegateMessages(AbstractSockJsSession.java:380) [spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.web.socket.sockjs.transport.session.WebSocketServerSockJsSession.handleMessage(WebSocketServerSockJsSession.java:194) [spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.web.socket.sockjs.transport.handler.SockJsWebSocketHandler.handleTextMessage(SockJsWebSocketHandler.java:92) [spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.web.socket.handler.AbstractWebSocketHandler.handleMessage(AbstractWebSocketHandler.java:43) [spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.handleTextMessage(StandardWebSocketHandlerAdapter.java:110) [spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.access$000(StandardWebSocketHandlerAdapter.java:42) [spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter$3.onMessage(StandardWebSocketHandlerAdapter.java:81) [spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter$3.onMessage(StandardWebSocketHandlerAdapter.java:78) [spring-websocket-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.apache.tomcat.websocket.WsFrameBase.sendMessageText(WsFrameBase.java:395) [tomcat-embed-websocket-8.5.23.jar:8.5.23]
at org.apache.tomcat.websocket.server.WsFrameServer.sendMessageText(WsFrameServer.java:119) [tomcat-embed-websocket-8.5.23.jar:8.5.23]
at org.apache.tomcat.websocket.WsFrameBase.processDataText(WsFrameBase.java:495) [tomcat-embed-websocket-8.5.23.jar:8.5.23]
at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:294) [tomcat-embed-websocket-8.5.23.jar:8.5.23]
at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:133) [tomcat-embed-websocket-8.5.23.jar:8.5.23]
at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:82) [tomcat-embed-websocket-8.5.23.jar:8.5.23]
at org.apache.tomcat.websocket.server.WsFrameServer.doOnDataAvailable(WsFrameServer.java:171) [tomcat-embed-websocket-8.5.23.jar:8.5.23]
at org.apache.tomcat.websocket.server.WsFrameServer.notifyDataAvailable(WsFrameServer.java:151) [tomcat-embed-websocket-8.5.23.jar:8.5.23]
at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.upgradeDispatch(WsHttpUpgradeHandler.java:148) [tomcat-embed-websocket-8.5.23.jar:8.5.23]
at org.apache.coyote.http11.upgrade.UpgradeProcessorInternal.dispatch(UpgradeProcessorInternal.java:54) [tomcat-embed-core-8.5.23.jar:8.5.23]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:53) [tomcat-embed-core-8.5.23.jar:8.5.23]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-8.5.23.jar:8.5.23]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459) [tomcat-embed-core-8.5.23.jar:8.5.23]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.23.jar:8.5.23]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_144]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_144]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.23.jar:8.5.23]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_144]
Caused by: org.springframework.security.web.csrf.MissingCsrfTokenException: Could not verify the provided CSRF token because your session was not found.
at org.springframework.security.messaging.web.csrf.CsrfChannelInterceptor.preSend(CsrfChannelInterceptor.java:55) ~[spring-security-messaging-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.messaging.support.AbstractMessageChannel$ChannelInterceptorChain.applyPreSend(AbstractMessageChannel.java:158) ~[spring-messaging-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:113) ~[spring-messaging-4.3.13.RELEASE.jar:4.3.13.RELEASE]
... 32 common frames omitted
Run Code Online (Sandbox Code Playgroud)
我的配置文件:
WebSocket配置
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer{
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/websocket").setHandshakeHandler(new MyHandshakeHandler()).setAllowedOrigins("*").withSockJS();
}
public class MyHandshakeHandler extends DefaultHandshakeHandler {
@Override
protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler,
Map<String, Object> attributes) {
// TODO Auto-generated method stub
return super.determineUser(request, wsHandler, attributes);
}
}
}
Run Code Online (Sandbox Code Playgroud)
控制器功能
@MessageMapping("/hello")
@SendTo("/topic/messaging")
public Message sendMessage(Message message) throws Exception {
Thread.sleep(10); // simulated delay
messageRepository.save(message);
return new Message(message.getFromUserId(), message.getToUserId(), message.getMessageText(), "delivered", message.getDate());
}
Run Code Online (Sandbox Code Playgroud)
JS函数连接:
function connect() {
var headerName = "${_csrf.headerName}";
var token = "${_csrf.token}";
var headers = {};
headers[headerName] = token;
var socket = new SockJS('/websocket');
stompClient = Stomp.over(socket);
stompClient.connect(headers, function (frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/messaging', function (message) {
showMessage(JSON.parse(message.body).messageText);
});
});
}
Run Code Online (Sandbox Code Playgroud)
所以我的问题是:Web浏览器正在连接到应用程序并发送消息(我不知道它是否安全),但是它无法从应用程序接收任何消息。
我的问题:如何实现安全的websocket连接,以及如何摆脱该错误。
我是保护Web应用程序的新手,请原谅。
谢谢您的任何建议。
安德鲁
从文档中:
通常,我们需要在HTTP标头或HTTP参数中包含CSRF令牌。但是,SockJS不允许使用这些选项。相反,我们必须在Stomp标头中包含令牌
好的,现在我们知道我们必须将这些标头作为Stomp标头包括在内。如果在应用程序中使用JSP,则可以从客户端的请求属性获取CSRF标头和令牌。
var headerName = "${_csrf.headerName}";
var token = "${_csrf.token}";
如果您没有使用JSP,而是使用普通的HTML,则必须CsrfToken在REST端点上公开令牌,例如/csrf:
@RestController
public class CsrfController {
@RequestMapping("/csrf")
public CsrfToken csrf(CsrfToken token) {
return token;
}
}
Run Code Online (Sandbox Code Playgroud)
还有其他警告。例如,假设您要允许其他域访问您的Web套接字终结点,WebSocketSecurityConfig您可以提供以下内容:
@Override
protected boolean sameOriginDisabled() {
return true;
}
Run Code Online (Sandbox Code Playgroud)
我从文档中学到的最后一件事是:
SockJS在CONNECT消息上使用POST进行任何基于HTTP的传输。通常,我们需要在HTTP标头或HTTP参数中包含CSRF令牌。但是,SockJS不允许使用这些选项。相反,我们必须按照第24.4.3节“将CSRF添加到Stomp标头”中所述在Stomp标头中包含令牌。
这也意味着我们需要通过Web层放宽对CSRF的保护。具体来说,我们要为连接URL禁用CSRF保护。我们不想禁用每个URL的CSRF保护。否则,我们的站点将容易受到CSRF攻击。
第二段是这里的关键,简单来说,您必须将以下内容添加到扩展的类中 WebSecurityConfigurerAdapter
http
.csrf()
// ignore our stomp endpoints since they are protected using Stomp headers
.ignoringAntMatchers("/chat/**")
.and()
.headers()
// allow same origin to frame our site to support iframe SockJS
.frameOptions().sameOrigin()
.and()
.authorizeRequests()
Run Code Online (Sandbox Code Playgroud)
https://docs.spring.io/spring-security/site/docs/current/reference/html/websocket.html
| 归档时间: |
|
| 查看次数: |
6970 次 |
| 最近记录: |