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
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
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
SQL Injection # Never trust user input class User def self.authenticate(username, password) where("username = '#{username}'" + " AND password = '#{password}'").first end end
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
Safe By Default • Thankfully, Rails HTML escapes all output by default • Symbols such as < are replaced with character entities such as < • But what if your application needs to show HTML output?
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
Example # Use helper.sanitize in a console helper.sanitize "Hello" => "Hello" # pass a list of allowed tags tags = ['em', 'strong'] helper.sanitize "Hello", tags: tags => "Hello"
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
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
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
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
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
CSRF Prevention # Your application layout includes # a per-user token by default... <%= csrf_meta_tags %> # That renders this HTML name="csrf-param" /> name="csrf-token" />
CSRF Prevention # Your application controller raises # an exception if the token is not # included with a POST request... protect_from_forgery with: :exception
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
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
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
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
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)
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
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
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