【问题标题】:How to protect user's "channel" on socket.io and node js?如何保护用户在 socket.io 和 node js 上的“通道”?
【发布时间】:2014-09-30 07:56:14
【问题描述】:

我创建了一个社交网络,它发展得非常好。我想使用 socket.io 和 node 实现实时通知。

嗯。已经这样做了,而且它是这样工作的......

USER A 向 USER B 发送消息,然后通过 emit 通知节点服务器写入属于用户 B 的通道。

每个用户在浏览网站时都会连接到自己的频道:

<script type="text/javascript">
var socket = io.connect( 'https://notificationserver.com/' );
socket.on( 'notifications_USERID', function( data ) {
    var data_type=data.data_type;
    //sample
    if(data_type=="message"){
      $.notify("You got a new message", "success");
    }

});
</script>

很简单。用户的频道是 notifications_USERID。

这不是安全的偏离路线。如果有人将 html 页面保存到它的计算机并加载它,他们将瞄准获取特定的用户通知。

那么,什么是使其安全且只有真正登录的用户才能访问的最佳方法?

更新

我使用 curl 向节点服务器发送数据,如下所示:

 $curl = curl_init();                                        
 $data = json_encode(array("receiverid"=>$uid,"secret"=>"SOMESECRET"));                                                         
 curl_setopt($curl, CURLOPT_URL, "http://notificationserver:1334");
 curl_setopt($curl, CURLOPT_POST, 1);

 curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
 curl_setopt($curl, CURLOPT_TIMEOUT, 1);
 curl_setopt($curl,CURLOPT_CONNECTTIMEOUT,1);
 curl_exec($curl);

这是我的 APP.JS 文件

var http = require('http'),
    fs = require('fs');

var key="SOMESECRET";

var app = http.createServer(function (request, response) {

    if (request.method == 'POST') {
        var body = '';
        var jsonString = '';

        request.on('data', function (data) {

            body += data;
            jsonString += data;
            if (body.length > 1e6) { 
                request.connection.destroy();
            }
        });
        request.on('end', function () {


             var json_data=JSON.parse(jsonString);
             var receiverid=json_data.receiverid;
             var secret=json_data.secret;


             if(secret==key){
                NewMessageNotify(receiverid); 
             }else{
                request.connection.destroy(); 
             }


        });
    }else{
        response.writeHead(200, {'Content-Type': 'text/html'});
        response.write("<h1>Hello World</h1>");
        response.end();
    }

}).listen(1334);

var io = require('socket.io').listen(app);

function NewMessageNotify(receiverid){
    io.sockets.emit("notifications_"+receiverid,{ data_type: "message" }); 
}

【问题讨论】:

  • 你是如何从服务器发送消息的?我们能看到那个代码吗?我认为您将对连接用户进行身份验证,然后跟踪哪个 socket.id 连接到哪个经过身份验证的人。然后,当您想向该人发送消息时,您只需将其发送到经过身份验证的套接字。您为每个用户使用自定义消息名称的方案在技术上允许任何人收听所有消息。
  • 如果您想充分利用 StackOverflow,请在发布您的问题后 20-30 分钟内回来查看,看看人们是否需要一些帮助来理解您的问题。绝大多数可能会提供帮助的人会在前 30-60 分钟内看到您的问题。如果不完全清楚并且您没有回答所提出的问题,那么人们就会过去,您将错过他们的帮助。这个地方不像典型的论坛那样工作,您可以在 24 小时后发布并回来。如果您的问题不清楚,将在此之前关闭。
  • 你好。我正在使用 php 写入节点服务器。我还发送了某种密码,只有当“密码”匹配时,服务器才会通知用户。这样我就可以避免有人不需要的发布到它。
  • 如果不查看此处的服务器端代码,我认为我们无法为您提供帮助,因此我们可以了解您如何发送消息。如果您依靠消息名称来区分每个用户的消息,听起来您的安全模型不起作用。

标签: node.js websocket socket.io


【解决方案1】:

您的安全模型已损坏,并且正在将所有用户的所有消息发送给所有人(您实际上是在广播它们)。稍微调整客户端 javascript 或从任何计算机运行的恶意 javascript 以比socket.io 稍低的级别挂接,任何用户都可以收听所有消息。

在这段代码中:

function NewMessageNotify(receiverid){
    io.sockets.emit("notifications_"+receiverid,{ data_type: "message" }); 
}

io.sockets.emit() 部分将该消息发送到所有打开的套接字。这根本不是你想做的。您希望“Bob”的消息仅发送到 Bob 的套接字。然后,除了向您证明自己是 Bob 的人之外,没有其他人有机会查看它们。

因此,要将 Bob 的消息仅发送到 Bob 的套接字,您必须在 Bob 和他的套接字之间保持某种关联。通常,这将作为身份验证过程的一部分完成(您没有显示),因此当有人与您的服务器建立 socket.io 连接并成功通过 Bob 身份验证时,您将记录 Bob 和特定套接字之间的链接.我不太了解 socket.io,不知道它是否具有维护该链接的内置机制,但我知道有几种方法可以做到。

  1. 如果您不打算拥有数以亿计的用户,您可以使用聊天室功能。当 Bob 使用唯一的用户 ID 登录时,您可以用他的名字将他加入聊天室。然后稍后当您想向 Bob 发送消息时,您只需将他的名字广播到聊天室即可。他将是该聊天室的唯一听众,因为您的服务器永远不会将其他任何人放入其中。这有点歪曲了聊天室的设计目的,但由于您的 userId 必须是唯一的,因此您可以使用用户名作为聊天室名称,socket.io 会自动为您保留名称和套接字之间的链接。

  2. 您可以创建自己的用户数据结构和 socket.id。当给定用户连接到您的服务器并成功通过身份验证时,您只需将它们添加到您的数据结构中。当它们断开连接时,您将它们移除。

示例代码:

var users = {};

io.on('connection', function(socket){
    // new socket connection here
    // authenticate the user
    // after successful login and authentication, add them to our data structure
    var username = "...";
    users[username] = socket;


    socket.on('disconnect', function() {
        // remove them from our data structure
        delete users[username];
    });
});

然后,向特定用户发送数据:

function NewMessageNotify(receiverid){
    // get socket for that specific user
    var socket = users[receiverid];
    if (socket) {
        socket.emit("notifications",{ data_type: "message" }); 
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-24
    • 2012-07-16
    • 2016-05-25
    • 2016-02-08
    • 2018-02-09
    • 2020-11-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多