如何使用 passport.js 正确实现 serializeUser?
How to properly implement serializeUser with passport.js?
好的,所以我刚刚进入 MEAN 堆栈,我正在尝试使用 Passport.js 构建一个应用程序。
我刚刚开始用户序列化以维护会话。在他们的示例中,Passport 使用此进行序列化和反序列化:
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
所以,我的问题是:这个例子是否安全?如果我没有理解错的话,这是否意味着客户端可以伪造用户 ID 以任何拥有该 ID 的用户身份登录?
我想我想问的是,他们的示例是否被认为是 "secure" 和正确的做事方式,或者是否期望您更改这些函数以生成唯一的序列化。如果这被认为是安全的,那么我想我遗漏了一些关于它如何工作的东西,我很乐意被填补。
另一方面,如果这不安全并且我应该编写自己的函数来代替这些函数,那么以下是执行此操作的有效且安全的方法吗:
- 在用户序列化后,生成随机散列并将其放入用户的数据库条目中。随机哈希是代表该用户的序列号。
- 反序列化后,在数据库中查找随机散列和return对应的用户。如果未找到哈希,则抛出某种错误。
- 当用户注销时,从他们在数据库中的条目中删除他们的序列散列。
如果到这里我的逻辑是有效的,那么生成这个随机散列的正确方法是什么?
是的,这就是您进行序列化/反序列化的方式。未从客户端收到 id
。
会话信息存储在您的本地会话存储中,例如。数据库,在一个随机 ID 下。例如,express-session
使用 uid-safe 生成会话 ID。此 ID 设置为 cookie,然后发送给客户端。
当客户端发出请求时,如果会话 ID 未被篡改,则从 cookie 中读取会话 ID(通常该 ID 使用您在初始化会话时定义的 secret
进行签名)。使用此 ID,可以从本地会话存储中读取真实会话数据。这就是反序列化中使用的id
的来源。
这是存储到 MongoDB 的会话对象的示例:
{
"_id" : "_RXnIfFeb_qH6AXMO2ounrxlJZPHkwda",
"session" : "{\"cookie\":{\"originalMaxAge\":null,\"expires\":null,\"secure\":false,\"httpOnly\":true,\"path\":\"/\"},\"passport\":{\"user\":\"5614c62e4372842244660dcf\"}}"
}
这里的_id
就是cookie中签名发送的内容。解码为 JSON 对象的 session
字符串是:
{
"cookie": {
"originalMaxAge": null,
"expires": null,
"secure": false,
"httpOnly": true,
"path": "/"
},
"passport": {
"user": "5614c62e4372842244660dcf"
}
}
此处,passport.user
是我的应用程序 seralizeUser
编辑的实际用户 ID seralizeUser
,在加载会话时提供给 deserializeUser
。
那么,如果您更改 cookie 内容会怎样?如果 cookie 已签名,它将失效,因为更改后的值与签名不匹配。如果未签名,则在查询会话存储时使用该值。该查询不会 return 任何东西,因为您更改了 ID 并且数据库中没有匹配的会话(除非您已经找到/猜到了另一个活动会话的会话 ID - 即执行 session hijacking)。
好的,所以我刚刚进入 MEAN 堆栈,我正在尝试使用 Passport.js 构建一个应用程序。
我刚刚开始用户序列化以维护会话。在他们的示例中,Passport 使用此进行序列化和反序列化:
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
所以,我的问题是:这个例子是否安全?如果我没有理解错的话,这是否意味着客户端可以伪造用户 ID 以任何拥有该 ID 的用户身份登录?
我想我想问的是,他们的示例是否被认为是 "secure" 和正确的做事方式,或者是否期望您更改这些函数以生成唯一的序列化。如果这被认为是安全的,那么我想我遗漏了一些关于它如何工作的东西,我很乐意被填补。
另一方面,如果这不安全并且我应该编写自己的函数来代替这些函数,那么以下是执行此操作的有效且安全的方法吗:
- 在用户序列化后,生成随机散列并将其放入用户的数据库条目中。随机哈希是代表该用户的序列号。
- 反序列化后,在数据库中查找随机散列和return对应的用户。如果未找到哈希,则抛出某种错误。
- 当用户注销时,从他们在数据库中的条目中删除他们的序列散列。
如果到这里我的逻辑是有效的,那么生成这个随机散列的正确方法是什么?
是的,这就是您进行序列化/反序列化的方式。未从客户端收到 id
。
会话信息存储在您的本地会话存储中,例如。数据库,在一个随机 ID 下。例如,express-session
使用 uid-safe 生成会话 ID。此 ID 设置为 cookie,然后发送给客户端。
当客户端发出请求时,如果会话 ID 未被篡改,则从 cookie 中读取会话 ID(通常该 ID 使用您在初始化会话时定义的 secret
进行签名)。使用此 ID,可以从本地会话存储中读取真实会话数据。这就是反序列化中使用的id
的来源。
这是存储到 MongoDB 的会话对象的示例:
{
"_id" : "_RXnIfFeb_qH6AXMO2ounrxlJZPHkwda",
"session" : "{\"cookie\":{\"originalMaxAge\":null,\"expires\":null,\"secure\":false,\"httpOnly\":true,\"path\":\"/\"},\"passport\":{\"user\":\"5614c62e4372842244660dcf\"}}"
}
这里的_id
就是cookie中签名发送的内容。解码为 JSON 对象的 session
字符串是:
{
"cookie": {
"originalMaxAge": null,
"expires": null,
"secure": false,
"httpOnly": true,
"path": "/"
},
"passport": {
"user": "5614c62e4372842244660dcf"
}
}
此处,passport.user
是我的应用程序 seralizeUser
编辑的实际用户 ID seralizeUser
,在加载会话时提供给 deserializeUser
。
那么,如果您更改 cookie 内容会怎样?如果 cookie 已签名,它将失效,因为更改后的值与签名不匹配。如果未签名,则在查询会话存储时使用该值。该查询不会 return 任何东西,因为您更改了 ID 并且数据库中没有匹配的会话(除非您已经找到/猜到了另一个活动会话的会话 ID - 即执行 session hijacking)。