einnocent
einnocent

Reputation: 3954

How to force a secure cookie over HTTP with Rails

I'm working with a Rails app that sits behind a reverse-proxy server (Nginx), and I need the session cookie for the Rails app to be flagged Secure. However, when I set it like below,

Application.config.session_store :cookie_store, :key => '_app_session', :secure => true

Rails stops sending the _app_session cookie.

I know Rails is holding it back because I am hitting Rails directly with curl -v, and I can see the _app_session cookie when I omit :secure => true.

How do I force Rails to send the secure cookie over the HTTP connection?

Note: It's okay, in this specific scenario, to be sending a secure cookie over HTTP. This traffic is happening in an area considered secure before getting wrapped in SSL and sent out into the world. Further, "terminating SSL upstream is quite common", so I'm not the first to have a setup like this.

Alternatives (What Doesn't Work)

Here's what I've tried already:

I wrote a script in Lua that adds Secure to the cookie. It worked, but my boss said we can't have Lua in the Nginx.

I couldn't figure out how to use the following directives in Nginx to achieve what I wanted:

I tried adding set_proxy_header and add_header as suggested here, but it didn't work, and I suspect there's something peculiar about our setup that may be causing that.

Finally, hypothetically I could write a C module for Nginx, but I'm not going to do that.

Upvotes: 1

Views: 4466

Answers (3)

Suciu Eus
Suciu Eus

Reputation: 189

If your application is always secure, the best way is to add proxy_cookie_flags (since Nginx version 1.19.3) configuration to your Nginx (in your desired location). There is no need for an additional script.

For all cookies use:

proxy_cookie_flags ~ secure;

Check more in the documentation: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cookie_flags

Upvotes: 0

brightball
brightball

Reputation: 933

You should look at the rack-ssl-enforcer gem. Removes the problem from rails and it's highly configurable to your needs.

Upvotes: 0

einnocent
einnocent

Reputation: 3954

I added the following to the relevant location blocks in my Nginx conf file:

proxy_set_header X-Forwarded-Proto https;

It didn't work before because I had used X-Forwarded-Proto $scheme at the suggestion of the link in my question. I don't know why that didn't work, but doing

$ curl -v -H "X-Forwarded-Proto: https" http://localhost:95/app-path

does return the expected _app_session cookie, with the Secure flag set, so clearly RoR just needs to know that the secure cookie will end up going out over https.

Update (Jun 2015)

The reason why I had trouble with this was because our servers were proxy passing http requests to themselves for https and not setting X-Forwarded-Proto first. Once I understood our topology better, I was able to do X-Forwarded-Proto $scheme before the first proxy pass. That is the correct solution.

Upvotes: 6

Related Questions