The authenticity token is used to prevent Cross-Site Request Forgery attacks (CSRF). To understand the authenticity token, you must first understand CSRF attacks.
CSRF
Suppose that you are the author of bank.com
. You have a form on your site that is used to transfer money to a different account with a GET request:
A hacker could just send an HTTP request to the server saying GET /transfer?amount=$1000000&account-to=999999
, right?
Wrong. The hackers attack won't work. The server will basically think?
Huh? Who is this guy trying to initiate a transfer. It's not the owner of the account, that's for sure.
How does the server know this? Because there's no session_id
cookie authenticating the requester.
When you sign in with your username and password, the server sets a session_id
cookie on your browser. That way, you don't have to authenticate each request with your username and password. When your browser sends the session_id
cookie, the server knows:
Oh, that's John Doe. He signed in successfully 2.5 minutes ago. He's good to go.
A hacker might think:
Hmm. A normal HTTP request won't work, but if I could get my hand on that session_id
cookie, I'd be golden.
The users browser has a bunch of cookies set for the bank.com
domain. Every time the user makes a request to the bank.com
domain, all of the cookies get sent along. Including the session_id
cookie.
So if a hacker could get you to make the GET request that transfers money into his account, he'd be successful. How could he trick you into doing so?
With Cross Site Request Forgery.
It's pretty simply, actually. The hacker could just get you to visit his website. On his website, he could have the following image tag:
<img src="http://bank.com/transfer?amount=$1000000&account-to=999999">
When the users browser comes across that image tag, it'll be making a GET request to that url. And since the request comes from his browser, it'll send with it all of the cookies associated with bank.com
. If the user had recently signed in to bank.com
... the session_id
cookie will be set, and the server will think that the user meant to transfer $1,000,000 to account 999999!
Well, just don't visit dangerous sites and you'll be fine.
That isn't enough. What if someone posts that image to Facebook and it appears on your wall? What if it's injected into a site you're visiting with a XSS attack?
It's not so bad. Only GET requests are vulnerable.
Not true. A form that sends a POST request can be dynamically generated. Here's the example from the Rails Guide on Security:
<a href="http://www.harmless.com/" onclick="
var f = document.createElement('form');
f.style.display = 'none';
this.parentNode.appendChild(f);
f.method = 'POST';
f.action = 'http://www.example.com/account/destroy';
f.submit();
return false;">To the harmless survey</a>
Authenticity Token
When your ApplicationController
has this:
protect_from_forgery with: :exception
This:
<%= form_tag do %>
Form contents
<% end %>
Is compiled into this:
<form accept-charset="UTF-8" action="/" method="post">
<input name="utf8" type="hidden" value="✓" />
<input name="authenticity_token" type="hidden" value="J7CBxfHalt49OSHp27hblqK20c9PgwJ108nDHX/8Cts=" />
Form contents
</form>
In particular, the following is generated:
<input name="authenticity_token" type="hidden" value="J7CBxfHalt49OSHp27hblqK20c9PgwJ108nDHX/8Cts=" />
To protect against CSRF attacks, if Rails doesn't see the authenticity token sent along with a request, it won't consider the request safe.
How is an attacker supposed to know what this token is? A different value is generated randomly each time the form is generated:
A Cross Site Scripting (XSS) attack - that's how. But that's a different vulnerability for a different day.