Hacker News new | ask | show | jobs
by tptacek 5252 days ago
Congrats on the launch. I think I speak for everyone on HN when I say, you're going about this the right way: learn enough to build applications for yourself, whether or not you're going to be a code committer over the long term.

Can I give you some quick advice? Don't take this the wrong way: Rails makes it easy to learn enough to be dangerous in 12 weeks. Some quick hits on obvious things you should look over in your application to ensure it isn't overtly insecure:

* Every model class should have an "attr_accessible" statement, and the attributes you expose through it should be minimal. A very common misconception: "the things in attr_accessible are the only attributes users can set". Not so! The things in attr_accessible are the only attributes users can set automatically, through mass assignment. You can expose things that aren't in attr_accessible by manually settings them with assignment statements. Assume anything that's in an "attr_accessible" list, and every attribute of a model without attr_accessible, can and will be set to the most hostile possible value, like "role=admin".

* Rails programming intros have a bad habit of introducing ActiveRecord finders in the context of the model class object --- in other words, "Post.find(params[:id])". This is exactly the wrong way to do it; it's so bad that you can literally generate a list of vulnerabilities on Rails projects by grepping app/controllers for "[A-Z][a-z]+]\.find". Instead, make sure all your finders work via associations, like "@current_user.posts.find(params[:id])".

* Use a popular plugin for file uploads. Rails doesn't do much of anything to defend against file upload/download vulnerabilities. If I was building a public-facing Rails application, I'd do whatever I could to keep the filesystem namespace out of my requests --- storing all files on Amazon S3 without explicitly storing them in temp files is a good way to do this.

* Don't enable the old-style wildcard route ("/:controller/:action/:id) or any of its variants ("/posts/:action/:id :controller => :posts); whether you declare methods "public" or "private" in a controller should have nothing to do with whether they're exposed to attackers.

* Have a "PreauthController" that inherits from "ApplicationController" and disables the is-logged-in check; in other words, every controller, particularly every controller generated by "rails generate", should be post-authentication by default. Set up the before_filter that checks for a valid user session right there in ApplicationController, then "turn it off" for the LoginController by having it inherit from PreauthController. Similarly: if you can get away with not having an AdminController at all --- run a totally separate Rails app for admin that requires a VPN to get to --- do that; otherwise, have an abstract AdminOnlyController class with no methods in it that does nothing but set up a before_filter to check for admin privileges, and have every admin-only controller inherit from it.

* Pretend the backtic operator (the one that executes Unix commands) doesn't exist.

You may do all of these things already (in which case, good for you! you learned more in 12 weeks than a lot of Rails developers do in years). I just called them out because (a) not doing them will be tremendously painful down the road (individual XSS slipups are annoying but unlikely to kill you, but vulnerabilities that allow people to dump your whole database are something else) and (b) they are so easy to fix.

Good luck!

5 comments

Teaching good security practices was one goal of the Ruby on Rails Tutorial (a resource mentioned in the OP). It uses attr_accessible for every model and uses find-through-association (emphasizing the security implications of both), and it most assuredly does not use the /:controller/:action/:id pattern or backticks. It punts image upload over to Gravatar, and recommends Paperclip for those who need custom uploads.

Having a PreauthController definitely sounds like a good idea, but it might be a bit obscure for beginning developers. I'll consider it for inclusion as an exercise in one of the chapters covering authorization, or maybe I'll include it in more advanced Rails Tutorial material down the road. Thanks for the tip.

All I can say is, I looked under the hood at the application we're talking about and thought these might be useful suggestions. Particularly attr_accessible.

I've found a lot of Rails apps over the last couple years that were diligent about having an attr_accessible in every model, but not diligent about what went in the attr_accessible. Following the Rails idiom, they were doing all their attribute assignment through update-style params[:model] model[foo] model[bar] stuff, and attr_accessible "breaks" that.

The Rails tutorial is good (and ambitious) --- just know, this stuff trips up solid, experienced Rails developers all the time.

When I was starting out, every tutorial seemed to assume that I even knew what "mass assignment" implied. Creating a bunch of bad things at once? Changing a lot of existing things in a bad way at once like their creator_id so a bad guy could access them?

I think "mass assignment" and "attr_accessible" in tutorials should always link to the API documentation[1] that explains the implications and the tools at your disposal + example code.

[1]: http://api.rubyonrails.org/classes/ActiveModel/MassAssignmen...

Worse still, I started off with Beginning Rails 3 by Apress, and it makes only one obscure reference to attr_accessible, and not in the context of security, doesn't mention mass assignment at all, and has no chapter on even basic security. Beginners need to learn this stuff early, so Apress' oversight is unforgivable. mhartl OTOH is to be applauded.
I remember reading you post regarding mass assignment a few years back. Great little read.

http://api.rubyonrails.org/classes/ActiveModel/MassAssignmen...

Those are awesome pointers - there should be a tool that you could upload all your applications files to, the tool would scan all the files for these errors and return a report on vulnerabilities found and instructions on correcting. Maybe this already exists? I am a beginner programmer as well, making my way through Rails Tutorial (chapter 10) and Learn Ruby the Hard Way (exercise 35) and Codecademy Code year.
Thank you for this. I will have to look into a few off that list and implement them. All the models does have attr_accessible. Using CarrierWave for uploads.
I think it might be worth your time to double check your attr_accessibles. Just:

  grep attr_accessible app/models/*rb 
Everything that comes up on that list, you should be comfortable with users giving any value they want to; that's what attr_accessible (effectively, not literally) means: "I give up any control of how these attributes will be set".
Thank you for that. I shot you an email..
You seem to have a good bit of experience securing rails apps. Are there lessons hard learnt?
No, it's all just common sense really.
This would make a great blog post. Thanks for the info.