Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I generate a CSRF token from the Rails console?

I'm trying to make an authenticated post request, and I need the CSRF. When I log in, it isn't generating the _csrf_token for some reason:

2.0.0p247 :126 >   app.post '/community_members/login', {"refinery_user[login]"=>'chloe', 'refinery_user[password]'=>'test'}
 => 302
2.0.0p247 :127 > app.session
 => {"warden.user.refinery_user.key"=>[[56], "$2a$10$gr/rTcQfuXnes1Zml3qOPu"], "session_id"=>"f77d89cef9ff1710890f575b479bb690"}

I tried app.session[:_csrf_token] ||= SecureRandom.base64(32) before login, but it is always deleted. I also tried to get the login form first, but _csrf_token is still not set.

2.0.0p247 :133 >   app.get '/community_members/sign_in'
2.0.0p247 :134 > app.response # authenticity_token is burried in the raw HTML
2.0.0p247 :136 >   app.post '/community_members/login', {"refinery_user[login]"=>'chloe', 'refinery_user[password]'=>'test'}
2.0.0p247 :137 > app.session
 => {"warden.user.refinery_user.key"=>[[56], "$2a$10$gr/rTcQfuXnes1Zml3qOPu"], "session_id"=>"c2c564229e55b81ca788788558d7d11a"}

How do I manually generate the token to pass to the post request?


Oh ok, I think I need to submit the authenticity_token (that is set in the session after GETing the login form) to the login form, then it puts it in the session permanently! This worked:

app.post '/community_members/login', {'authenticity_token'=>'GfT5GtcUmYQ927oNQmh2MR0NKQucGSx8mtMg3Ph9kXw=', "refinery_user[login]"=>'chloe', 'refinery_user[password]'=>'test'}

Here is a full example: https://stackoverflow.com/a/23899701/148844

like image 334
Chloe Avatar asked May 28 '14 21:05

Chloe


2 Answers

I felt like using Nokogiri to parse the response was a little heavy so I wrote a simple regex to pull the authenticity token out of the response.

app.get  '/api_with_form'
authenticity_token = app.response.body.match(/<[^<]+authenticity_token[^>]+value="([^"]+)"[^>]+>/)[1]

I'm using this to log in

app.get  '/users/sign_in'
authenticity_token = app.response.body.match(/<[^<]+authenticity_token[^>]+value="([^"]+)"[^>]+>/)[1]
app.post '/users/sign_in', 'user[email]' => 'my_username', 'user[password]' => 'my_password', authenticity_token: authenticity_token
like image 73
Nate Avatar answered Oct 31 '22 17:10

Nate


Unless you load the page before you do app.post, there is no CSRF token generated to begin with. Manually generating a new one will not help because it won't match what is stored on the server, which is likely to be some null value.

You need to load the page, parse out the CSRF token, and then use that one.

Alternately, you can load the form, try to read the CSRF token out of app.session[:_csrf_token] and use that.

like image 21
merlin2011 Avatar answered Oct 31 '22 17:10

merlin2011