XSS and Rails

XSS stands for Cross-site scripting. However it has nothing to do with cross-site. It has everything to do with your site.

XSS is consistently a top web application security risk as per The Open Web Application Security Project (OWASP) .

XSS vulnerability allows hacker to execute JavaScript code.

Your site has a form. I enter <script>alert(document.cookie)</script> and I hit submit. If I see an alert then it means I can execute JavaScript code on your site and your site has XSS vulnerability.

If a hacker can execute JavaScript code then the hacker can see your cookie.

If you are logged into your application then your application sets a cookie. That is how your application knows that you are logged in.

If a hacker can see your cookie then the hacker can log in.

By the way having SSL does not protect the site from XSS vulnerability.


An easy way to prevent XSS is to not to allow users to execute JavaScript code. This is the reason why when you go to post comment many sites have messages similar to this one.

limited html example

Some sites allow some html code and other do not allow any html code at all.

It is possible for the hacker to insert JavaScript code in your system. For example if database stores <script>alert(document.cookie)</script> then JavaScript code has come inside the application. However as long as you deny the opportunity for that code to be executed in browser you are safe.

You can also take precaution and sanitize all user input so that JavaScript code does not comes into the system at all.

The right approach depends on your need and the application framework you are working with.

A practical example

It is very commont to display address in a formatted way. Usually the code is something like this

address_array = [name, address1, address2, city_state_zip, country_name].compact
address_array.join('<br />')

Since here the address is being separated by an html tag <br />. When developer looks at the html page he/she sees the <br /> tag literally on the screen so the developer comes back to code and marks the string as html_safe.

address_array = [name, address1, address2, city_state_zip, country_name].compact
address_array.join('<br />').html_safe

Now the browser renders the address with proper <br /> tag and the address looks nicely formatted. The developer moves on.

However notice that developer has marked user input data like address1 as html_safe and as I discussed earlier this is exposing your site to XSS attack.

Here is how it should be fixed without exposing any security issue.

address_array = [name, address1, address2, city_state_zip, country_name].compact
address_array.map{ |i| html_escape(i) }.join('<br />').html_safe

Notice that user input elements are being subjected to html_escape before they are marked as html_safe.

What tools Rails provides

In the earlier version of Rails we were encouraged to use <%= h post.comment %> in views. Here h is a short name for html_escape. In Rails 3.x the content is automatically escaped. It means if the hacker enters <script>alert(document.cookie)</script> then after html_escape has performed its operation the browser sees "&lt;script&gt;alert(document.cookie)&lt;/script&gt;". In this way the user does not get to see the alert message which is a good thing. It means users cannot execute JavaScript code on your site and your site is XSS safe.

If you do want to format the text a little bit then you can use simple_format . If user enters a bunch of text in text area then simple_format can help make the text look pretty without compromising security. It will strip away <script> and security sensitive tags. html_escape internally uses sanitize method. Checkout that method to see what options you can pass. Think before you act because you might be opening a security vulnerability.

Also be careful with raw method. It will output without escaping the string.

In case of Json you need to handle escaping yourself

Note that when user entered <script>alert(document.cookie)</script> in the textarea then database stored the value as <script>alert(document.cookie)</script> . No escaping is done before storing the value in the database. It is the ERB that does the escaping and ensures that site is protected.

All is well and after a few months boss comes and asks to make that page ajaxy. Now data is sent to browser in JSON format.

Now Controller looks like format.json { render json: @user }.

This will produce JSON structure like this "{\"about\":\"<script>alert(document.cookie)</script>\"}".

On the client side you have code to display the content. $('body').append(data.about). Well when the about content is added to dom the script will be executed and now your site is vulnerable to XSS.

You would think that using json_escape should solve the problem. However json_escape produces invalid JSON. Yes that is right. The output of json_escape is invalid JSON. There is an open pull request to take care of that issue.

The point is that if you are passing JSON data to be displayed on the browser then , by default, you do not have the escape protection that ERB provides.

No spam. Delivered around once a month.