Websocket安全性

40

我希望使用WebSockets与我们的服务器通信来实现网络(angular)和iPhone应用程序。过去我们使用HTTP请求时,通过使用请求数据、URL、时间戳等哈希值来进行身份验证和保护请求。

据我所知,我们无法在WebSockets请求中发送头文件,因此我想知道如何保护每个请求。

是否有人有任何想法或好的做法?


2
好问题。我还没有使用Websockets的经验,但这是我想尽早做的事情。我找到了这个链接:https://auth0.com/blog/2014/01/15/auth-with-socket-io/ - Rob
@Rob 谢谢,那是一个开始。但我想要一种可以防止中间人攻击的方法。我实在找不到这样的方法,在过去,我将整个请求和请求数据哈希处理,因此即使有人更改了请求,服务器也会知道。我想我可以将数据序列化为字符串,并将哈希作为 URL 的一部分传递,但不确定这是否安全/好的做法。 - John Doe
@Rob 不是的,a 是通过公钥/私钥(用于 Angular 的 OAuth 令牌)生成的,在请求特定数据(如 IP 地址、随机数、请求数据、时间戳等)之上。 - John Doe
3
一旦建立了TLS连接(wss://),只要客户端验证了服务器的证书,而服务器也能够安全地验证客户端,那么该特定连接就会受到MitM攻击的保护。头部信息可供WS服务器用于帮助客户端身份验证... 当然,必须完全遵守https://www.owasp.org/index.php/Authentication_Cheat_Sheet中的所有规则;永远不要接受非TLS连接作为已验证的连接,而且身份验证cookie必须是TLS和HTTP Only的:不可供客户端JavaScript使用。 - Ghedipunk
1
另外,如果您在cookie中使用会话令牌,请参阅https://www.owasp.org/index.php/Session_Management_Cheat_Sheet以确保通过混合WebSocket和HTTP流量进行安全身份验证的必要性... (此外,上述未添加的是:标头,因此cookie仅在握手期间对WS服务器可用,因此,如果出于任何原因更改会话令牌(每次用户的身份验证状态发生更改都应该更改),则WS连接必须断开并重新启动)。 - Ghedipunk
显示剩余8条评论
4个回答

37
为了保护您的消息安全,使用SSL/TLS上的WebSockets(wss://而不是ws://)。不要自己编写加密解密算法。
关于身份验证。HTTP和WebSockets之间的一个重大区别是HTTP是无状态协议,而WebSockets不是。
使用HTTP时,您必须在每个请求中发送头文件(cookie、令牌等)。使用WebSockets,您建立一个连接。在最初的交互中,您可以对客户进行身份验证,并且在连接的其余部分中,您知道客户端已通过身份验证。
Heroku的人员描述了一种模式,其中客户端使用HTTP进行身份验证,获得一张票据,然后将该票据作为第一条消息发送到WebSocket连接上。请参见https://devcenter.heroku.com/articles/websocket-security

你能澄清一下吗?这方面的文档真的很零散。你是说我只需要使用 wss://,协议就会自动切换到 TLS 吗?需要什么服务器配置?我在某些服务器上尝试过,但收到了一个糟糕的 400 Bad Request 响应。 - Sonny
当然,您需要设置服务器以确保安全。所需的服务器配置取决于您使用的服务器。请提出单独的问题。虽然我可能无法帮助您。 - Pieter Herroelen

4
我同意使用SSL/TLS的wss://连接。始终使用加密流量。有几种实现身份验证的方法。请参见此处:http://simplyautomationized.blogspot.com/2015/09/5-ways-to-secure-websocket-rpi.html
大多数示例都使用Python或Node.js,并针对树莓派进行了指导,但是一般概念是值得考虑的好主意。在帖子中有链接到一个SocketRocket辅助库,它允许您将身份验证插入到auth标头中(SocketShuttle)。

3
与服务器进行安全通信包括相互认证双方。如果您需要通过一个通信渠道传输具有不同身份验证凭据的不同用户(这在现今是一种罕见的想法),则需要分别进行身份验证。否则,您只需要设计密钥分发方案(以便您的应用程序知道服务器和客户端的公钥,您的服务器具有熟悉客户端公钥的协议,有许多模式可供选择)。
为此,选择范围比SSL或自己的加密要宽得多(尽量避免自己编写加密算法)。
对于Web服务器到浏览器部分,SSL是您唯一的选择,但是它不应被视为良好的安全措施,每年都会出现更多漏洞、密码降级和信任问题。它承载着20年来糟糕的工程决策和紧急修复的负担,因此如果您能获得更好的东西-那就值得这样做。尽管如此,对于普通网站而言,它仍然比没有好得多。
在您的移动应用程序中,您可以轻松使用许多提供与服务器进行安全会话消息传递的加密库,具有显着更高的安全性保证,无需依赖。
  • https://github.com/mochtu/libsodium-ios, libsodium-ios,一个iOS包装器,用于NaCl,它是现代密码库中最好的之一,具有许多新颖的ECC密码实现,在学术界受到高度赞扬,由一个狂热追求在所有情况下获得最佳性能的疯子编写(简而言之:我很喜欢它 :))。

  • Themis是我参与的一个项目,我们有非常ObjC友好的iOS版本库,并且提供了一个方便的教程,介绍如何在iOS上进行安全的WebSocket通信:https://www.cossacklabs.com/building-secure-chat


2
你应该使用SSL/TLS保护你的连接,并使用https代替http,wss代替ws。为了进行身份验证/授权,你可以向websocket连接添加查询参数,并添加类似用户名/密码的内容。 例如:
wss://example.com/path?username=password=anotherParam=99ace112-dd56-427e-ba3d-9dd23e9c7551

是的,在JS中,您无法添加任意标头,但是您可以在Websocket连接中添加协议和Sec-WebSocket-Protocol标头,并在服务器端根据Websocket协议对用户进行身份验证/授权。


但是,即便在 WSS 中,URL 也是以明文形式发送的,对吧?这意味着密码和用户名可能会被嗅探到... - foxtrotuniform6969
是的,但是您可以通过发送大量查询参数、非常复杂的解码参数以及通过传递自己发明的模板并在后端验证它们来使其变得更加复杂。 - MHK
在 JavaScript 中,你不能为 WebSocket 设置头部。但是你可以设置这个: Sec-WebSocket-Protocol ;) 并检查客户端是否发送了有效的字符串,如果是,则打开 socket。 - MHK
这不是最佳实践,因为任何人都可以连接并打开大量HTTP连接,浪费您的资源并使您的服务器非常繁忙。Sec-WebSocket-Protocol将作为预连接身份验证方法工作,并且不包含在查询参数中。 - MHK
1
使用wss时,url不会以明文形式发送。 - Ted Bigham
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接