WebSockets身份验证

32

当使用WebSocket连接时,有哪些可能的方式可以进行用户身份验证?

示例场景:通过加密的WebSocket连接的基于Web的多用户聊天应用程序。如何确保每个连接都属于某个经过身份验证的用户,并且在连接期间无法被伪造的用户所利用。

3个回答

44

如果您已经为应用程序的非 WebSocket 部分执行身份验证,请在连接后将会话 cookie 作为第一条消息传递,并像通常一样检查 cookie。

警告:当使用 FlashSocket 时,以下内容不起作用:
如果您正在使用 socket.io,则更加容易,因为 cookies 会在连接时自动传递,并可以按以下方式访问:

var io = require('socket.io');
var socket = io.listen(app); 
socket.on('connection', function(client){ 
    cookies = client.headers['cookie'];
});

4
你确定这总是有效吗?例如,如果Socket.IO退回到Flash sockets,浏览器cookie将不会发送(据我所知)。 - Thomas
1
@Thomas 你说得对,有一个问题已经提交,提到应该通过第一条消息进行身份验证。 - Derek Dahmer
1
这是一种实用的方法,但它要求执行登录(和 cookie 设置)的 Web 页面来自与 WebSocket 相同的源,否则从登录页面设置的 cookie 将不会在 WebSocket 连接上发送。 - oberstet
2
依赖于 cookies 是一个不好的想法,因为跨域 WebSockets 是允许的,并且将传递与目标 URL 相关联的 cookies。这会让您完全暴露于 CORS 攻击之下,除非您也检查 Origin 标头。 - Aaron Dufour
如果使用CORS,Cookie将无法工作。SocketCluster曾经使用Cookie来存储JWT令牌,但现在已经不再使用了。请参见https://github.com/SocketCluster/socketcluster-client/issues/9 - Jon

3
SSL/TLS可以使用X.509证书来验证客户端和服务器。这取决于您使用的Web应用程序平台。在Apache中,可以检查SSL_CLIENT_CERT 环境变量是否有效,并针对已知证书列表进行验证。这不需要使用完整的PKI,也不需要为每个客户端购买证书。尽管我建议使用CA来支持您的服务器的SSL证书。

您的意思是SSL证书将分别用于HTTP和WebSocket连接吗? - yojimbo87
2
我不同意Rook所说的。SSL/TLS可以确保数据在传输层中没有被更改,但问题在于我们如何知道Web Socket请求来自用户A而不是用户B?假设用户A和B都已登录,由于Web Socket在连接建立后不会发送cookie,那么在后续过程中,这个Web Socket如何确保请求来自真正的用户A而不是用户B呢? - Ricky Jiao

1

有两种方法。

一种方法是允许任何人打开websocket连接。在连接打开后,客户端发送授权令牌作为第一条消息。如果客户端在一定时间内未发送有效令牌,则关闭连接。

另一种方法是使用cookie(它们由浏览器在每个请求中自动发送)。这需要您实现CSRF保护(比通常更多,因为没有同源策略(SOP)用于websocket)。您可以在这里找到详细信息。概述如下:

  1. 使用站点的正常身份验证,从js向后端发出“websocket预授权”请求
  2. 后端在响应正文中返回CSRF令牌,并在响应头中设置一个带有SameSite=Strict的“websocket auth” cookie
  3. 尝试在查询参数中添加CSRF令牌的情况下与后端建立websocket连接
  4. 后端检查以下内容
    • websocket auth cookie和CSRF令牌是否有效
    • Origin标头的值是否与已批准的域匹配
  5. 后端发送响应并升级连接以使用websockets

第一种方法更简单,但缺点是需要您拥有一些服务器端状态等待客户端进行身份验证。这可能会允许攻击者通过消耗所有可用套接字来执行拒绝服务攻击。


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