避免存储访问 public 页面的 cookie

Avoid storing cookies for visits to public pages

我使用 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。以下是访问 public 页面的示例:

我只想在创建帐户或登录后存储 cookie,用户同意 cookie 政策,而不是在 public 页面上,以避免 GDPR 要求的“cookie 同意框”。

如何才能在浏览器登录后才存储cookie?

更新

我按照答案中的建议去掉了两个饼干。我停止服务器,删除 localhost 的 cookie,启动服务器,发出 public 页面请求,但 public 页面上仍然有一个 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());

现在服务器不存储访问 public 页面的 cookie。我在登录用户和 public 页面访问者的通知中使用了 flash 消息,例如当页面不再可用时。

所以问题就变成了:是否可以只在服务器端使用 flash 消息,从一个处理程序到另一个处理程序,而不存储 cookie?

离开文档,saveUninitialized 标志应该设置为 false -

Forces a session that is "uninitialized" to be saved to the store. A session is uninitialized when it is new but not modified. Choosing false is useful for implementing login sessions, reducing server storage usage, or complying with laws that require permission before setting a cookie. Choosing false will also help with race conditions where a client makes multiple parallel requests without a session. The default value is true, but using the default has been deprecated, as the default will change in the future. Please research into this setting and choose what is appropriate to your use-case.

https://github.com/expressjs/session#saveuninitialized

在创建静态页面路由后,为cookie/sessions配置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/session 中间件之前声明的,所以 cookie 中间件不适用于静态路由。

如果您的路由结构比这更复杂,我建议您将会话逻辑作为一个中间件函数,您可以从专用文件中导出它 (middlware.js?)。然后您可以要求它并根据需要在特定路由器中添加 cookie/session 中间件(在该路由器中声明任何静态路径之后)。