Skip to content

Instantly share code, notes, and snippets.

@slothelle
Created June 27, 2013 18:23
Show Gist options
  • Save slothelle/5878997 to your computer and use it in GitHub Desktop.
Save slothelle/5878997 to your computer and use it in GitHub Desktop.

Web Security

This post outlines three common web security vulnerabilities with specific examples in Rails. For a more complete list, I highly recommend the OWASP Rails security cheatsheet.

Cross-Site Scripting (XSS)

A cross-site scripting attack is when malicious scripts are injected into a web site in order to compromise it.

For example, let's say we want to allow html tags such as <strong> in our blog comments, so we render raw output using the Rails method #html_safe:

<%= comment.body.html_safe %>

Unfortunately, any time we perform a raw output of user submitted data, we expose a XSS vulnerability -- if someone had submitted a comment with body <script>alert('youve been hacked!')</sript>, the saved script would be shown and executed anytime someone visited the page.

To prevent XSS, we need to ensure that HTML content is encoded. While we could whitelist specific tags that we want to allow, it's safer to disallow HTML altogether and use a different markup language for rich text formatting like markdown.

Additional Resources:

SQL Injection (SQLI)

A SQL injection attack consists of insertion or "injection" of a SQL query via the input data from the client.

To dive into an example, let's suppose we had a search form which submitted to the following controller action:

def search
  @posts= Post.find(:all, :conditions => "title LIKE '%#{params[:query]}%'")
end

A user could submit '); DELETE FROM posts -- in the search form, which would result in the following query:

=> SELECT "posts".* FROM "posts" WHERE (title LIKE '%'); DELETE FROM posts --%')

This deletes all records from the posts table!

To prevent this, we need to ensure that the user input is escaped before being interpolated in the SQL statement by using an array condition instead of a pure string:

def search
  @posts= Post.find(:all, :conditions => ["title LIKE ?", "%#{params[:query]}%"])
end

Using this ActiveRecord idiom ensures that the user input is escaped, which produces the following SQL:

SELECT "posts".* FROM "posts" WHERE (title LIKE '%\'\'); DELETE FROM posts --%')

Notice how escaping the quotes prevents the malicious SQL from being executed as its own statement. Phew, we're safe!

Additional Resources:

Cross-Site Request Forgery (CSRF)

Cross-Site Request Forgery (CSRF) is an attack that tricks the victim into loading a page that contains a malicious request. It is malicious in the sense that it inherits the identity and privileges of the victim to perform an undesired function on the victim's behalf eg. changing the victim's e-mail address, password, or purchasing something.

For example, imagine you and I are Facebook chatting and I send you a link to a webpage containing the following form:

<form action="http://facebook.com/delete_my_account" method="post">
  <input type="submit" value="Click here to see what I sent you!">
</form>

You innocently click the button, which means your browser will send a POST request to Facebook and delete your account (hypothetically). This is a CSRF attack.

In reality, this wouldn't work because Facebook protects against CSRF. You prevent CSRF by ensuring that requests originate from verified sources.

A common way to ensure this is to have a token in the user session that is inserted as a hidden input in forms and then verified on the server when a request is received.

You can observe Rails doing this by examining the source code of any form generated using a form helper and method POST. You'll find a security token:

<input name="authenticity_token" type="hidden" value="MmjlKCXtUjL1lzB4IX/Dx9uNACKg9zMMCU" />

Rails checks the authenticity token against the token stored in the user session to verify requests. It's important to note that Rails does not perform such a check GET requests, and that GET requests should never be used for actions which alter data.

Additional Resources:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment