In this article I have described the security issues related to a ruby on rails web application. I have followed DRY by linking to articles with good explanation and solutions to security concerns wherever required. This guide can also be used as a quick security check for your current web application.
Authentication is the foremost requirement of most of the web applications to authenticate and give privileges to their users. Apart from normal authentication mechanism rails have plugins for OpenID, CAS and Access Control. Build your own authentication system only if your requirements are very unique or you do not trust other implementations.Plugin - Restful Authentication (recommended) - easy to use and you can tweak it according to your requirements.
http://railscasts.com/episodes/67 http://svn.techno-weenie.net/projects/plugins/restful_authentication/ Build your own authentication. You should rarely need to do this ... Restful Authentication is quite flexible.
http://www.aidanf.net/rails_user_authentication_tutorial OpenID - a universal authentication system to avoid use of multiple username and password on the Internet. OpenID is getting quite famous now-a-days.
http://media.railscasts.com/videos/068_openid_authentication.mov http://agilewebdevelopment.com/plugins/openidauthentication Access Control : To easily proivde different priviliges to your users. There are a lot of cool plugins available for access control.
https://opensvn.csie.org/traccgi/tobionrailshttp://code.google.com/p/rolerequirement/http://agilewebdevelopment.com/plugins/activeacl_rails_authorization_system Centralized Authentication Server - is used to implement single login/password for your users across multiple application. It can also be used for a single sign-on system. For example, Gmail and Google Reader have a single sign-on between them.
http://agilewebdevelopment.com/plugins/cas_authentication_filter Use Google Authentication API to let your users login using their google username and password.
http://rubyforge.org/projects/asgoogleaccount/ More Plugins :
Rails inbuilt Authentication - http://ryandaigle.com/articles/2006/12/4/whats-new-in...Acts_as_authenticated - http://technoweenie.stikipad.com/plugins/show/User+AuthenticationSuper Simple Authentication - http://ariejan.net/2007/08/24/super-simple-...
- Model -
The problem arises when metacharacters are injected into your queries to database. Rails has a very good support to avoid SQL injection if you follow conventions in issuing queries to your database.Description :
http://manuals.rubyonrails.com/read/chapter/43 Alternate Solution - use hash for specifying conditions in #find
http://rails.rubyonrails.com/classes/ActiveRecord/Validations/ClassMethods.html Conditional validation using :on and :if options. Checkout this cool video
http://media.railscasts.com/videos/041_conditional_validations.mov Be careful using validates_uniqueness_of, it has problems when used with :scope option. Open bug tickets :
http://dev.rubyonrails.org/ticket/5608http://dev.rubyonrails.org/ticket/9235http://dev.rubyonrails.org/ticket/8811http://dev.rubyonrails.org/ticket/8774 Use :allow_blank to pass validations if value is nil or empty string
http://ryandaigle.com/articles/2007/9/5/what-s-new-in-edge-rails-validations-now-allow_blank Testing Validations - do read the comments in this article
http://blog.jayfields.com/2006/12/rails-unit-testing-activerecord.html Useful Tips
Its easy to manage 'nil' values using :allow_nil, its quite handy. For ex: set :allow_nil => true in validates_uniqueness_of to check uniqueness of non-nil values and ignore nil values
validates_presence_of is not required if you are using validates_format_of, unless regular expression accepts empty string.
Creating records directly from parameters
While creating database records directly from form params, a malicious user can add extra fields into the params and manually submit the web page which will set values of fields which you do not want user to set.Description :
http://manuals.rubyonrails.com/read/chapter/47 Alternate Solution - Trim the parameters to keep the required keys and remove the others.
- Controller -
Use private and protected in controller for methods which should not be actions. Actions are pubic methods and can be invoked from the browser.hide_action : If non-action controller methods must be public, hide them using hide_action.
http://www.mathewabonyi.com/articles/2006/08/11/hide_action-a-hidden-treasure Be careful of bypassing private and protected using meta-programming
Always authorize user request. By tweaking form parameters or url a user can send request to view/modify other users information if there is no proper authorization of parameters.For example :
## To find information of an order which belongs to a particular user.
@order = Order.find(order_id)
@order = @user.orders.find(order_id)Do not ignore hidden fields - a user can easily modify their value, so suspect them similar to params[:id]
Filter sensitive logs
Prevent logs of sensitive unencrypted data using #filter_parameter_logging in controller. The default behavior is to log request parameters in production as well as development environment, and you would not like logging of password, credit card number, etc.Video Tutorial
Cross Site Reference(or Request) Forgery (CSRF)
In a CSRF attack, the attacker makes victim click on a link of his choice which would contain a GET/POST request and causes web application to take malicious action. The link could be embedded in a iframe or an img tag. Its recommended to use secret token while communicating with user to avoid this attack.
Its little complex to understand this attack. So, only those readers who are very enthusiastic to know about it, please read the Description below. Rest can directly move ahead to use the plugin.Description :
http://isc.sans.org/diary.html?storyid=1750 http://en.wikipedia.org/wiki/Cross-site_request_forgery Use Get and Post appropiately (note : Both get and post are vulnerable to CSRF)
http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1 Example - Gmail CSRF security flaw
http://ajaxian.com/archives/gmail-csrf-security-flaw Plugin - CSRF Killer (recommended) - it requires edge rails
Secure action - http://code.google.com/p/secure-action-plugin/Security extension - http://svn.aviditybytes.com/rails/plugins/security_extensions/
Minimize session attacks
If an attacker has session-id of your user, he can create HTTP requests to access user account. An attacker can get session-id by direct access to user machine or is able to successfully run malicious scripts at user machine. In this section we will talk about how to avoid or minimize the risk if attacker has user session-id. Following steps are helpful:
Store IP Address, but creates problem if user moves from one network to another.
Create a new session everytime someone logs in.
Expire session on user logout, user is idle for a time period or on closing of browser/tab. For maximum security expire sessions on all the three conditions. Code for session expiry on timeout
## Timeout after inactivity of one hour.
MAX_SESSION_PERIOD = 3600
reset_session if session[:expiry_time] and session[:expiry_time] <>http://www.naffis.com/2007/5/22/automatically-expiring-sessions-in-rails Do not put expiry time in the cookie unless your cookie information is properly encrypted. If not, use server side session expiry.
http://wiki.rubyonrails.org/rails/pages/HowtoChangeSessionOptions Persistent session / login in rails - global setting in enviornment.rb
ActionController::Base.session_options[:session_expires] = say after two yearsPersistent session / login in rails - to give your users a feature - remember me
http://blog.codahale.com/2006/04/08/dynamic-session-expiration-times-with-rails/ http://www.onrails.org/articles/2006/02/18/auto-login http://livsey.org/2006/6/30/persistent-logins-in-rails
Stop spam on your website from DNS Blacklist
Avoid access to your website from IP addresses which are present in DNS Blacklist(DNSBL).Plugin - DNSBL check
Caching authenticated pages
Page caching does bypass any security filters in your application. So avoid caching authenticated pages and use action or fragment caching instead.
- View -
Cross site scripting(XSS) attack
http://manuals.rubyonrails.com/read/chapter/44 Can we avoid tedious use of h() in views?
http://wiki.rubyonrails.org/rails/pages/HowToEscapeHTML Sanitize() is used to escape script tags and other malicious content other than html tags. Avoid using it ... its unsecure. Use white_list instead.
http://www.rorsecurity.info/2007/08/17/dont-use-strip_tags-strip_links-and-sanitize/ White_list plugin
Anti-spam form protection
When using Captcha do ensure the following :
Images are rendered on webpage using send_data and are not stored at the server, because its not required to store images and are redundant.
Avoid using algorithm used by standard Catpcha plugins as they can easily be hacked, instead tweak an existing algorithm or write your own.
Use a Captcha which does not store secret code or images in filesystem, as you will have trouble using Captcha with multiple servers. Tutorial - a nice article on concepts of captcha
http://revolutiononrails.blogspot.com/2007/04/pedo-mellon-minno-or-captcha-on-rails.html Plugin - ReCaptcha (recommended)
http://recaptcha.net/http://ambethia.com/recaptcha/ Plugin - BrainBuster - a logic captcha based on simple puzzles, math and word problems. By default, it has limited set of problems and you would have to come up with large set of your own problems.
http://robsanheim.com/brain-buster Plugin - Simple Captcha (not recommended) as it breaks all the must have features of a good Captcha implementation.
Hide mailto links
Mailto links in a webpage can be attacked by e-mail harvesting bots. Use the plugin CipherMail to generate a 1024 bit random key and obfuscate the mailto link.Plugin - CipherMail
Use password strength evaluators
A lot of people have used password strength evaluators simply because its used by google in their registration form. You can use it to help your users register with strong password. But I don't think its a must have security addon. Uptill now I have not found a good algorithm to assess strength of a password, but some of them are reasonable.
Also, if there is an open source tool or algorithm for evaluating password strength, it can easily be broken. So, you might consider tweaking the algorithm or building one from scratch.Tools
http://www.certainkey.com/demos/password/ http://www.jeffro2pt0.com/ajax-powered-password-strength-meter/ http://www.geekwisdom.com/dyn/passwdmeter http://www.jvoorhis.com/articles/2006/04/06/automatic-password-suggestion-for-your-rails-app
- Miscellaneous -
Transmission of Sensitive information
Use SSL to encrypt sensitive data between transfer from client to server. SSL hits server performace, so you might consider using SSL only for few pages which transfer sensitive data to and fro.Plugin ssl_requirement
http://svn.rubyonrails.org/rails/plugins/ssl_requirement/README Mongrel, rails, apache and SSL
http://blog.innerewut.de/2006/06/21/mongrel-and-rails-behind-apache-2-2-and-ssl Controller in SSL subdomain
http://www.railsonwave.com/railsonwave/2007/7/10/howto-put-a-controller-under-a-ssl-subdomain Sample SSL code in rails
Be very careful when you allow your users to upload files and make them available for other users to download.Description
http://www.rorsecurity.info/2007/03/27/working-with-files-in-rails/ Must read - Section 26.7 of Agile web development with rails - 2nd edition
http://www.pragmaticprogrammer.com/titles/rails2/ In place file upload
http://kpumuk.info/ruby-on-rails/in-place-file-upload-with-ruby-on-rails/ 3 plugins for file upload reviewed at :
Secure your setup / environment
Proper Mysql configuration
Use good passwords
Security plugins directory
http://agilewebdevelopment.com/plugins/category/1http://www.railslodge.com/pluginshttp://railsify.com/categories/security-production Note : I will keep this security guide updated. Any additions/improvements are welcome.