If I create a brand new Rails application (using Rails 3.0.9) and knock up a quick bit of scaffolding as follows:
$ rails new testing
$ rails g scaffold thing name:string
Then app/controllers/application_controller.rb contains a "protect_from_forgery" by default, so it should check the authenticity_token during a POST create. At least, that's my understanding.
Why then, does this line successfully create a new Thing, without supplying the token.
$ curl -F "thing[name]=abc123" http://localhost:3000/things
The log entry says:
Started POST "/things" for 127.0.0.1 at 2011-07-05 08:29:18 +0100
Processing by ThingsController#create as
Parameters: {"thing"=>{"name"=>"abc123"}}
AREL (0.3ms) INSERT INTO "things" ("name", "created_at", "updated_at") VALUES ('abc123', '2011-07-05 07:29:18.484457', '2011-07-05 07:29:18.484457')
Redirected to http://localhost:3000/things/18
Completed 302 Found in 89ms
I can also do this to delete records:
$ curl -X DELETE http://localhost:3000/things/18
The same thing happens in production mode. Doesn't this leave my application open to CSRF?
If you pass invalid CSRF token or send request without it, Rails will nullify session, so protect_form_forgery is useless if your application could be accessed by everyone.
But it will save your application from CSRF attack if you have session-based authentication system.
More info: How does Rails CSRF protection work?
Related
I wanted to build API for my existing application. The special authentication token was generated and added to my database. The problem is that when it comes to comparing between token sent by user application with the one defined in the database, I get such error:
NameError (uninitialized constant ActiveSupport::SecurityUtils):
app/controllers/api/v1/base_controller.rb:64:in `authenticate_user!'
Rendered
/home/snow/.rvm/gems/ruby-2.0.0-p643/gems/actionpack-4.0.2/lib/action_dispatch/middleware/templates/rescues/_source.erb
(25.4ms)
Rendered
/home/snow/.rvm/gems/ruby-2.0.0-p643/gems/actionpack-4.0.2/lib/action_dispatch/middleware/templates/rescues/_trace.erb
(0.8ms)
Rendered
/home/snow/.rvm/gems/ruby-2.0.0-p643/gems/actionpack-4.0.2/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb
(29.9ms)
Rendered
/home/snow/.rvm/gems/ruby-2.0.0-p643/gems/actionpack-4.0.2/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (74.0ms)
Or you can see the response from postman:
Searching the Web for answer, it appeared that it may be caused by the incompatibility of Rails version and secure_compare method. (My application is built on Rails 4.0.2 while it is needed to use Rails 4.2.0.) Is rails upgrading the only solution for my problem, or is there any other way to securely compare tokens without using ActiveSupport::SecurityUtils ?
Authentication code is here:
def authenticate_user!
token, options = ActionController::HttpAuthentication::Token.token_and_options(request)
user_phone_number = options.blank?? nil : options[:phone_number]
user = user_phone_number && User.find_by(phone_number: user_phone_number)
if user && ActiveSupport::SecurityUtils.secure_compare(user.authentication_token, token)
#current_user = user
else
return unauthenticated!
end
end
I have a large number of JSON files and would like to automate POSTing them all via my form. I tried via curl:
curl -d "startup[name]='test startup'" -d "startup[url]='http://startup.com'" -d "startup[category]=['','Analytics']" -d "startup[founded(1i)]='2013'" -d "startup[founded(2i)]='5'" -d "startup[founded(3i)]='1'" -d "startup[description]='blah'" http://localhost:5000/startups
But I get an HTML response with a trace that says ActionController::InvalidAuthenticityToken
How can I easily automate my POSTs. If I can do this easier in Ruby I would love to hear how.
You can disable csrf protection on controller-by-controller basis:
skip_before_filter :verify_authenticity_token
Add the above line to StartupsController, now the form will submit
I think you should do a get request to the new action first, say
http://localhost:5000/startups/new
Then parse html to find out the authenticity token, use this as one of the parameters of your POST request
I'm trying to simulate a POST to my simple Rails scaffold web service. The files created by the scaffold have not been changed. When I POST data from the website form, a record is created correctly.
When I attempt to POST with curl, a record is created in the database, but it has NULL values in the fields, except for 'updated_at' and 'created_at'. I'm new to command line curl so I may not be doing it correctly.
curl -d "name=Gazoo&friend=Rubble" localhost:3000/flintstones
I get back this from WEBrick:
Started POST "/flintstones" for 127.0.0.1 at Thu Apr 28 18:04:47 -0600 2011 Processing by FlintstonesController#create as Parameters: {"name"=>"Gazoo", "friend"=>"Rubble"} AREL (0.3ms) INSERT INTO "flintstones" ("name", "friend", "created_at", "updated_at") VALUES (NULL, NULL, '2011-04-29 00:04:47.779902', '2011-04-29 00:04:47.779902') Redirected to http://localhost:3000/flintstones/4
After a GET for the json
curl localhost:3000/flintstones.json
I receive:
[{"flintstone:{"name":null,"created_at":"2011-04-29T00:09:58Z","updated_at":"2011-04-29T00:09:58Z","id":4,"friend":null}}]
Why do I get null in my fields?
Thanks in advance.
I've googled a bit and every example of using curl with a rails web service shows the parameters passed in the format
object[paramName]=paramValue
as well as one -d set for each parameter which would make your CURL statement look like
curl -d "flintstone[name]=Gazoo" -d "flintstone[friend]=Rubble" localhost:3000/flintstones
Here are the sources I'm referencing:
How to Use cURL to Test RESTful
Rails
Using cURL to test RESTful
Rails Web Services
Rails (by default) doesn't look for a post body in the way provided, "name=Gazoo&friend=Rubble". It looks for this scheme - given your model is Flintstones and your fields are name and friend - "Flintstone[name]=Gazoo&Flintstone[friend]=Rubble". This is rail's DSL for post body from a form post.
I'm using Rails 2.3.8 with Ruby 1.8.7 (both installed via CPanel) and gem 1.3.7 and I'm using MongoDB.
Well, I get the following error when I'm trying to create an user (class User):
Processing UsersController#create (for 127.0.0.1 at 2010-11-13 16:09:55) [POST]
Parameters: {"commit"=>"Create", authenticity_token"=>"3AdGHqazhzJUddjLDIKSNzcGTR8KN1Hh7PL+9+vrJ74=", "user"=> "name"=>"jqa"}}
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken)
Rendering /home/jqa/public_html/web/public/422.html (422 Unprocessable Entity)
Any Help? Thanks in advance
Are you using rails form helper to generate the registration form? I guess not and thats why you are getting this error. I suggest you to use form_for or form_tag method for the form.
You are getting this because rails generate an authenticity token along with the generated form which gets posted back on form submit as a hidden field. With this rails can assume that it is an authentic request from the same app.
If you have generated the form with hand crafter html, this hidden field wont be there in the form and that why rails is cribbing about it!
there is a scaffold created Story... and in the create action, there is
#story = Story.new(params[:story])
i was curious as to what is in params... so i want to dump out params... but there is no view associated with the create action... is there a way to dump out its content? is there a way to dump out the POST variables in of my code too? (to see what's going on in the lower level)
The easiest thing to do is just dump params out to the log:
Rails.logger.info("PARAMS: #{params.inspect}")
If you're in development mode, just look in your development.log and that line will be there.
The params scope is a combination of URL/FORM (GET/POST) fields, and it will be printed out in the log as part of the normal output processing, so you might not need your own dumping of it - any development or production log contains the params dump at the top of the log line, e.g.
Processing Clients::ClientsController#show (for x.x.x. at 2009-05-24 00:34:26) [GET]
Parameters: {"id"=>"303", "user_id"=>"2"}
Now I know Rails more, you can also simply use a
p params
in your code and look at the console's output (the log shown on the console)
If you're on a Mac, Spike is a great little app the analyses log files and will let you inspect params for requests, amongst other things.
Using Fiddler on Windows, it is shown
the HTTP line #1 is:
POST /stories HTTP/1.1
this is the POST content:
authenticity_token=62iw%2BrsxlCFsbnxsS7FXKRn6CcvJfjottrsBPlM5lZo%3D&story%5Bname%5D=Google+Main+Site&story%5Blink%5D=www.google.com&commit=Create
listed in a table:
authenticity_token 62iw+rsxlCFsbnxsS7FXKRn6CcvJfjottrsBPlM5lZo=
story[name] Google Main Site
story[link] www.google.com
commit Create
and the server log is:
Parameters: {"commit"=>"Create", "story"=>{"name"=>"Google Main Site", "link"=>"www.google.com"}, "authenticity_token"=>"62iw+rsxlCFsbnxsS7FXKRn6CcvJfjottrsBPlM5lZo="}
You don't need to anything except look in your logs (they live in /log). Unless you're fiddling with something, the logging of parameters is turned on by default in all logs.
Processing PostsController#create (for 127.0.0.1 at 2009-05-24 13:03:24) [POST]
Parameters: {"commit"=>"Create", "authenticity_token"=>"2G6BKOs8xNAaXiToVf4r1ko8QZzP9QAomi2PHVQC5Oc=", "story"=>{"something"=>"asdfafd"}}
Parameters lists all parameters, and the hash following "story" is the equivalent of params[:story] (everything comes to the server as strings, and Rails turns it into a HashWithIndifferentAccess so that you can access it with a symbol).
If you're on a *NIX system (including OS X) open a new terminal window/tab and type the following command:
tail -f log/development.log
You'll get a constant stream of requests coming in -- including params -- and the resulting DB actions. Invaluable for development/debugging, IMO.