如何在socket.io和node js上保护用户的“通道”?

时间:2014-09-29 21:08:27

标签: node.js websocket socket.io

我创建了一个非常好的社交网络。我想使用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" }); 
}

1 个答案:

答案 0 :(得分:3)

您的安全模型已损坏,并且正在向所有人发送所有用户的所有消息(您实际上是在广播它们)。通过略微调整客户端javascript或从任何计算机运行的流氓javascript片段,以比socket.io略低的水平挂钩,任何用户都可以收听所有消息。

在此代码中:

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

io.sockets.emit()部分将该消息发送到所有打开的套接字。这根本不是你想要做的。你想要消息&#34; Bob&#34;只被发送到鲍勃的套接字。然后,没有其他人有机会查看它们,除非你以Bob身份认证自己。

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

  1. 如果您没有数以万计的用户,您可以使用聊天室功能。当Bob使用唯一的用户ID登录时,您可以将他与他的名字一起加入聊天室。然后,当你想给Bob发送一条消息时,你只需用他的名字向聊天室广播。他将成为该聊天室的唯一监听者,因为您的服务器永远不会让其他任何人进入它。这稍微违背了聊天室的设计,但由于你的userIds必须是唯一的,它允许你使用用户名作为聊天室名称,socket.io将自动为你保留名称和套接字之间的链接。

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

  3. 示例代码:

    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" }); 
        }
    }