Preventing security issues in Rails

Security is a major concern for any developer aspiring for successful and sustainable development of web applications. Every developer wants to code in such a manner that their applications are as secure as possible from any attacks, however, no code can be 100% bug-free or secured. So, the developers are aware that they need to do their best to make their applications with minimum vulnerability to attacks. Detecting vulnerabilities is easy but security breaches and hacks might result in losses. This is the reason why it is always better to check for security issues right from the start of the application development process along with conducting regular quality checks to keep things on track.

1] Sessions

A good place to start evaluating the security is with the sessions, which can be vulnerable to certain attacks.

session[:user_id] = @current_user.id
User.find(session[:user_id])

– By default, Ruby on Rails uses a Cookie-based session store. This implies that unless something is changed, the session will not expire on the server. So, it means that we should never keep sensitive data such as passwords and IDs etc in sessions.
– The best practice therefore, is to work with a database based session, which is very easy with Rails –

Project::Application.config.session_store :active_record_store
Session ID is a 32-character random hexadecimal string.

The session ID is generated using SecureRandom.hex which generates a random hexadecimal string using any of the platform-specific methods such as OpenSSL, /dev/urandom or Win32, for generating cryptographically secure random numbers. Currently, it is not possible to brute-force i.e trial and error attack on login credentials in Rails’ session Ids.

Here are some of the common session based attacks:
Session Hijacking:- This allows the attackers to steal a user’s session ID and use the web application in the victim’s name.
Session Fixation:- Apart from stealing a user’s session ID, the attacker is also capable of fixing a session ID known to them. This is called as session fixation.
Session Expiry:- The attackers attempt to also increase the time-frame of the attack with sessions that never expire. The attacks such as cross-site request forgery (CSRF), session hijacking and session fixation are the examples.

2] Command Injection

An application becomes vulnerable to command injection, in case the attacker is able to influence the command line parameters or the Unix commands as a whole. However, since running the UNIX commands in Rails is not common, these attacks are less likely to take place.
On the other hand, vulnerabilities may arise in a background process that making direct use of the Unix commands for the customer data.

Here are some of the common Rails command line methods:
%x[…]
system()
exec()
`…`
It should also be noted that there are more than one ways how to chain commands together, but that also depends on the hosting operating system. Examples: “&”, “&&”, “|”, “||” etc.
Secured environment variables while running commands
The processes that are run by your rails applications get the environment variables of the parent processes which may comprise of the API keys etc.

3] SQL  Injection

SQL injection happens when a user is able to manipulate a value which is used unsafely inside an SQL query. This can result in data loss, data leaks, elevated privilege among the other undesired outcomes.

SQL injection is very easy and common attack which usually occurs and its impact can be very severe depends on the website and the situation it occurs.

As developers we should take care of all those possibilities where SQL injection can occur and should handle the same accordingly.

This is what SQL Injection looks like:

Employee.all(:conditions => "designation = #{params[:designation]}")

Above code is vulnerable to SQL injection , following code will prevent from SQL injection.

Employee.all(:conditions => ['designation = ?', params[:designation]])

OR

Employee.all(:conditions => {:designation => params[:designation]})
Counter-measures against SQL Injection in Rails

Testing every statement for SQL injection can be a tedious job but we should take some countermeasures like static code scanner like brakeman and you can write some unit test cases.
a)General rule:– Never use params in string inflection (#{}) like so
Eg

User.where("name = '#{params[:name]}'")

b)Watch out that params may also be an array, for example:

params[:user] if you add ?user[]=1 to the URL. User.exists? params[:user] will then run the query SELECT 1 AS one FROM “users” WHERE (1) LIMIT 1.

4] Cross-site Scripting (XSS)

With the help of XSS, an attacker gets enabled to execute scripts in the security context of your web application.

Consider this Rails view snippet: <%= @flat.title %>. If the flat’s title is edited along with adding the HTML, this Rails view renders that HTML in the application’s security context. Thus, the browser would run the HTML, which is XSS.

In fact, this doesn’t work in Rails these days yet, in Rails version 2 you’d be required to escape every single user input: <%= h(@flat.title) %>
Nowadays, rails comes with a flag on each string which marks it as HTML whether safe or not: @flat.title.html_safe?. In case it is not safe ( for example from a parameter, from the database, …), it will get automatically escaped while using it in this way: <%= @flat.title %>
In Rails 3.0 protection against XSS is a default behavior.

Counter-measures

a) A Content Security Policy(CSP) strategy

A Content Security Policy is basically in the form of an HTTP header and this makes a declaration of the rules about what all sources are allowed for all kinds of assets. As a consequence of following these rules, all else is disallowed. Once implemented appropriately, it is capable of wiping out all the Cross-Site-Scripting (XSS) vulnerabilities in your app.

b) HTML-Safe,ActiveSupport::SafeBuffer

The ActiveSupport::SafeBuffer module was introduced by Rails 3 to add an HTML-safe flag to strings. By default, it is false, especially, when the string has an external source such as the database or the params. The flag is returned with “string”.html_safe?.

The HTML-escape method h(), escapes the string marking a string as HTML-safe.

h("html>").html_safe? #=> true
("html>").html_safe? #=>false

c) OWASP (Open Web Application Security Project) XSS Prevention

For the prevention of XSS, all the untrusted data needs to be denied and restricted from being put directly into the HTML or any other context (like JavaScript, CSS, attribute contexts).

d) XSS protection in HAML templets

While using the Haml templates, instead of ERB, strings are automatically escaped in the same way as in ERB templates. And in the same way as it is with the ERB templates, HTML-safe strings (string.html_safe? returns true) do not get skipped automatically. The != notation in Haml works the way <%= raw(…) %> works in ERB, so, it renders the unescaped version.
By default,

="emphasized"
!= "emphasized"

compiles to:

<em>emphasized</em>
emphasized

So care should be taken while using != in Haml and it should be made sure that no user data is rendered unescaped.
Following are some preventive measures which can be taken care of while developing rails application.

1] Authentication

Use Device or Authlogic gem.
– To enable auth please dont forget to add ->

class ProjectController < ApplicationController
before_filter :authenticate_user
– By default Devise requires only  6 characters for a password. The minimum can be changed in: /config/initializers/devise.rb
config.password_length = 8..128
– You can change the password complexity by adding the following code in user model.

validate :password_complexity
def password_complexity
if password.present? and not password.match(/\A(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+\z/)
errors.add :password, "must include at least one lowercase letter, one uppercase letter, and one digit"
end
end
2] Insecure Direct Object Reference or Forceful Browsing

– Ruby on Rails apps make use of a restful URL structure making the paths used mostly guessable and intuitive. So, in order to protect against a user trying to access or modify data that belongs to another user, the actions need to be specifically controlled. There is no such built-in kind of a protection out of t he gate on a vanilla Rails application. Further, it can be performed manually at the controller level.
– Use cancancan or pandit for access control

3] Mass Assignment and Strong Parameters
- class Project < ActiveRecord::Base
attr_accessible :name, :admin
end

According to the example above, with the admin attribute accessible, the following could work:
– curl -d “project[name]=triage&project[admin]=1” host:port/projects
– config.active_record.whitelist_attributes = true

4] Redirects and Forwards

– It is advisable to avoid using the redirects that use parameters
For eg:- //www.example.com/redirect?url=//www.example_commerce_site.com/checkout
– restrictive protection is to use the :only_path

begin
if path = URI.parse(params[:url]).path
redirect_to path
end
rescue URI::InvalidURIError
redirect_to '/'
end

– Have hash of approved sites and allow only them to get redirected.

5] Dynamic Render Paths

– Care should be taken when you are dynamically rendering any view based on some condition. It might result in loading admin view.

6] Cross Origin Resource Sharing

– Like file upload.
– The receiving site should restrict and allow only whitelisted domains and make sure that requests are also coming from those domains only.
– Also set the Access-Control-Allow-Origin header in both the response to the OPTIONS request and POST request. This is because the OPTIONS request is sent first, in order to determine if the remote or receiving site allows the requesting domain.
– A POST request, is sent. Once again, the header must be set in order for the transaction to be shown as successful.

7] Business Logic Bugs

– The applications regardless of the technology they are based on, can comprise of business logic errors that are prone to lead to security bugs. It can be really tricky to detect such security bugs using the automated tools. The practices such as regular reviews of the codes, pair programming and writing unit tests can help you best avoid such security bugs to arise.

8] Sensitive Files

Following are some files which we should take care of while developing a web application.
/config/database.yml- May contain production credentials.
/config/initializers/secret_token.rb – Contains a secret used to hash session cookie.
/db/seeds.rb – May contain seed data including bootstrap admin user.
/db/development.sqlite3 – May contain real data.

9] Encryption

Ruby on Rails uses OS encryption. You should almost never write your own solutions for encryption.
Updating Rails and Having a Process for Updating Dependencies.

Tools to detect security issues in rails application

  • Brakeman
  • bundler-audit
  • Codesake::Dawn
  • Rack::Attack
  • Tarantula
  • Hakiri Toolbelt

Subscribe For Latest Updates

Related Posts

Leave a Comment

Your email address will not be published. Required fields are marked *

en_USEnglish