PHP + socket.io(会话,授权和安全问题)

pat*_*ryk 12 php security authentication node.js socket.io

我有一个工作的PHP应用程序,我想在其中添加实时支持.我想使用nodejs/socket.io来添加这种功能.

我发现的第一个问题是如何在nodejs端正确授权用户(用户已经通过PHP会话在php后端进行了身份验证).在nodejs端使用socket.handshake.header.cookie我可以解析并获取PHP会话ID,我可以通过redis/memcache/database进行身份验证(取决于我用来保存会话信息的内容).
当用户只打开一个站点的选项卡/窗口时,一切看起来都很酷 - 当拥有更多并使用session_regenerate_id()时,在nodejs中用户使用另一个sessionid键进行身份验证,因此除了他们连接的套接字ID之外,我无法区分两个选项卡用.当用户注销时,他不应该在任何选项卡上收到任何消息(因为他已经从该浏览器的每个选项卡/窗口中注销).所以在注销消息(在注销PHP之前从浏览器发送的东西)我应该删除连接到授权用户ID的所有套接字连接.但是,如果用户登录两个设备(例如PC浏览器和ipad safaris),该怎么办?在一台设备上注销后,他不应该在他注销的设备上收到任何消息,而不是在每台设备上.如何区分socket.io中不同设备/浏览器的连接?当然不使用session_regenerate_id()会很有效,但如果我真的想使用这个功能,我该怎么办?

我遇到的另一个问题是安全问题(甚至问题).让我们假设应用程序中的授权用户可以看到页面example.com/user1(这是user1的新闻源),但是看不到example.com/user2(例如,他没有权限查看它).我希望socket.io在用户访问example.com/user1时向浏览器发送更新消息,当用户在example.com/user2站点上时当然不发送.在socket.io端,我可以读取引用地址(因此,当用户在user2站点上时,他没有得到任何socket.io连接).问题是:我应该将引用地址与node.js端的经过身份验证的用户的权限进行比较吗?或者,node.js端的referer值是否安全在node.js端添加另一个db检查会降低它的速度(因为几乎每个请求都应该在两端进行相同的数据库检查 - PHP和node.js).

或者也许socket.io + PHP应用程序的整个概念以我提出的方式工作是错误的?

更新

我想我找到了一种方法来省略第一个问题的问题 - 基本上我只是添加另一个cookie(除了PHPSESSID)fe.名为NODESESSID,我在用户被授权时生成(fe.使用uniqid()).现在,node.js端的授权正在比较PHPSESSID和NODESESSID(两者必须匹配).现在,当用户注销时,他将消息注销传递给socket.io,socket.io断开所有使用NODESESSID的套接字.这就像连接重新生成会话ID的好处而不是重新生成会话ID(但不容易受到会话固定的影响,不是吗?).

Jan*_*ser 1

对于你的第二个问题:

正如评论中提到的,Referer 并不安全。

我在我的应用程序中遇到了类似的问题,这就是它对我的作用。

首先,我有一个单页应用程序,其中所有流量都通过套接字,但这不是必需的。它也应该按照您管理它的方式与会话一起工作。

在nodejs onConnect 中,我询问后端用户是否经过身份验证,然后将用户ID 存储到套接字对象(socket.data)中,并填充哈希图以直接从用户ID 查找套接字。

其次,我使用 Redis 并从 Nodejs 订阅 Redis 列表(请参阅 redis pub/sub)。php 后端将消息推送到此列表中,并使用用户 ID 来寻址该消息。Nodejs 获取此消息(例如,新的新闻提要项),在提到的哈希图中查找用户 ID 并将其发送到客户端。因此,用户只能获得他被授权的内容。然后客户端决定如何处理该消息。如果用户在他的提要页面上,则可以添加该项目。如果用户正在查看其他人的提要,它可以简单地在页面的其他位置添加通知。它也可能会丢弃它。

在 php 后端站点上,每次发生需要在某些连接的客户端上实时显示的事件时,都会将此消息发送到 redis。如果 user1 在 user2 的 feed 上发帖,则新项目将存储在数据库中,同时作为消息发送到 redis 队列中。

该系统还有助于减少数据库负载,因为 Nodejs 只需查询数据库即可确保连接的用户已经通过身份验证。