Reputation: 68006
Below is an error, caused by a form in my Rails application:
Processing UsersController#update (for **ip** at 2010-07-29 10:52:27) [PUT]
Parameters: {"commit"=>"Update", "action"=>"update", "_method"=>"put", "authenticity_token"=>"ysiDvO5s7qhJQrnlSR2+f8jF1gxdB7T9I2ydxpRlSSk=", **more parameters**}
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
This happens for every non-get
request and, as you see, authenticity_token
is there.
Upvotes: 190
Views: 302539
Reputation: 401
This error is normal and expected. It probably comes from the fact that the user has a cookie that expires, e.g. when they left the window open for too long. So I would never skip checking the authenticity token.
Instead, I would redirect the user back to the previous page so that they can create a new session. Here is an example how to handle this inside controllers/ApplicationController.rb:
rescue_from ActionController::InvalidAuthenticityToken do
redirect_back(fallback_location: companies_url(subdomain: 'dashboard'), alert: 'Your session expired. Please try again.'
end
Upvotes: 1
Reputation: 13617
What if this exception happens randomly and only on production app ? Only for login scenario.
An ActionController::InvalidAuthenticityToken occurred in sessions#create:
Should I suppose that it may be because some users might have /login page cached and is passed stale token ? No users reports about login problem so I suppose after second approach login worked for them. I use Device if that matters.
Upvotes: 0
Reputation: 8449
I had the same issue but with pages which were page cached. Pages got buffered with a stale authenticity token and all actions using the methods post/put/delete where recognized as forgery attempts. Error (422 Unprocessable Entity) was returned to the user.
Add:
skip_before_filter :verify_authenticity_token
add
skip_before_action :verify_authenticity_token
On pages which do caching.
It deprecated skip_before_filter
in favour of skip_before_action
.
Consider this Q/A or this official RoR doc.
The *_filter family of methods have been removed from the documentation. Their usage is discouraged in favor of the *_action family of methods
you can use skip_forgery_protection
and that it is safe to use it for a REST API that doesn't use session data.
As @toobulkeh commented, this is not a vulnerability on :index
, :show
actions, but beware using this on :put
, :post
actions.
For example:
caches_page :index, :show
skip_before_filter :verify_authenticity_token, :only => [:index, :show]
Upvotes: 239
Reputation: 2532
ActionController::InvalidAuthenticityToken
can also be caused by a misconfigured reverse proxy. This is the case if in the stack trace, you get a line looking like Request origin does not match request base_url
.
When using a reverse proxy (such as nginx) as receiver for HTTPS request and transmitting the request unencrypted to the backend (such as the Rails app), the backend (more specifically: Rack) expects some headers with more information about the original client request in order to be able to apply various processing tasks and security measures.
More details are available on GitHub
TL;DR: the solution is to add some headers:
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;
}
Upvotes: 62
Reputation: 2916
I found a solution.
When you define your own html form you may forget to include an authentication token string needed by the controller for security reasons. But when you use the Rails generator to create forms you get something like following:
<form accept-charset="UTF-8" action="/login/signin" method="post">
<div style="display:none">
<input name="utf8" type="hidden" value="✓">
<input name="authenticity_token" type="hidden"
value="x37DrAAwyIIb7s+w2+AdoCR8cAJIpQhIetKRrPgG5VA=">
.
.
.
</div>
</form>
So the solution to the problem is to either manually add the authenticity_token field or use the Rails form helpers rather then removing, downgrading or upgrading the code Rails generates.
Upvotes: 23
Reputation: 113
I experienced a similar error in Rails 6. Having tried the solutions above, I did a form review and saw that I had used a <button>.....</button>
HTML tag in my form instead of submitting through Rails
<%= form.submit %>form helper. Changing to the form helper resolved the issue.
Upvotes: 0
Reputation: 30206
This happened to me when upgrading from Rails 4.0 to 4.2.
The 4.2 implementation of verified_request?
looks at request.headers['X-CSRF-Token']
, whereas the header my 4.0 app had been getting was X-XSRF-TOKEN
. A quick fix in my ApplicationController was to add the function:
def verify_authenticity_token
request.headers['X-CSRF-Token'] ||= request.headers['X-XSRF-TOKEN']
super
end
Upvotes: 1
Reputation: 52218
This happened to me when carrying out manual tests of the sign up process of my application (signing up/in with multiple users).
A very simple and pragmatic solution may be to do what I did, and use a different browser (or incognito if using chrome).
This was a much better solution in my case than disabling security features!!
Upvotes: 0
Reputation: 4843
Running rails dev:cache
in my console fixed this for me! (Rails 6)
I think it might be something to do with Turbolinks, but CSRF only seems to work when local caching is enabled.
Upvotes: 1
Reputation: 131
For Development environment, I tried many of these attempts to fix this issue, in Rails 6. None of them helped. So if none of these suggestions worked for you, try below.
The only solution I found was to add a txt file into your /tmp folder.
In your app's root directory, either run:
touch tmp/caching-dev.txt
Or manually create a file by that name in your /tmp folder. Since this fixed it for me, I assume the root of the issue is a caching conflict.
Upvotes: 0
Reputation: 3258
In rails 5, we need to add 2 lines of code
skip_before_action :verify_authenticity_token
protect_from_forgery prepend: true, with: :exception
Upvotes: -2
Reputation: 11890
This answer is much more specific to Ruby on Rails, but hopefully it will help someone.
You need to include the CSRF token with every non-GET request. If you're used to using JQuery, Rails has a helper library called jquery-ujs
that builds on top of it and adds some hidden functionality. One of the things it does is automatically includes the CSRF token in every ajax
request. See here.
If you switch away from it like I did you might find yourself with an error. You can just submit the token manually or use another library to help scrape the token from the DOM. See this post for more detail.
Upvotes: 0
Reputation: 31
Add
//= require rails-ujs
in
\app\assets\javascripts\application.js
Upvotes: 3
Reputation: 2339
Following Chrome Lighthouse recommendations for a faster application load, I have asynced my Javascript:
views/layout/application.html.erb
<%= javascript_include_tag 'application', 'data-turbolinks-track' => 'reload', async: true %>
This broke everything and got that Token error for my remote forms. Removing async: true
fixed the problem.
Upvotes: 0
Reputation: 650
I have checked the <%= csrf_meta_tags %> are present and clearing cookies in browser worked for me.
Upvotes: 2
Reputation: 85
For rails 5, it better to add
protect_from_forgery prepend: true
than to skip the verify_authentication_token
Upvotes: 2
Reputation: 23661
Just adding the authenticity_token
in form fixed it for me.
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
Upvotes: 46
Reputation: 274
I had the same issue on localhost. I have changed the domain for the app, but in URLs and hosts file there was still the old domain. Updated my browser bookmarks and hosts file to use new domain and now everything works fine.
Upvotes: 0
Reputation: 232
We had the same problem, but noticed that it was only for requests using http:// and not with https://. The cause was secure: true
for session_store:
Rails.application.config.session_store(
:cookie_store,
key: '_foo_session',
domain: '.example.com',
secure: true
)
Fixed by using HTTPS ~everywhere :)
Upvotes: 6
Reputation: 3753
If you have done a rake rails:update
or otherwise recently changed your config/initializers/session_store.rb
, this may be a symptom of old cookies in the browser. Hopefully this is done in dev/test (it was for me), and you can just clear all browser cookies related to the domain in question.
If this is in production, and you changed key
, consider changing it back to use the old cookies (<- just speculation).
Upvotes: 10
Reputation: 791
There are several causes for this error, (relating to Rails 4).
1. Check <%= csrf_meta_tags %>
present in page layout
2. check authenticity token is being sent with AJAX calls if using form_for
helper with remote: true
option.If not you can include the line <%= hidden_field_tag :authenticity_token, form_authenticity_token %>
withing the form block.
3. If request is being sent from cached page, use fragment caching to exclude part of page that sends request e.g. button_to
etc. otherwise token will be stale/invalid.
I would be reluctant to nullify csrf protection...
Upvotes: 75
Reputation: 4861
I had this problem and the reason was because I copied and pasted a controller into my app. I needed to change ApplicationController
to ApplicationController::Base
Upvotes: 0
Reputation: 9771
I had this issue with javascript calls. I fixed that with just requiring jquery_ujs into application.js file.
Upvotes: 7
Reputation: 49629
For me the cause of this issue under Rails 4 was a missing,
<%= csrf_meta_tags %>
Line in my main application layout. I had accidently deleted it when I rewrote my layout.
If this isn't in the main layout you will need it in any page that you want a CSRF token on.
Upvotes: 87
Reputation: 68006
Problem solved by downgrading to 2.3.5 from 2.3.8. (as well as infamous 'You are being redirected.' issue)
Upvotes: -18
Reputation: 19145
The authenticity token is a random value generated in your view to prove a request is submitted from a form on your site, not somewhere else. This protects against CSRF attacks:
http://en.wikipedia.org/wiki/Cross-site_request_forgery
Check to see who that client/IP is, it looks like they are using your site without loading your views.
If you need to debug further, this question is a good place to start: Understanding the Rails Authenticity Token
Edited to explain: It means they are calling the action to process your form submit without ever rendering your form on your website. This could be malicious (say posting spam comments) or it could indicate a customer trying to use your web service API directly. You're the only one who can answer that by the nature of your product and analyzing your requests.
Upvotes: 32