How can a legitimate user submit an invalid CSRF token to Rails?

Our error logs sometimes contain legitimate forms that cause ActionController::InvalidAuthenticityToken .

My hypothesis is that the CSRF token stored in the user's session cookie changed at some point after the form was loaded, but before it was submitted. This causes a mismatch between the POSTed token and the cookie token, resulting in this error.

Given that a Rails session cookie expires only after the browsing session ends (i.e. when the web browser is closed), what are the ways in which this cookie (and the CSRF token it includes) can be changed without closing the browser?

We use cookies to store session data, which is the default behavior of Rails.

+7
ruby-on-rails csrf
source share
5 answers

Here we know:

  • Legal representations that throw an InvalidAuthenticityToken exception InvalidAuthenticityToken somehow lost the original CSRF token.
  • The token is stored in the session, which is stored in an encrypted cookie. Thus, this error means that their session cookie has changed since the form was created.
  • The session cookie does not expire if the user's browser window is not closed.

Now I believe that there are two ways in which invalid CSRF tokens can be presented by legitimate users.

Note that they apply to Rails 4.2. As I understand it, the "to-form CSRF tokens" feature in Rails 5 can soften them.

1. Change session on another tab

According to @crazymykl answer, the user can open the form and then go to another tab. This will modify the session cookie stored in the user's browser. When they return to the original tab and submit the form, the token from the form will not match the token in the session, and an error will appear.

2. Caching

By this rails error , Safari behaves strangely with caching in some circumstances. By reporting that it opens again with the same windows as last time (via Safari > Preferences > General ), opening the form and exiting Safari results when the form is displayed again.

Submitting this cached form causes a CSRF error. As the error opener ends, Safari seems to cache the page, but leaves a session cookie. Hence the discrepancy.

The solution to this problem is to set the Cache-Control header with the no-store directive. (The difference between no-cache and no-store is explained here ).

Other examples are welcome :).

0
source share

The user could log out and return, but had a tab with an open form from the old session. This will send the old token.

+7
source share

You wrote: Given that a Rails session cookie expires only after the browsing session ends (i.e. when the web browser is closed), what are the ways in which this cookie (and the CSRF token it includes) can be changed without closing the browser?


First, your hypothesis is correct. However, how you could do this is worth considering.

Presumptive presumption requires focusing on two levels.

One: a saved cookie is not deleted when a web browsing session ends, unless something has been encoded in this way; The cookie is probably saved until the cookie timeout expires, so itโ€™s likely that the next access to the page will use the old token, but since developers usually allow the page to be refreshed with a โ€œnew loginโ€, they can also refresh the token at that time. See @ Shikhar-Mann's Answer for a better understanding of sign_out_user.

Two: the cookie does not need to be changed for this problem, it is a CSRF token mismatch problem.

So, the main question: how can we have an inconsistent CSRF token that would be easier to answer: old data on the client due to a long wait, which leads to a timeout on the server, which invalidates the CSRF token during the delay. If the web page is not configured / created, as well as timeout and redirection, the client / user will never know.

Also, can I assume that CSRF is NOT persistent? It really isn't that important if you can access form data; I usually create a hidden field with CSRF data and use it instead. CSRF does not live very long, and session data is saved.

+1
source share

If closing the browser is not an option. Then you need to log out. To reach this place, run the following code in the ApplicationController.

rescue_from ActionController :: InvalidAuthenticityToken do | exception |

sign_out_user # Example method that will destroy user cookies

end

PS: Above from http://guides.rubyonrails.org/security.html#cross-site-request-forgery-csrf , so ask for help for more information.

0
source share

Do you use an Ajax form to submit a request? Does your page have multiple forms? If so, check your code to see if the correct csrf token will be sent along with the request. We had a similar problem with the page being displayed with one csrf token, and we used this token to submit the form one, and we would have another csrf token, and the second would send the old csrf token, which led to an error. I'm not sure how useful this is, but you want to share a similar problem with you.

0
source share

All Articles