MEANJS:SocketIO 中的安全性

MEANJS: Security in SocketIO

情况

我正在使用库 SocketIO in my 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,他可以在另一个应用程序中创建同一频道中的侦听器,并且他可以观看所有数据发送给用户;例如所有通知...

谢谢!

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

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

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

1。认证中间件

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

  1. 验证连接用户身份,使用 JSON Web Token (see jwt-simple) 他发送给我们作为查询参数。 (请注意,这只是一个示例,还有许多其他方法可以做到这一点。)
  2. socket.io 连接实例中保存他的 用户 ID(从令牌中读取),供以后使用(在步骤 2 中)。

服务器端代码示例:

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://whosebug.com/", {
  query: 'accessToken=' + accessToken
});

2。命名空间

Socket.io namespaces 让我们能够为每个连接的用户创建私人 房间 。然后我们可以将消息发送到特定的 room(因此只有其中的用户会收到它们,而不是每个连接的客户端)。

在上一步中,我们确保:

  1. 只有经过身份验证的用户才能连接到我们的 Socket.IO 界面。
  2. 对于每个连接的客户端,我们将用户 ID 保存为 socket.io 连接实例 (socket.userId) 的 属性。

剩下要做的就是在每次连接时加入适当的房间,名称等于新连接客户端的用户 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