Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rails 4 Application Security

Rails 4 Application Security

Slides from my O'Reilly Webcast.


Anthony Lewis

November 12, 2014

More Decks by Anthony Lewis

Other Decks in Programming


  1. Ruby on Rails 4 Application Security Anthony Lewis

  2. Overview • Authorization Attacks • Injection Attacks • SQL Injection

    • Cross-Site Scripting • Cross-Site Request Forgery Attacks • Mass Assignment Attacks
  3. Examples • The examples in this presentation are based on

    a simple social network application • Users sign up for accounts and create posts • Assume User and Post models • A user has many posts • A post belongs to a user
  4. Authorization Attacks Authentication is not authorization

  5. Definitions • Authentication identifies a user • Authorization specifies what

    a logged-in user can access within your application
  6. Authorization Attack • This attack is sometimes called an Insecure

    Direct Object Reference • In other words, a user might change the URL from posts/1 to posts/2 and try to edit another user’s post
  7. Example # This method lets any logged-in # user update

    any post. def update @post = Post.find(params[:id]) # ... end
  8. Example # This method ensures that a user # can

    only update their own post def update @post = current_user.posts.find(params[:id]) # ... end
  9. Injection Attacks Never trust the user

  10. Injection Attacks • An injection attack occurs when user input

    is executed as part of the application • Injection attacks are extremely common, especially in older applications • The first rule of avoiding injection attacks is never trust input from the user
  11. SQL Injection The most common attack

  12. SQL Injection # Never trust user input class User def

    self.authenticate(username, password) where("username = '#{username}'" + " AND password = '#{password}'").first end end
  13. So Far, So Good User.authenticate("tony", "secret") SELECT * FROM users

    WHERE (username = 'tony' AND password = 'secret') LIMIT 1 => #<User id: 1, username: ...>
  14. So Far, So Good User.authenticate("tony", "wrong") SELECT * FROM users

    WHERE (username = 'tony' AND password = 'wrong') LIMIT 1 => nil
  15. Magic Words • Attackers know a magic phrase for exploiting

    SQL Injection vulnerabilities. • What if we enter this for the password? ' OR '1' = '1
  16. Uh Oh User.authenticate("tony", "' OR '1' = '1") SELECT *

    FROM users WHERE (username = 'tony' AND password = '' OR '1' = '1') LIMIT 1 => #<User id: 1, username: ...>
  17. What Happened? • My password isn’t an empty string, but

    the addition of OR '1' = '1' made the expression true • The attacker is now logged in as me
  18. Solution # Switch to hash conditions class User def self.authenticate(username,

    password) where(username: username, password: password).first end end
  19. Solution • Rails automatically SQL escapes strings in hash conditions

    • If you see string interpolation inside a where method, assume it is dangerous
  20. Cross-Site Scripting Also known as XSS

  21. Cross-Site Scripting • A vulnerability that allows attackers to inject

    client- side JavaScript into web pages viewed by others • When another user views the page, the JavaScript is executed as if it were part of your application
  22. Safe By Default • Thankfully, Rails HTML escapes all output

    by default • Symbols such as < are replaced with character entities such as &lt; • But what if your application needs to show HTML output?
  23. Example # Create a new post with # JavaScript in

    the body Post.create( title: "XSS Test", body: "<script>alert('XSS');</script>" )
  24. Example # This view code... <%= @post.body %> # Becomes

    this HTML... &lt;script&gt;alert('XSS');&lt;/script&gt; # This will not execute
  25. Safe By Default • But what if your application needs

    to show HTML output? • Users want to use HTML to format their posts
  26. Example # This view code... <%= raw @post.body %> #

    Becomes this HTML... <script>alert('XSS');</script> # This WILL execute
  27. Remove Unsafe Tags • Rails includes the sanitize method to

    automatically remove unsafe HTML tags • The sanitize method uses a whitelist of allowed tags to clean up potentially unsafe strings • In Rails 4.2, sanitize is based on the Loofah gem
  28. Example # Use helper.sanitize in a console helper.sanitize "<p>Hello</p>" =>

    "<p>Hello</p>" # pass a list of allowed tags tags = ['em', 'strong'] helper.sanitize "<p>Hello</p>", tags: tags => "Hello"
  29. Example # This view code... <%= sanitize @post.body %> #

    Becomes an empty string... # Obviously, this will not execute
  30. Cross-Site Request Forgery Also known as CSRF

  31. CSRF Attacks • Occurs when one of your application’s users

    visits another site that has been modified by an attacker to target your site • The attacker must trick your application’s users into visiting the malicious page and activating the link • The malicious page uses your application’s trust in this user to accept requests
  32. Example • Imagine you are building an online payment application

    • Your application includes a transfer action that accepts amount and to parameters that specify how much money to transfer to another user • An attacker studies the requests generated by your site and attempts to replicate those requests on his own site
  33. Example <!-- an image tag on the attacker’s site causes

    a GET request --> <img src="http://yoursite.com/transfer? amount=100&to=attacker">
  34. Example • If one of your users visits this site,

    and your site is vulnerable to CSRF attacks, $100 is transferred from their account to the attackers account • This could also be done with a script on the attacker’s site that issues requests
  35. CSRF Prevention • Never use a GET request to change

    state • Use a POST request to update data • Include a user-specific token with all requests that change state in your application • Ignore requests that do not include this token
  36. CSRF Prevention • Rails includes helper methods for generating a

    user-specific token automatically • Rails calls this an authenticity_token • The token is stored in a meta tag on each page • The token is also included in a hidden field on every form
  37. CSRF Prevention # Your application layout includes # a per-user

    token by default... <%= csrf_meta_tags %> # That renders this HTML <meta content="authenticity_token" name="csrf-param" /> <meta content="KA1Q/JoVfI+aV6/L4..." name="csrf-token" />
  38. CSRF Prevention # Your application controller raises # an exception

    if the token is not # included with a POST request... protect_from_forgery with: :exception
  39. Mass Assignment Attacks Protect your attributes

  40. Mass Assignment • Model methods such as update_attributes and new

    accept a hash of attributes and update or set all attributes by default • Older Rails versions used the attr_accessible model method to define attributes that could be mass assigned • Rails 4 uses the Strong Parameters gem to move this responsibility to the controller
  41. Example • An attacker can modify your application’s forms or

    use a tool such as cURL to send parameters you aren’t expecting • For example, the attacker might try sending admin=true to your user signup form
  42. Example # The params variable in your # controller now

    looks like this: params = { user: { name: "Tony", admin: true } }
  43. Example # In older Rails versions this assigns # all

    attributes unless attr_accessible # is setup on the User model @user = User.new(params[:user]) # Assuming your User model has an admin # flag, the new user is now an admin
  44. Example # In Rails 4 this raises an exception #

    because it is a mass assignment # without a call to permit @user = User.new(params[:user]) # The new user is not created
  45. Example # The preferred pattern is to call # a

    private user_params method that # uses the permit and require methods # to setup allowed params @user = User.new(user_params)
  46. Example private def user_params params.require(:user).permit(:name, :email) end # this method

    returns this hash: # { name: "Tony" } # the admin flag is silently removed
  47. Summary • As your application gains popularity, the risk of

    attack rises • Rails provides the tools you need to protect your application and your users from attacks • Stay up-to-date on security issues
  48. Resources • The examples in this presentation are based on

    Chapter 11 of my book Rails Crash Course • The security vulnerabilities were taken from the OWASP Top 10 List • The Open Web App Security Project • www.owasp.org
  49. Thank you!