MEANJS:SocketIO的安全性

时间:2015-07-06 10:13:12

标签: angularjs node.js security socket.io meanjs

情况

我在我的SocketIO应用程序中使用了库MEAN.JS

NodeJS服务器控制器中的

    var socketio = req.app.get('socketio');
    socketio.sockets.emit('article.created.'+req.user._id,  data);
AngularJS客户端控制器中的

   //Creating listener        
   Socket.on('article.created.'+Authentication.user._id, callback);

   //Destroy Listener
   $scope.$on('$destroy',function(){
        Socket.removeListener('article.created.'+Authentication.user._id, callback);
   });

奥基。效果很好......

问题

如果一个人(黑客或其他人)获得用户的 id ,他可以在另一个应用程序中创建一个同一频道的监听器,并且他可以观看发送给用户的所有数据;例如所有的通知......

  • 我怎样才能做同样的事情,但更安全?

谢谢!

1 个答案:

答案 0 :(得分:2)

前段时间我偶然发现了同样的问题。这是我的解决方案(稍加修改 - 用于生产)。

我们将使用Socket.IO namespaces 为每个用户创建私人会议室。然后我们可以将消息(服务器端)发送到特定的房间。在我们的例子中 - 只有特定的用户才能收到它们。

但是要为每个连接的用户创建私人房间,我们必须先验证他们的身份。我们将使用简单的身份验证中间件supported by Socket.IO since its 1.0 release

1。身份验证中间件

自1.0发布以来,Socket.IO supports middleware.我们将使用它来:

  1. 使用JSON Web Token(请参阅jwt-simple)验证用户身份,并将其作为查询参数发送给我们。 (请注意,这只是一个示例,还有许多其他方法可以执行此操作。)
  2. socket.io连接实例中保存用户ID (从令牌中读取),以供日后使用(在步骤2中)。
  3. 服务器端代码示例:

    var io = socketio.listen(server); // initialize the listener
    
    io.use(function(socket, next) {
      var handshake = socket.request;
      var decoded;
    
      try {
        decoded = jwt.decode(handshake.query().accessToken, tokenSecret);
      } catch (err) {
        console.error(err);
        next(new Error('Invalid token!'));
      }
      if (decoded) {
        // everything went fine - save userId as property of given connection instance
        socket.userId = decoded.userId; // save user id we just got from the token, to be used later
        next();
      } else {
        // invalid token - terminate the connection
        next(new Error('Invalid token!'));
      }
    });
    

    以下是关于如何在初始化连接时提供令牌的示例,客户端:

    socket = io("http://stackoverflow.com/", {
      query: 'accessToken=' + accessToken
    });
    

    2。命名空间

    Socket.io namespaces为我们提供了为每个关联用户创建私人会议室的能力。然后我们可以将消息发送到特定的 room (因此只有其中的用户才能接收它们,而不是每个连接的客户端)。

    在上一步中,我们确保:

    1. 只有经过身份验证的用户才能连接到我们的Socket.IO界面。
    2. 对于每个已连接的客户端,我们将用户ID保存为socket.io连接实例(socket.userId)的属性。
    3. 剩下要做的就是在每次连接时加入正确的房间,其名称等于新连接客户端的用户ID。

      io.on('connection', function(socket){
        socket.join(socket.userId); // "userId" saved during authentication
      
        // ...
      });
      

      现在,我们可以发出仅此用户将会收到

      的有针对性的消息
      io.in(req.user._id).emit('article.created', data); // we can safely drop req.user._id from event name itself