避免存储用于访问公共页面的 cookie
Posted
技术标签:
【中文标题】避免存储用于访问公共页面的 cookie【英文标题】:Avoid storing cookies for visits to public pages 【发布时间】:2022-01-09 19:17:29 【问题描述】:根据Log user out of previous sessions,我使用 NodeJS 和 express-session
将会话信息存储在数据库中。相关代码在主脚本文件中:
const session = require('express-session');
const MongoDBStore = require('connect-mongodb-session')(session);
// Initialize mongodb session storage to remember users.
const store = new MongoDBStore(
uri: config.mongoUri,
// The 'expires' option specifies how long after the last time this session was used should the session be deleted.
// Effectively this logs out inactive users without really notifying the user. The next time they attempt to
// perform an authenticated action they will get an error. This is currently set to 3 months (in milliseconds).
expires: max_session_ms,
);
// Enable sessions using encrypted cookies
app.use(cookieParser(config.secret));
app.use(
session(
cookie:
// Specifies how long the user's browser should keep their cookie, probably should match session expiration.
maxAge: max_session_ms
,
store: store,
secret: config.secret,
signed: true,
resave: true,
saveUninitialized: true,
httpOnly: true, // Don't let browser javascript access cookies.
secure: config.secureCookies, // Only use cookies over https in production.
)
);
在路由文件中:
passport.use('user-otp', new CustomStrategy(
// code to validate one-time password.
));
问题在于,这种方法还会在浏览器上为未登录的用户存储 cookie。以下是访问公共页面的示例:
我只想在创建帐户或登录后(用户同意 cookie 政策)存储 cookie,而不是在公共页面上存储 cookie,以避免 GDPR 要求的“cookie 同意框”。
如何仅在浏览器登录后存储 cookie?
更新
我按照答案中的建议删除了两个cookie。我停止服务器,消除localhost
的cookies,启动服务器,发出公共页面请求,公共页面上还有一个cookie。这是服务器数据库上的会话数据:
> db.sessions.find().pretty()
"_id" : "DObp-FFNJGLD5c5kLKWfkCaEhfWHtWpo",
"expires" : ISODate("2022-03-03T19:41:29.807Z"),
"session" :
"cookie" :
"originalMaxAge" : 7776000000,
"expires" : ISODate("2022-03-03T19:41:29.807Z"),
"secure" : null,
"httpOnly" : true,
"domain" : null,
"path" : "/",
"sameSite" : null
,
"flash" :
浏览器会显示这个 cookie:
当我从应用程序中删除 PassportJS
以及将 sameSite
设置为 "strict"
时,我得到了相同的结果。
第二次更新
由于数据库会话有一个空的flash
字段,我怀疑这是由于闪现消息。我删除了这段代码:
const flash = require("express-flash");
app.use(flash());
现在服务器不存储用于访问公共页面的 cookie。我在通知中为登录用户和公共页面访问者使用 Flash 消息,例如当页面不再可用时。
所以问题变成了:是否可以仅在服务器端使用闪存消息,从一个处理程序到另一个处理程序,而不存储 cookie?
【问题讨论】:
【参考方案1】:在创建静态页面路由之后为 cookie/会话配置您的 app.use()
。 Express 按照声明的顺序评估中间件和路由。
基本上是这样做的:
// Create express app
// Declare app.use(express.static) routes
// Declare app.use(cookie) and app.use(session) routes
// Declare routes that need to use cookies/sessions
因为在这种情况下,静态内容路由是在 cookie/会话中间件之前声明的,所以 cookie 中间件不会应用于静态路由。
如果您的路由结构比这更复杂,我建议您将会话逻辑设置为可以从专用文件(middlware.js?)导出的中间件函数。然后,您可以要求它并根据需要在特定路由器中添加 cookie/会话中间件(在该路由器中声明任何静态路径之后)。
【讨论】:
是的,这行得通。一个缺点:如果用户访问公共页面,它看起来好像他们已退出,例如即使发送了 cookie,他们也会看到“登录”按钮。对于我的用例,我不需要同意,因为我只会存储技术 cookie,例如闪存消息。见***.com/questions/70237367/… 但如果我从头开始,我会这样做,并在子域中实现用户区。【参考方案2】:离开文档,saveUninitialized
标志应该设置为false
-
强制将“未初始化”的会话保存到存储中。当一个会话是新的但未被修改时,它是未初始化的。 选择 false 有助于实现登录会话、减少服务器存储使用或遵守在设置 cookie 之前需要许可的法律。 选择 false 还有助于解决竞争条件,其中客户端在没有会话的情况下发出多个并行请求。 默认值为 true,但不推荐使用默认值, 因为默认值将来会改变。请对此进行研究 设置并选择适合您的用例的内容。
https://github.com/expressjs/session#saveuninitialized
【讨论】:
这消除了公共页面的两个 cookie,我仍然有一个,connect.sid
。你也有吗?
嗯,这看起来很奇怪,但可能与resave
标志有关。不太清楚它是如何运作的 - github.com/expressjs/session#resave
我阅读了链接并设置了resave: false
。我清除了localhost
的cookies 并重新启动了服务器。我仍然得到localhost
设置的connect.sid
cookie。
我刚刚在saveUninitialized
描述的底部看到了这个注释 - Note if you are using Session in conjunction with PassportJS, Passport will add an empty Passport object to the session for use after a user is authenticated, which will be treated as a modification to the session, causing it to be saved. This has been fixed in PassportJS 0.3.0
您可以通过暂时禁用它来测试它是否与 Passport 相关?
我在app.js
中用passport
注释了三行:const passport = require('passport');
、app.use(passport.initialize());
和app.use(passport.session());
。我仍然得到相同的结果。以上是关于避免存储用于访问公共页面的 cookie的主要内容,如果未能解决你的问题,请参考以下文章