The Ruby on Rails Security Project would like to help you make your Rails applications more secure. I'm Heiko Webers of bauland42 and I also do Rails security audits. You read the official Rails Security Guide? Great, so we know each other already, I wrote it. Contact me at 42 -the AT sign- bauland42.de or on Twitter.

Do you have a Rails security strategy?
Here's the new complete Rails guide to developing an overall security strategy. If you sign up today, I’ll give it to you for free.

Feeds / Syndication
Most Popular
This site is currently being updated to be more useful, enter your email to be notified


Automatic security

Security is not easy-to-use, not fancy and it is hard to remember all those nasty attack methods. So there are automatic security checks, firewalls, helpers and a lot more. They are built to make your application more secure. But automatic security tools can't help you to find logic faults. What if you have a Cross-Site Scripting scanner that checks each and every field in your web application, but with a little knowledge, an attacker could change one id in the URL and he sees his neighbor's confidential data.

BUT, automatic tools can be of great help, if you won't solely rely on them. The SafeErb plugin reminds you to sanitize output, but it doesn't do it automatically. A mass-assignment scanner might find this kind of security holes in you application. Or a web application firewall may protect holes you are not aware of. And, of course, security is a process and should be incorporated into the entire project life cycle.

That having said, I'd like to show you a nice web application firewall for your .htaccess, if you happen to use Apache. It comes from 0x000000.com, a whitehat hacker site, and it's the result of seven years of server administration. It is not perfect, it is not especially for Rails applications or for your specific application, but it is definitely a good starting point. You can read the tutorial for explanation.

RewriteEngine On
Options +FollowSymLinks
ServerSignature Off

RewriteCond %{THE_REQUEST}     ^.*(\\r|\\n|%0A|%0D).* [NC,OR]

RewriteCond %{HTTP_REFERER}    ^(.*)(<|>|'|%0A|%0D|%27|%3C|%3E|%00).* [NC,OR]
RewriteCond %{HTTP_COOKIE}     ^.*(<|>|'|%0A|%0D|%27|%3C|%3E|%00).* [NC,OR]
RewriteCond %{REQUEST_URI}     ^/(,|;|:|<|>|">|"<|/|\\\.\.\\).{0,9999}.* [NC,OR]

RewriteCond %{HTTP_USER_AGENT} ^$ [OR]
RewriteCond %{HTTP_USER_AGENT} ^(java|curl|wget).* [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^.*(winhttp|HTTrack|clshttp|archiver|loader|email|harvest|extract|grab|miner).* [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^.*(libwww-perl|curl|wget|python|nikto|scan).* [NC,OR]
RewriteCond %{HTTP_USER_AGENT} ^.*(<|>|'|%0A|%0D|%27|%3C|%3E|%00).* [NC,OR]

RewriteCond %{QUERY_STRING}    ^.*(;|<|>|'|"|\)|%0A|%0D|%22|%27|%3C|%3E|%00).*(/\*|union|select|insert|cast|set
|declare|drop|update|md5|benchmark).* [NC,OR]RewriteCond %{QUERY_STRING}    ^.*(localhost|loopback|127\.0\.0\.1).* [NC,OR]
RewriteCond %{QUERY_STRING}    ^.*\.[A-Za-z0-9].* [NC,OR]
RewriteCond %{QUERY_STRING}    ^.*(<|>|'|%0A|%0D|%27|%3C|%3E|%00).* [NC]

RewriteRule ^(.*)$ access_log.php


[Server] Did you update OpenSSL?

Two weeks ago, the Debian package of OpenSSL has been found to generate weak keys (CVE). Here's the news from Heise online:

Security expert Luciano Bello has now discovered a critical vulnerability in the OpenSSL package which makes the random number sequences, and therefore keys generated, predictable. The problem only affects Debian and distributions derived from it, such as Ubuntu and Knoppix. [...]

OpenSSL provides connection security for many important network services, such as the Apache web server, the SSH login service, the OpenVPN service, the Bind name server, S/MIME e-mail encryption and the trustworthiness of digital signatures. This could enable attackers to listen in on and manipulate SSL connections, obtain unauthorised access to SSH servers or poison DNS server caches.

As it is a serious security vulnerability, it is strongly advised to update your keys, especially for the SSH login service. Although the security advice is two weeks old already, there are still thousands of servers vulnerable. Heise Security found 5% of nearly 2,000 servers tested to use weak keys.


Real world CSRF: Update your Radiant now

Radiant is a no-fluff, open source content management system designed for small teams, written in Ruby on Rails.

I have found several security problems in Radiant, informed the vendor, who fortunately removed the (critical) vulnerabilities quickly. As an update is available, I'm now publishing information about the vulnerabilites.

CSRF in a real world application
About Cross Site Reference Forgery attacks I've written in a previous post. Here is an example of what you can do with it in a real world application: An attacker could add his own administrator users, change the current's administrator's user name and password, or create malicious pages in the content management system. Vulnerable is Radiant version 0.6.6 and most likely previous versions. Not vulnerable is version 0.6.7.

In this proof-of-context page, you have to enter the URL of your Radiant setup and click the link. If you you're still logged in to that site, i.e. your cookie didn't expire, a new administrator "cracker" with the password "cracker" will be added. Of course the attacker won't ask you about the URL, and there are many ways to obfuscate the attack.
Changing the password
To change the password of an account, the user doesn't have to enter the old password. As Radiant version 0.6.7 is not vulnerable to CSRF, the admin's password may not be changed by CSRF. However, if an attacker manages to use the application in the admin's name, he will be able to hijack the entire application by changing the admin's password and possibly the user name. The attacker may use the application if he managed to brute-force the admin's login credentials or if he got hold of the admin's cookie (by listening to network traffic, for example).
Although this is an attack with (hopefully) difficult preconditions, I prefer to take care of second level attacks, too. As a precondition, require to enter the old password when changing the password, and use good passwords.
Unsalted passwords
The user's passwords in the database are encrypted, but not salted. So if someone gets hold of a user entry in the database, he can brute-force the users password in the matter of minutes using rainbow tables. From version 0.6.7, passwords are salted.


Holes in the textile
At least the Textile filter is vulnerable to injection, try to inject this:

!http://www.google.com/intl/en_ALL/images/logo.gif(Bunny" onclick="alert('XSS'))!

You can find more details in this post about Textile security. This is how an attacker could introduce malicious content. Of course this would require that the attacker has access to the application. But, as mentioned before, I prefer to make sure less/nothing will happen, if someone got past the first barrier.

The countermeasure against this, is to use Rails' sanitize() method with the Textile output.


[WebAppSec] Automatic security and HackerSafe

Several people asked me about automatic assessment tools to check the security of an application stack. My opinion is that they may be a great support, but they cannot replace some manual work (oh, well, maybe). Rails test are a great way to make sure your application is safe, but you have to write them on your own. Security is not a plug-n-play product, but rather a process.

Automatic security
One automatic security scan is provided by McAfee. The HackerSafe certification is a service that detects vulnerabilities on web sites using automatic tools. If all tests pass, the site owner gets an HackerSafe logo, that he can put on his site. Over 80,000 sites, according to McAfee, use the HackerSafe logo to increase customer trust. According to the description, the service uses port scans, a vulnerability scan on the network layer, but also an automatic audit of the web application layer. On this layer, it looks for SQL Injection and Cross-Site Scripting (XSS) vulnerabilities. It is, however, not clear whether the service scans for other important attack methods, such as CSRF.

XSS and HackerSafe 
But, apparently, protection from XSS and other vulnerabilities is not a prerequisite for the HackerSafe logo. Russ McRee discovered several XSS holes in HackerSafe certified sites which allows the attacker to grab customer credentials or redirect the user to a malicious web site. He also made a video to demonstrate various XSS holes in five certified sites. Someone also found an SQL Injection vulnerability in a HackerSafe certified site. And I've seen at least one HackerSafe site which is vulnerable to CSRF. Although, maybe McAfee does not scan for CSRF, it is definitely an important attack method.
McAfee reacts 
A spokesperson for McAfee told British media that the company does not find XSS holes to be as critical as SQL Injection or other vulnerabilities. According to her, an XSS hole would not lead to revocation of the HackerSafe certification, although the company informs the customer about it. She added that XSS holes cannot be exploited to break into a server. No they cannot, but an attacker may steal the user's login credentials or credit card number, install malware on the client's computer or snitch his authentication cookie.
HackerSafe - just an image? 
After all, the HackerSafe certificate means that the site is protected against known attacks. It does, however, not mean that the site is not vulnerable to important attacks on the web application layer, which accounts for "an estimated 70% of all security breaches", according to the McAfee web site. And it does not mean that the site has no logic flaws, which gives an attacker (or another user) access to information he is not allowed to see. This can only be done by a manual security audit.


CSRF - An underestimated attack method

Cross Site Reference Forgery works by including malicious code or a link in a page that accesses a web application that the user is believed to have authenticated. If the session for that web application has not timed out, an attacker may execute unauthorized commands.

Most Rails applications use cookie-based sessions. Either they store the session id in the cookie and have a server-side session hash, or the entire session hash stays on the client-side. In either case the browser will automatically send along the cookie on every request to a domain, if he can find a cookie for that domain. The controversial point is, that it will also send the cookie, if the request comes from a site of a different domain. Let's start with an example:


  • Bob browses a message board and views a post from an attacker where there is a crafted HTML image element. The element references a command in Bob's banking application, rather than an image file (note that .src is meant to be src).

  • <img .src="http://www.bank.com/transfer?account=bob&amount=1000&destination=attacker">

  • Bob's session at www.bank.com is still alive, because he didn't log out a few minutes ago.

  • By viewing the post, the browser finds an image tag, which it tries to load from www.bank.com. As explained before, it will also send along the cookie with the valid session id.

  • The web application at www.bank.com verifies the user information in the corresponding session hash and transfers the money to the attackers account. It then returns a result page which is an unexpected result for the browser, so it will not display the image.

  • Bob doesn't notice the attack, only a few days later he finds out about the strange transfer.

It is important to notice that the actual crafted image or link doesn't necessarily has to be situated in the web application's domain, it can be anywhere – in a forum, blog post or email.



This figure is taken from shiflett.org and illustrates how CSRF works.


CSRF appears very rarely in CVE (Common Vulnerabilities and Exposures), less than 0.1% in 2006, but it really is a 'sleeping giant' [Grossman]. This is in stark contrast to the results in my (and others) security contract work – CSRF is an important security issue.



CSRF Countermeasures

First of all, GET and POST have to be used according to the W3C. Secondly, a security token in non-GET requests will protect your application from CSRF.

The HTTP protocol basically provides two main types of requests - GET and POST (and more, but they are not supported by most browsers). The World Wide Web Consortium (W3C) provides a checklist for choosing HTTP GET or POST:


Use GET if:

  • The interaction is more like a question (i.e., it is a safe operation such as a query, read operation, or lookup).

Use POST if:

  • The interaction is more like an order, or

  • The interaction changes the state of the resource in a way that the user would perceive (e.g., a subscription to a service), or

  • The user be held accountable for the results of the interaction.

The verify method in a controller can make sure that specific actions may not be used over GET. Here is an example to verify that the transfer action will be used over POST, otherwise it redirects to the list action.


verify :method => :post, :only => [ :transfer ], :redirect_to => { :action => :list }


With this precaution, the attack from above will not work, because the browser sends a GET request for images, which will not be accepted by the web application.

But this was only the first step, because POST requests can be send automatically, too. Here is an example for a link which displays harmless.com as destination in the browser's status bar. In fact it dynamically creates a new form that sends a POST request (.href is meant to be href).


<a .href="http://www.harmless.com/" onclick="var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = 'http://www.example.com/account/destroy'; f.submit();return false;">To the harmless survey</a>


Or the attacker places the code into the onmouseover event handler of an image (again, .src is meant to be src):


<img .src="http://www.harmless.com/img" width="400" height="400" onmouseover="..." />


There are many other possibilities, including Ajax to attack the victim in the background. The solution to this, is to include a security token in non-GET requests, which will be checked on the server-side. In Rails 2 this is a one-liner in the application controller:


protect_from_forgery :secret => "123456789012345678901234567890"


This will automatically include a security token, calculated of the current session and the server-side secret, in all forms and Ajax requests generated by Rails. You won't need the secret, if you use CookieStorage as session storage. It will raise an ActionController::InvalidAuthenticityToken error, if the security doesn't match what was expected.


Note that cross-site scripting (XSS) vulnerabilities bypass all CSRF protections. XSS gives the attacker access to all elements on a page, so he can read the CSRF security token from a form or directly submit the form.  This is how the Samy MySpace worm did it.