Skip to content

Request origin does not match request base_url #22965

Closed
@tpbowden

Description

@tpbowden

I am running the Rails 5.0.0 beta1 and after deploying to production have noticed something odd. My application is running being an Nginx reverse proxy which decrypts SSL.

Every time I try to submit a form, a ActionController::InvalidAuthenticityToken is raised. I have managed to narrow this down to line 399 in ActionController. The problem is that the request origin has https:// as the protocol and the request base_url has http:// as the protocol.

I have tried setting the X-Forwarded-Proto header and using config.force_ssl = true but neither made any difference.

I have not yet figured out a way to isolate a failing test case but am happy to look into it if anyone has any suggestions.

Activity

tpbowden

tpbowden commented on Jan 8, 2016

@tpbowden
Author

Fix by adding more headers in Nginx (X-Forwarded-Ssl on, X-Forwarded-Port 443 and X-Forwarded-Host hostname)

afair

afair commented on Jan 19, 2016

@afair
Contributor

I also ran into this issue. I'll describe it differently to help with future searches.

Submission of any form to Nginx proxying to a Puma unix socket running a Rails 5.0.0.beta1 app responds with:

Can't verify CSRF token authenticity

and throws:

ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken)

even though the App's CSRF is set up correctly. The app works in development (puma or thin, without Nginx), and worked in Nginx/Puma/Rails-4.2. I don't know if this is specific to using Puma, but seems like the same problem could exist with other servers (unicorn, passenger, etc.)

I don't know if this behavior change is an error or intended.

I can confirm @tpbowden's solution worked for me as well. In my nginx configuration, I setup the app to proxy to puma listening on a unix socket. Here are the relevant parts of the configuration.

upstream myapp {
  server              unix:///path/to/puma.sock;
}
...
location / {
  proxy_pass        http://myapp;
  proxy_set_header  Host $host;
  proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header  X-Forwarded-Proto $scheme;
  proxy_set_header  X-Forwarded-Ssl on; # Optional
  proxy_set_header  X-Forwarded-Port $server_port;
  proxy_set_header  X-Forwarded-Host $host;
}
tpbowden

tpbowden commented on Jan 19, 2016

@tpbowden
Author

The issue isn't related to Puma and would happen to any web server running behind a reverse proxy which isn't passing the correct headers through. The way I managed to figure out how this issue was being caused was by following the error down the stack trace.

The root of the issue is the code in request.origin == request.base_url, which compares the Origin header's value against the base_url which is build up by a Rack::Response. There are 3 parts to this value, the scheme, the host and the port. All three of these are calculated based on a series of headers which not present by default when using a reverse proxy.

You can follow the source for Rack::Request#base_url here and it will become clear by looking in your web logs which headers are missing.

tpbowden

tpbowden commented on Jan 19, 2016

@tpbowden
Author

I've just done a bit more research and it is definitely the intended behaviour. It can be disabled in your app config using config.action_controller.forgery_protection_origin_check = false. It is enabled by default however.

jonnyparris

jonnyparris commented on Mar 11, 2016

@jonnyparris

@tpbowden Did you find a solution that doesn't disable forgery protection in the end? I think I'm facing the same problem and really struggling to make 'clean' progress.

tpbowden

tpbowden commented on Mar 11, 2016

@tpbowden
Author

Yes the problem was not passing enough headers through my reverse proxy (nginx) for Rails/Rack to determine whether the request was originally made using https or not (since it was already decrypted by the time it hit Rails)

jonnyparris

jonnyparris commented on Mar 11, 2016

@jonnyparris

ahh, so how did you find out what was missing...and how did you add the missing headers? Thanks so much for the quick reply!

tpbowden

tpbowden commented on Mar 11, 2016

@tpbowden
Author

If you look at @afair's comment above he was referenced a correct Nginx config, you just need to add the x-forwarded headers related to ssl. I figured out which ones were missing by digging though the source code of Rack's request object to find out how it determine's the protocol of the request.

jonnyparris

jonnyparris commented on Mar 11, 2016

@jonnyparris

Alas @afair's config doesn't work for me. Moreover, my logs have been annoyingly sparse since adding my Puma config (but that's another story.)
Thanks anyway, I'll think on it.

jonnyparris

jonnyparris commented on Mar 12, 2016

@jonnyparris

I narrowed my issue down to nginx not playing well with 2 virtual hosts running at the same time. I'm trying to run a staging VPS and a production VPS using jwilder's nginx-proxy.
Everything works fine using the standard generated conf file when only staging OR production is running. However I run into the ActionController::InvalidAuthenticityToken errors on form submissions when both are running at once.
I haven't solved it yet, but thought I'd leave this here in case anyone else follows a similar trail of blunders.

straight-shoota

straight-shoota commented on Feb 7, 2017

@straight-shoota

Thanks @tpbowden and @afair I was desperatly trying to make any sense of this oddly failing CSRF protection... then I found this issue 👍

tripitakit

tripitakit commented on Feb 17, 2017

@tripitakit

Many thanks @tpbowden and @afair, you've made my day!

68 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @afair@fguillen@dchandekstark@eloyesp@straight-shoota

        Issue actions

          Request origin does not match request base_url · Issue #22965 · rails/rails