cURLing with Rails' Authenticity Token

cURLing with Rails' Authenticity Token

Our event, Developers Developers Developers Developers, is this weekend.

When the amount of registrations reached the capacity of the venue, we removed the registration form from the website.

However, we left the Rails route and controller around and encouraged students to register by reading the source code of the application and coding their way in. We pointed them to the staging app so they could practice before registering via the production app.

D8 registration challenge

Rails' authenticity_token

So we just need to POST to /registrations with the right params, right? Right. However, “the right params” needs to include Rails' authenticity_token, which the framework uses to combat CSRF. The payload also needs to include a cookie because the authenticity_token depends on it.

Curling

cURL

So here’s the cURL solution.

Step 1:

curl http://dddd-staging.heroku.com --cookie-jar cookie | grep csrf

That will store the cookies in a file named “cookie” and print out the authenticity_token you need (it’s the value of the content attribute on the csrf-token meta tag):

<meta name="csrf-param" content="authenticity_token"/>
<meta name="csrf-token" content="sNMk592JV2wwHn6DPJ8C5oy/hHDnjIlZBOHyngtTbpQ="/>

Meanwhile, the contents of the cookies file looks like this:

# Netscape HTTP Cookie File
# http://curl.haxx.se/rfc/cookie_spec.html
# This file was generated by libcurl! Edit at your own risk.

#HttpOnly_dddd-staging.heroku.com FALSE / FALSE 0 _dddd_session BAh7...

Step 2:

curl http://dddd-staging.heroku.com/registrations --data
"registration[name]=Dan
Croak&registration[twitter]=croaky&registration[school_name]=Holy
Cross&registration[role]=Developer&authenticity_token=sNMk592JV2wwHn6DPJ8C5oy/hHDnjIlZBOHyngtTbpQ="
--cookie cookie

This adds the authenticity_token and also includes the cookie from the first request.

The output will be the original HTML that we fetched and replaced on the page via Ajax when registration was still open:

<div class="student">
  <div class="avatar">
    <img src="http://avatar.statusok.com/croaky?size=73" />
  </div>
  <div class="student-details">
    <div class="name">Dan Croak</div>
    <div class="twitter">@croaky</div>
    <div class="role-and-school">
      Developer, Holy Cross
    </div>
  </div>
  <h2>Thanks for registering! We can't wait to see you!</>
  <h3>Follow @<a href="http://twitter.com/thoughtbot">thoughtbot</a> and @<a href="http://twitter.com/greenhornboston">greenhornboston</a> for updates.</h3>
  <h3>We also invite you to join our private <a href="http://groups.google.com/group/developers-developers-developers-developers">mailing list</a> for speakers and attending students.</h3>
</div>

Another Approach: Using Web Inspector

However, we’re living in the future here, folks. It’s 2011, and we’ve got a GUI for everything - no need to get Terminal all over your hands.

This is a web browser, I know this

So let’s load the site normally in a web browser, view the HTML source to grab that authenticity token, insert a form into the DOM, then submit it.

I’ll be using Chrome and the WebKit Inspector here, but you could also use Firefox and the excellent Firebug plugin.

Step 1: Find the authenticity token

Here I view the HTML source and look for the authenticity token in the <head> element:

Auth Token

Step 2: Insert a form into the HTML

Here’s the registration form that we’ll add back into the page. I made sure to insert the right authenticity token:

<form action="/registrations" method="POST">
  <input type="text" name="registration[name]"        value="Jason Morrison" />
  <input type="text" name="registration[twitter]"     value="jayunit" />
  <input type="text" name="registration[school_name]" value="RIT" />
  <input type="text" name="registration[role]"        value="Developer" />
  <input type="text" name="authenticity_token" value="iKSXdP4+Ir80ABwsmwvX5LjUKdto3n6p99E/+pgmegI=" />
  <input type="submit" />
</form>

You can insert the form anywhere. Let’s overwrite this paragraph:

Edit HTML

Paste in the HTML:

Pasted HTML

Step 3: Submit the form

Click submit, and you’re off to the races.

Form Success

See you at the event!

Dan Croak Developer