koa: SSL load balancer + secure cookies means lots of requests 500 error
I’m running a Koa app behind a load balancer that terminates SSL. I set app.proxy to true, and have these lines to enable secure session cookies:
const session = require('koa-session');
app.proxy = true;
app.use(session({secure: true}))
When the load balancer terminates SSL and sends through X-Forwarded-Proto: https requests, everything works fine and a secure cookie gets set.
However, any request without a X-Forwarded-Proto: https header generates the following stack trace:
Error: Cannot send secure cookie over unencrypted connection
at Cookies.set (/Users/kevin/src/github.com/bigco/website/node_modules/koa/node_modules/cookies/lib/cookies.js:86:11)
at Session.save (/Users/kevin/src/github.com/bigco/website/node_modules/koa-session/index.js:296:15)
at commit (/Users/kevin/src/github.com/bigco/website/node_modules/koa-session/index.js:163:10)
at Object.session (/Users/kevin/src/github.com/bigco/website/node_modules/koa-session/index.js:120:7)
at session.next (<anonymous>)
at Object.bodyParser (/Users/kevin/src/github.com/bigco/website/node_modules/koa-bodyparser/index.js:68:12)
at bodyParser.next (<anonymous>)
at onFulfilled (/Users/kevin/src/github.com/bigco/website/node_modules/koa/node_modules/co/index.js:65:19)
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
The offending code is here, in the cookies library:
, secure = this.secure !== undefined ? !!this.secure : req.protocol === 'https' || req.connection.encrypted
, cookie = new Cookie(name, value, opts)
, signed = opts && opts.signed !== undefined ? opts.signed : !!this.keys
if (typeof headers == "string") headers = [headers]
if (!secure && opts && opts.secure) {
throw new Error('Cannot send secure cookie over unencrypted connection')
}
A response is that I should be performing http redirects at the load balancer layer and my Node app shouldn’t handle http requests. Of course.
But there are a variety of reasons I might send requests without that header:
- my Node app needs to do custom logic to decide how to redirect HTTP requests to HTTPS
- the load balancer sends health checks and I can’t configure the headers it sends, also it is not forwarding them for a health check
- automated tooling makes requests directly to an app host (say, a stats or expvar server)
Basically it doesn’t seem like setting a secure cookie in an insecure environment should be an error, and it’s confusing that every request has to set X-Forwarded-Proto: https even when it’s not forwarding the request from anywhere else.
Alternatively, koa could just decide to not set a session cookie if there’s no X-Forwarded-Proto: https header, or catch this error from the cookies library and handle it appropriately. But it doesn’t seem very easy to handle in my own codebase.
Let me know if this is better to be reported against the cookies library. I think this is the right place for it, though.
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Comments: 17 (3 by maintainers)
Previously, previously, previously, previously, previously, previously.
I’m running into the same issue as @kevinburke . In short, I have an app that is in the following infra:
browser (https/443) -> AWS ALB (load balancer) -> Web App (http/80) with Proxy Middleware -> ALS ALB 2 (http/80) -> Web App 2.
I’m not in control of the infrastructure, but I know that the incoming request will be secure, so I want to force koa to send secure cookies.
To be fair, it’s possible I’m running into this because ALBs may not chain
X-Forwarded-*headers correctly, but nevertheless, it would be helpful to have an option to override the cookie setting in koa.I adapted @kevinburke 's middleware for koa 2:
For the moment, working around this with this middleware:
Fourth link is broken, by the way. I think you meant https://github.com/pillarjs/cookies/issues/71
@kevinburke not sure if this is still relevant to you. But the app.proxy (koajs) value needs to be set to true, so that the “X-Forwarded-Proto” value will be trusted, which should be set to “proxy_set_header X-Forwarded-Proto https;”, in Nginx for example.
not sure what you expect. you are sending a secure cookie over a non-secure connection. i would just not set the cookie on a non-secure connection but not allowing sessions on those requests. in other words, put your health check middleware above the session middleware.
this is also why i don’t like session middleware that always create/check the session. i use https://github.com/koajs/redis-session-sets for a more functional version of sessions – sessions are only created and updated when i specifically ask for it.