ActionPack: Security

The Rails 2.0 Preview Release is available now, which is great news. The announcement includes a paragraph on security:

  • "we now ship we a built-in mechanism for dealing with CRSF attacks", yes it works fine
  • "The old TextHelper#sanitize method has gone from a black list (very hard to keep secure) approach to a white list approach." Very good news. This is in fact the white_list plugin which has been merged. A test with my private XSS list worked fine. It even has an easier way to allow tags directly in the method:
    sanitize @article.body, :tags => %w(table tr td), :attributes => %w(id class style)
  • "Finally, we’ve added support for HTTP only cookies. They are not yet supported by all browsers, but you can use them where they are." Http only cookies can be used from IE v6.SP1 and recently Firefox v2.0.0.5. Http only cookies cannot be accessed by document.cookie anymore. However, you have to keep in mind that there are other ways to get the cookie. But still, it shuts down the most obvious way of getting at the cookies.

Plugins merged and Ruby’s Net::HTTPS

Good news: The csrf_killer plugin has been merged by Rick for Rails 2.0, so it is available in the current trunk. Go here for the changeset, and here for some documentation.

Furthermore, the insecure text helper methods strip_links, strip_tags and sanitize have been updated, mostly to strip nested tags. Still, I don't recommend using them, as new tickets (same applies for strip_tags) are coming in for this fresh change.

And for those of you using the Ruby Net::HTTP and Net::HTTPS libraries, here is a security vulnerability in it (it's for Ruby, not Rails):

  • A vulnerability results from the Net::HTTPS library failing to validate the name on the SSL certificate against the DNS name requested by the user. By not validating the name, the library allows an attacker to present a cryptographically valid certificate with an invalid CN.

Update: There's a post on the official Ruby site now.

Ruby on Rails Security Cheatsheet

I’m back from the Rails Conference Europe in Berlin. I realize that a 45 minute talk is hardly enough to tell everything which is important to say about Rails security. Moreover, you will never get the level right in a talk about security (or generally): There are Rails newbies, everyday-programmers and even security experts.

Anyway, I was referring to this web site quite often as I wanted to provide further reading about more advanced security problems in Rails and their countermeasures. Therefore, I created a Rails security cheatsheet with all the information in one place.

Go to the Ruby on Rails Security cheatsheet.

PS: My slides will be available here.
PS 2: You can find the links to the plugins I mentioned in the blogroll on the => :right.

OpenID security issues

As many Rails projects use the OpenID service to authenticate its users, I want to bring some of its security issues to your attention which were announced recently. Gareth Heyes found a cross-site request forgery attack vector with MyOpenID, one of the bigger OpenID providers. MyOpenID reacted promptly, but other providers have the same problem. Here's what he writes:

When developing a OpenID system is very important to include form tokens in order to prevent CSRF attacks. The MyOpenID.com site had included form tokens but the token was stored in the URL of the site.

A more general article about OpenID security issues can be found on GNUCITIZEN.

RedCloth security thoughts

Often times RedCloth is used to prevent Cross Site Scripting, because it uses a markup other than HTML to format text. “RedCloth is a module for using Textile in Ruby. Textile is a text format. A very simple text format. Another stab at making readable text that can be converted to HTML.” For example *a phrase* becomes a phrase in RedCloth. However, there are a few things you have to know:

Note: the original attributes href and src were replaced by the blog software with xhref and xsrc in the following.

Using RedCloth without any options is still vulnerable to XSS:

>> RedCloth.new(‘<script>alert(1)</script>’).to_html
=> “<script>alert(1)</script>”

Use the :filter_html option to remove or escape HTML which wasn’t created by the Textile processor:

>> RedCloth.new(‘<script>alert(1)</script>’, [:filter_html]).to_html
=> “alert(1)”

However, this does not filter all HTML, a few tags will be left, for example <a>:

>> RedCloth.new(“<a xhref=’javascript:alert(1)’>hello</a>”, [:filter_html]).to_html=> “<p><a _href=\”javascript:alert(1)\”>hello</a></p>”

According to the source code, the image tag (<img xsrc=””>) is allowed, as well, which should allow attacks like these:

<IMG xsrc=javascript:alert(‘XSS’)> 

However, my setup (version 3.0.4) gives me errors when passing image tags. I recommend to use a combination of RedCloth and the good old white_list filter, as in:

>> RedCloth.new(‘”ha”:javascript:alert(1);’).to_html
=> “<p><a xhref=\”javascript:alert(1);\”>ha</a></p>”

>> white_list(RedCloth.new(‘”ha”:javascript:alert(1);’).to_html)
=> “<p><a>ha</a></p>”

As you can see, the Textile syntax allows you to create JavaScript links, as well. And if you think a JavaScript link looks suspicious to the users you can hide links in the data: protocol, as in Thou art so tolerant.

Another attack vector could be built with the Textile ability to include CSS. As described earlier, an attacker may deface your site and display his own elements (links, buttons, maybe login forms) on top of your original ones and lure the victim on one of his pages:

>> RedCloth.new(‘p{position:absolute; top:50px; left:10px; width:150px; height:150px}. Spacey blue’).to_html
=> “<p style=\”position:absolute; top:50px; left:10px; width:150px; height:150px;\”>Spacey blue</p>”

>> RedCloth.new(‘p{position:absolute; top:50px; left:10px; width:150px; height:150px}. No spacey blue’, [:filter_styles]).to_html
=> “<p>No spacey blue</p>”

So a good combination of RedCloth and the WhiteListHelper should be a secure solution.

Don’t use strip_tags, strip_links and sanitize

Update: This is about earlier releases, Rails 2.0 provides a new sanitize method which uses a white list. Also, strip_tags and strip_links have been updated, the attack vectors below do not work anymore.
 
Rails includes several insecure text helpers, especially strip_tags, strip_links and sanitize. Do not rely on the these as they do not fulfill what the name promises. Here are two examples:
 
Note: the original attributes href and src were replaced by the blog software with xhref and xsrc in the following.

>> strip_tags("sdfasdf<<b>script>alert('hello')<</b>/script>")
=> "sdfasdf<script>alert('hello')</script>"

>> strip_links("<a xhref='http://www.holy-angel.com/'><a xhref='http://www.attacker.com/'>Test</a></a>")
=> "<a xhref='http://www.attacker.com/'>Test</a>"

I've posted a bug ticket at http://dev.rubyonrails.org/ticket/8864 which was followed by http://dev.rubyonrails.org/ticket/8877, but it won't be fixed until Rails 2.0, so I recommend to use Rick's white_list plugin to remove all but some safe tags.

Thou art so tolerant

Web browsers are quite helpful: If you are a web-designer and you don't produce (X)HTML compliant pages, they will be rendered correctly anyway, because they quite fault-tolerant. But there are some features in some browsers that are questionable, here are some advanced examples:

  • Even though this file has a strange extension, IE will interpret the JavaScript inside: http://kleinerfeigling.kl.ohost.de/hubi.istdick
  • IE guesses the protocol you wanted to use, so try to enter this link: somescript:alert("hi");
    See here for more examples of that. It seems that a simple link to this doesn't work, but with a few tricks you can execute it:
    <a ONclicK=` ;; morescript:alert(String.fromCharCode(88,83,83))` xhref='#'>TEST</a>
  • The last example actually contains another trick to hide malicious code: the onclick event is used with backticks `
  • Do you know the data protocol of Firefox, you can hide JavaScript in it, you can even base64 encode it, try this link: data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K

Older tricks can be found in the XSS Cheat Sheet

sanitize() and blacklists

This is Rails' sanitize method:

sanitize(html)
Sanitizes the html by converting <form> and <script> tags into regular text, and removing all "onxxx" attributes (so that arbitrary Javascript cannot be executed). It also removes xhref= and xsrc= attributes that start with "javascript:".

This is a blacklist method which removes potential harmful JavaScript. As I said before, blacklist filter are never complete and filter only the most basic cross-site scripting attacks, there will always be special code which works fine in some browsers, even though you have used a filter. Examples are here, here and here (list != infinite). Here are some other examples that pass through sanitize and execute in IE (mostly v6) or Firefox:

  • <IMG _src="javascript:alert(String.fromCharCode(88,83,83));">
  • <DIV STYLE="background-image: url(javascript:alert(1))">
  • <div style="width: expression(alert(1))">hello</div>
  • <INPUT TYPE="IMAGE" _src="javascript:alert(1);">

I will not post these examples as a ticket, because I think fixing a blacklist is rather useless. As DHH said in one of the tickets, sanitize in that form is kind of deprecated, a whitelist filter is definitely better. I recommend not to use sanitize until it is being converted to a whitelist filter.

This is RSnake's famous XSS Cheat Sheet.

Everything You Always Wanted to Know About Web Application Security – But Were Afraid to Ask

Here is an interesting general document about web application security, a list with frequently asked questions: http://www.owasp.org/index.php/OWASP_AppSec_FAQ

It gives good advice on how to design the login process. It describes a best practice for the "Lost Password" feature, which is especially important these days where there are an increasing number of attacks based on this feature. One thing I have to add in this context: You should not return a meaningful error message if the user name for the lost password existed. An attacker can use this to find valid user names, and did you know that a password cracker can check 30,000 passwords a minute over the Internet?

BTW, I'm glad that LoginSugar, the popular login system generator, has seen a security update after I published several security issues here. If you use it, please download the new version which is now also compatible with Rails 1.2.

Tour Dates

The Ruby On Rails Security Project is now also touring in real life, spreading the word of secure programming. I am doing a conference session for the two main upcoming Ruby On Rails events in Europe. The first one is in German on June, 22nd, the second in English on September, 19th:

I see you there!