【问题标题】:Express-session Secure Cookies not working快速会话安全 Cookie 不起作用
【发布时间】:2017-10-17 18:07:40
【问题描述】:

当不使用安全 cookie true 设置时,我的应用用户登录工作正常。当我启用安全 cookie 时,登录似乎正常,但似乎 cookie 未保存且用户未登录。

换句话说,这是可行的:

app = express();
app.use(session({
    secret: 'secret code',
    store: sessionStore,
    resave: false,
    saveUninitialized: false,
    cookie: {
        secure: false,
        maxAge: 5184000000 // 60 days
        }
}));

这不起作用(用户无法登录):

app = express();
app.set('trust proxy');
app.use(session({
    secret: config.cookieSecret,
    store: sessionStore,
    resave: false,
    saveUninitialized: false,
    proxy: true,
    secureProxy: true,
    cookie: {
        secure: true,
        httpOnly: true,
        maxAge: 5184000000 // 60 days
        }
}));

在 cloudflare 和 nginx 之后。这是在我的 nginx 配置中:

location ~ / {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://localhost:3000;
}

根据我的阅读,我认为它应该有效。我错过了什么?

编辑:我正在使用有效的 ssl 证书运行 https。

【问题讨论】:

标签: node.js express nginx express-session


【解决方案1】:

对我有用的设置组合:

  • nginx服务器配置里面,添加proxy_set_header X-Forwarded-Proto $scheme;
  • express-session 配置中:

    server.use(
      session({
        proxy: true, // NODE_ENV === 'production'
        cookie: {
          secure: true, // NODE_ENV === 'production'
        },
        // everything else
      })
    );
    

【讨论】:

  • 在 nginx 中设置代理标头帮助我解决了我的问题。谢谢!
【解决方案2】:

使用 Heroku 时的解决方案:

在 Heroku 中,所有请求都以纯 http 形式进入应用程序,但它们具有标头 X-Forwarded-Proto 以了解原始请求是 http 还是 https。这会导致 express 看到非 ssl 流量,因此它在 Heroku 上运行时拒绝设置安全 cookie。 Express 只会通过 https 发送安全 cookie。 您必须通过启用“信任代理”设置来告诉 express 信任 X-Forwarded-Proto 标头中的信息,即原始请求是通过 https 完成的。。在定义我放的 cookie 属性之前

app.set('trust proxy', 1);

1 表示信任第一个代理。 1 足以让我设置cookie: secure

【讨论】:

    【解决方案3】:

    我的猜测是实际的问题是这样的:

    httpOnly: true
    

    这意味着任何客户端代码都无法访问 cookie(通过document.cookie),并且您执行的任何 XHR(“AJAX”)请求都需要显式设置withCredentials,然后才能在请求中发送任何 cookie .

    这取决于您使用的客户端设置如何做到这一点:

    【讨论】:

    【解决方案4】:

    Apache 反向代理解决方案

    对于那些正在寻找潜在解决方案并使用 Apache 反向代理的用户:确保在相应域的 VirtualHost 指令内的 ProxyPass 指令上方添加以下指令:

    RequestHeader set X-Forwarded-Proto expr=%{REQUEST_SCHEME}
    RequestHeader set X-Forwarded-SSL expr=%{HTTPS}
    
    ProxyPass / http://localhost:8001/
    ProxyPassReverse / http://localhost:8001/
    

    此更改使我的 cookie 得以保留。

    此外,正如其他人所指出的,不要忘记将以下代码添加到您的 生产(或其他使用代理的托管环境)快速配置中:

      if (app.get('env') === 'production') {
          app.set('trust proxy', 1); // trust first proxy, crucial
      }
    

    最后,确保您的 cookie/会话设置正确设置。查看 Stoyan Borov 对最低要求的回答。以下是我的设置方式:

        app.use(session({
            cookie: {
                sameSite: 'lax', // lax or strict
                secure: process.env.NODE_ENV === 'production', // Crucial
                maxAge: 1000 * 60 * 60 * 24 * 30, // 30 days
            },
            proxy: true, // Crucial
            resave: false,
            saveUninitialized: true,
            secret: 'Gotta love cookies',
            store: yourSessionStore,
            rolling: true,
        }));
    

    【讨论】:

    • 很好的答案,感谢您对 Apache 步骤的良好解释!
    • 嗨,维克多,我遇到了同样的问题。见这里*.com/questions/71145818/…。你能告诉我如何设置你在 nodejs/express 中提到的 apache 标头吗?我无法使用 apache 设置它们,因为 heroku 不使用它
    【解决方案5】:

    这正是安全 cookie 的作用。它不会被浏览器保存在不安全的环境中,请阅读http://

    您需要添加一个 ssl sert,将所有 http 请求重定向到 https,然后 cookie 将保存在浏览器中。

    在本地设置 https 很烦人,因此在配置/环境变量中设置 secure 您还可以在源代码管理中设置为 false 并启用它以进行生产/登台。

    编辑: 同时启用重新保存,resave: true

    【讨论】:

    • 我正在使用带有有效 ssl 证书的 HTTPS。抱歉,我应该包含该信息。
    • 启用重新保存,resave: true
    【解决方案6】:

    app.set('信任代理', 1);像魅力一样工作

    【讨论】:

      【解决方案7】:

      从 cookie-parser 中删除密钥似乎可以解决问题并允许出于某种原因登录。我使用与会话 cookie 相同的密钥(正如文档所说的那样),所以我不明白为什么它不起作用,但它与不安全的 cookie 一起使用。将密钥保留在 cookie-parser 上并启用 session resave true 也有效。如果有人能解释一下,将不胜感激。

      【讨论】:

        【解决方案8】:
        <VirtualHost *:80>
         ServerName xx.com
            ProxyPreserveHost On
        <Location "/">
        
                ProxyPreserveHost On
                ProxyPass http://localhost:8080/
                ProxyPassReverse http://localhost:8080/
                RequestHeader set X-Forwarded-Port "443"
                RequestHeader set X-Forwarded-Proto "https"
        </Location></VirtualHost>
        
        
        

        【讨论】:

          最近更新 更多