保护基于 Spring 消息传递的 websocket 服务
Securing a Spring messaging based websocket service
我已经为此工作了 3 周,但没有真正的解决方案,我真的希望你能帮助我。
一点项目背景:
具有基于 JavaScript/PHP 客户端的 Webapp 通过 SocksJS 和 Stomp 向 "gate"
发送消息
gate写在Java/Spring,使用@SendTo和@MessageMapping收发消息
来自gate的消息被发送到RabbitMQ并通过"messageBrokerRegistry.enableStompBrokerRelay"
返回给客户端
到目前为止一切正常,发送的消息正在返回。
现在是高级安全部分:
- 消息应该通过包含用户和内容的 cookie 来保护...
据我所知,WebSockets 本身不支持安全性。您必须像 "common" 具有 BASIC 身份验证或类似功能的网络应用程序一样保护您的网络应用程序。所以我添加了一个带有 class 扩展 GenericFilterBean 的 servlet 过滤器。如果用户发送了页面加载的正确 cookie,否则他会收到 403 错误。
问题来了:
由于@SendTo 向所有订阅者发送消息而@SendToUser 似乎只向一个会话发送消息,因此我倾向于使用@SendToUser。但是似乎没有办法选择要创建的 rabbitMQ 队列。我想要一些类似“/myqueue-user-123”的东西。这对于 @SendToUser 是不可能的,因为生成的队列是随机的并且基于我无法覆盖的 SessionID。
所以我尝试了(除了拦截器、事件等之外,我尝试了 LOADS 的东西),使用没有值的@SendTo,以便客户端可以决定它必须发送到的队列。
我现在需要的是评估cookie中的用户与“/myqueue/user-123”相关。如果不是,请不要向他发送消息。阻止他订阅。断开他,无论如何。
但在我看来,你无论如何也做不到
- 停止发送消息,只是 "intercept" 记录它们而不改变
- 断开 websocket 因为它会自动尝试重新连接
- 抛出异常,因为无论如何订阅都会成功(事件只是事件,而不是干扰)。
如果有任何建议或提示,我将不胜感激。因为我完全被困在这里...
我理解你的痛苦,我花了两天时间试图了解有关 WebSocket 的 spring 安全问题。
Websocket 不 officially
支持身份验证方式,但是 spring-security 支持(或多或少)。
我建议您在 WebSocket 级别而不是 HTTP 进行身份验证,大多数用于 WebSocket(和 stomp)的 JavaScript 库不会随 HTTP 握手一起发送 headers。
您将找到有关如何在 WebSocket 级别进行身份验证的详细指南 here。在上面的例子中,我使用 Websocket Headers 值来验证我的客户,你可以把你的 cookie 值放在这些 headers 中,或者用 localstorage 替换 cookie。
使用此方法,您将可以访问控制器中的 Principal
,这应该可以解决 SendToUser 问题。
我已经为此工作了 3 周,但没有真正的解决方案,我真的希望你能帮助我。
一点项目背景:
具有基于 JavaScript/PHP 客户端的 Webapp 通过 SocksJS 和 Stomp 向 "gate"
发送消息
gate写在Java/Spring,使用@SendTo和@MessageMapping收发消息
来自gate的消息被发送到RabbitMQ并通过"messageBrokerRegistry.enableStompBrokerRelay"
返回给客户端
到目前为止一切正常,发送的消息正在返回。
现在是高级安全部分:
- 消息应该通过包含用户和内容的 cookie 来保护...
据我所知,WebSockets 本身不支持安全性。您必须像 "common" 具有 BASIC 身份验证或类似功能的网络应用程序一样保护您的网络应用程序。所以我添加了一个带有 class 扩展 GenericFilterBean 的 servlet 过滤器。如果用户发送了页面加载的正确 cookie,否则他会收到 403 错误。
问题来了:
由于@SendTo 向所有订阅者发送消息而@SendToUser 似乎只向一个会话发送消息,因此我倾向于使用@SendToUser。但是似乎没有办法选择要创建的 rabbitMQ 队列。我想要一些类似“/myqueue-user-123”的东西。这对于 @SendToUser 是不可能的,因为生成的队列是随机的并且基于我无法覆盖的 SessionID。
所以我尝试了(除了拦截器、事件等之外,我尝试了 LOADS 的东西),使用没有值的@SendTo,以便客户端可以决定它必须发送到的队列。
我现在需要的是评估cookie中的用户与“/myqueue/user-123”相关。如果不是,请不要向他发送消息。阻止他订阅。断开他,无论如何。
但在我看来,你无论如何也做不到 - 停止发送消息,只是 "intercept" 记录它们而不改变 - 断开 websocket 因为它会自动尝试重新连接 - 抛出异常,因为无论如何订阅都会成功(事件只是事件,而不是干扰)。
如果有任何建议或提示,我将不胜感激。因为我完全被困在这里...
我理解你的痛苦,我花了两天时间试图了解有关 WebSocket 的 spring 安全问题。
Websocket 不 officially
支持身份验证方式,但是 spring-security 支持(或多或少)。
我建议您在 WebSocket 级别而不是 HTTP 进行身份验证,大多数用于 WebSocket(和 stomp)的 JavaScript 库不会随 HTTP 握手一起发送 headers。
您将找到有关如何在 WebSocket 级别进行身份验证的详细指南 here。在上面的例子中,我使用 Websocket Headers 值来验证我的客户,你可以把你的 cookie 值放在这些 headers 中,或者用 localstorage 替换 cookie。
使用此方法,您将可以访问控制器中的 Principal
,这应该可以解决 SendToUser 问题。