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
为每个用户创建私人房间。然后我们可以向特定 房间 发送消息(服务器端)。在我们的例子中 - 只有特定的用户才能收到它们。
但是要为每个连接的用户创建私人房间,我们必须先验证他们的身份。为此,我们将使用简单的身份验证 middleware,supported by Socket.IO since its 1.0 release.
1。认证中间件
自 1.0 版发布以来,Socket.IO supports middleware.我们将使用它来:
- 验证连接用户身份,使用 JSON Web Token (see
jwt-simple
) 他发送给我们作为查询参数。 (请注意,这只是一个示例,还有许多其他方法可以做到这一点。)
- 在
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(因此只有其中的用户会收到它们,而不是每个连接的客户端)。
在上一步中,我们确保:
- 只有经过身份验证的用户才能连接到我们的 Socket.IO 界面。
- 对于每个连接的客户端,我们将用户 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
情况
我正在使用库 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
为每个用户创建私人房间。然后我们可以向特定 房间 发送消息(服务器端)。在我们的例子中 - 只有特定的用户才能收到它们。
但是要为每个连接的用户创建私人房间,我们必须先验证他们的身份。为此,我们将使用简单的身份验证 middleware,supported by Socket.IO since its 1.0 release.
1。认证中间件
自 1.0 版发布以来,Socket.IO supports middleware.我们将使用它来:
- 验证连接用户身份,使用 JSON Web Token (see
jwt-simple
) 他发送给我们作为查询参数。 (请注意,这只是一个示例,还有许多其他方法可以做到这一点。) - 在
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(因此只有其中的用户会收到它们,而不是每个连接的客户端)。
在上一步中,我们确保:
- 只有经过身份验证的用户才能连接到我们的 Socket.IO 界面。
- 对于每个连接的客户端,我们将用户 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