Rails Quiz: XSS Edition
Cross-site scripting (XSS) is a type of computer security vulnerability that enables an attacker to inject code into a web page. When a user later visits that web page the code is executed in that user’s browser. The attacker can then steal the user’s session cookie and log into the site with that user’s account. Think you know all about XSS? Test your knowledge with this mini-quiz!
Question 1
Which of the following examples are secure from XSS attacks?
-
<%= @user.comment %>
-
<%= html_escape @user.comment %>
-
<%= sanitize @user.comment %>
-
<%= raw @user.comment %>
-
<%= @user.comment.html_safe %>
Got it?
You sure?
Ok, answer:
The first three options are secure.
Rails 3 added XSS protection by default which means that all strings passed into <%= %>
are automatically escaped.
Option 2 unnecessarily escapes the comment twice.
Option 3 uses sanitize
to strip all HTML tags and attributes that aren’t whitelisted, and the result is escaped afterwards.
The last two options use raw
and html_safe
to mark the comment as safe so that it is not escaped.
This means they’re vulnerable to XSS attacks.
Question 2
We want to create the following view helper:
module ApplicationHelper
def strong(content)
# Render content inside a `strong` tag
end
end
To be later used in a view like this:
<%= strong(@user.name) %>
Which of the following implementations render the strong tag and are secure from XSS attacks?
-
content_tag(:strong, content)
-
"<strong>#{html_escape content}</strong>"
-
"<strong>#{content}</strong>".html_safe
-
raw("<strong>#{content}</strong>")
Done?
You certain?
Ok, answer:
Only option 1 is correct. content_tag
(as well as tag
) escapes the content but does not escape the strong
tag.
Option 2 escapes the content with html_escape
.
However, as we saw in the first question, Rails automatically escapes all strings so the strong
tag is then also escaped.
The last two options correctly mark the string as safe so that the strong
tag is not escaped. However, they do not escape the content with html_escape
. This means they’re vulnerable to XSS attacks.
Final question
An often overlooked XSS attack vector is the href
value of an a
tag.
If it starts with javascript:
or data:
it is executed when the link is clicked.
Which of the following examples are secure from XSS attacks?
-
<a href='<%= @user.website %>'>Personal Website</a>
-
<%= link_to 'Personal Website', @user.website %>
-
<%= link_to 'Personal Website', sanitize(@user.website) %>
-
<%= sanitize link_to 'Personal Website', @user.website %>
Finished?
No doubts?
Ok, answer:
Only the last option is secure.
The tricky part of this question is that sanitize
works with HTML — not with URLs.
This means that you should sanitize
the whole a
tag instead of just the href
value.
And that’s it!
Conclusions
-
Rails protects you when rendering user input with
<%= %>
… -
Unless you use
raw
orhtml_safe
to render HTML. In that case usehtml_escape
(or its handy aliash
) to escape user input. -
Rails does not protect you when passing user input to the URL part of
link_to
. In that case usesanitize
to clean thea
tag.
To detect these types of vulnerabilities and more I recommend using brakeman, the static analysis security vulnerability scanner for Ruby on Rails applications.