Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the CSRF token in Rails not prevent multiple tabs from working properly?

After reading about how the CSRF protection works in Rails, I tried to trigger CSRF protection by doing this:

Note: We are using cookie based sessions.

  1. Visit login page. Check CSRF token in meta => abc123
  2. Open a 2nd browser tab, and visit the same login page. CSRF token in meta is different => def456
  3. Go back to 1st tab.
  4. Submit login credentials.

I expected this to fail, because the 2nd tab generated a new, different CSRF token. When the login form submits, shouldn't the token that gets submitted to the server be an old, stale one?

However, this does work:

  1. Visit login page. Check CSRF token in meta => abc123
  2. Open a 2nd browser tab, and visit the same login page. CSRF token in meta is different => def456
  3. Go back to 1st tab.
  4. Submit login credentials.
  5. Logout (clearing session)
  6. Go to 2nd tab, and submit login.

In this case, I get an InvalidAuthenticityToken exception as expected. Why?

like image 485
you786 Avatar asked Dec 08 '17 23:12

you786


People also ask

How does CSRF token work in Rails?

Rails CSRF TokenThe server generates these tokens, links them to the user session, and stores them in the database. This token is then injected into any form presented to the client as a hidden field. When the client correctly submits the form for validation, it passes the token back to the server.

Why CSRF token is not working?

Invalid or missing CSRF token This error message means that your browser couldn't create a secure cookie, or couldn't access that cookie to authorize your login. This can be caused by ad- or script-blocking plugins, but also by the browser itself if it's not allowed to set cookies.

Can a CSRF token be used more than once?

The CSRF token sent in the state parameter is the "client side" of your usual CSRF token (the one you put in a hidden input field on your forms). Since the CSRF token will (by design) be sent in GET requests, it's advisable to make them unique and not reuse them.

How does Ruby on Rails prevent CSRF?

Briefly, Cross-Site Request Forgery (CSRF) is an attack that allows a malicious user to spoof legitimate requests to your server, masquerading as an authenticated user. Rails protects against this kind of attack by generating unique tokens and validating their authenticity with each submission.


1 Answers

Source: https://medium.com/rubyinside/a-deep-dive-into-csrf-protection-in-rails-19fa0a42c0ef

Why the request in the second tab doesn't fail

The CSRF token in the meta tag is actually a concatenation of two strings: a "one-time pad" generated per request, and the "real" CSRF secret XORed with the one-time pad. See in the diagram below how the one-time pad is prepended to the XORed string in the masked token, which gets stored in the meta tag:

Diagram of construction of CSRF token

Rails stores the CSRF secret in a session cookie without XORing. Javascript should be used in the browser to read the masked token from the meta tag and pass it in the X-CSRF-TOKEN header.

When Rails validates a request, it:

  1. Splits the value passed in the X-CSRF-TOKEN header to retrieve the one-time pad and XORed string.
  2. XORs them together to retrieve the real secret.
  3. Compares this with the secret in the cookie.

This is why you are seeing changing tokens in the meta tag -- the one-time pads are different. If you validated the tokens, you would find the same secret in both tokens.

Note: This one-time pad business might seem unnecessary. Anyone can retrieve the real secret if they have the masked token. Surprisingly, the purpose of the XORing is to change the CSRF token on every request so an attacker can't use timing attacks to discern the secret. See this paper on the BREACH SSL attack.

Why the request fails on logout

As noted in @max's comment, logging out deletes the session cookie. The next request generates a new CSRF secret which no longer matches the older masked tokens.

like image 72
Sarkom Avatar answered Sep 28 '22 19:09

Sarkom