Can I use curl or curb to POST to a form that uses rails' Cross-site request forgery protection?
-
04-06-2021 - |
题
I have a simple rails webpage where a user enters in a few textfields and uploads a picture. Rails then stores the picture and updates the databases on the server. It works fine.
However, I also need a script on another computer to update the web page occasioanlly using the curl/curb libraries. When i try to do that, though, I get this error:
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken)
When I look closer, it seems that rails puts in a hidden field called "authenticity_token" whenever it creates a form:
<form action="/headshots/single" enctype="multipart/form-data" method="post"> <input name="authenticity_token" type="hidden" value="798b514826513c881613a0c18b52839489a12181" /> . . . </form>
The curb script won't work because it doesn't have the "authenticity_token" thing. Is there any way around this? Maybe make another webpage that does the same thing, but just for my curb script?
解决方案
The hidden input is there to prevent Cross-Site Request Forgery. You can't make a post to a rails action which is so protected without first getting the form and extracting the hidden authenticity_token
parameter. curl isn't clever enough to do this on its own.
You have two options:
- turn off the CSRF protection by removing the call to
protect_from_forgery
from your controller(s). Bad Idea. run one request to get the form, use a quick-and-dirty regex to get the paremeter, say
/name="authenticity_token".*value="([^"]+)"/
and then run another request posting that value for
authenticity_token
. It's brittle and it might make people hate you but it will work.- Use something more sophisticated than
curl
to make the necessary request for the form and the successive submission. Mechanize appears to be the de facto standard.
其他提示
How to submit a form with mechanize:
Mechanize.new.get('url_with_form').forms[0].tap{|f| f.field = 'value'}.submit