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

20 tips to secure your Rails application

20 tips to secure your Rails application

Slides for my talk at Conferencia Rails 2016

Daniel Lobato García

October 15, 2016
Tweet

More Decks by Daniel Lobato García

Other Decks in Programming

Transcript

  1. 20 actionable tips to secure your Rails application Conferencia Rails

    Madrid ‘16 Daniel Lobato García (@dLobatog)
  2. 2 CONFERENCIA RAILS 2016 Writing about web security is always

    a dangerous exercise. There’s a good chance I’ve gotten at least one or more facts wrong in this talk despite taking a good deal of time to research the topic from various angles.
  3. CONFERENCIA RAILS 2016 7 AGENDA • Password resets • Updating

    attributes • Handling sessions securely • Cookies • Handling profile pictures • Links to user’s own page • File uploading • Protecting user actions • Protecting against password crackers • Protecting your frontend • + 5 more general tips
  4. CONFERENCIA RAILS 2016 8 PASSWORD RESET PASSWORD RESET Forgot password

    link Send page with token Forgot password link Submit new password
  5. CONFERENCIA RAILS 2016 9 PASSWORD RESET def reset user =

    User.find_by_token(params[:user][:token]) if user.present? // Some confirm password validation stuff user.reset_password(params[:user][:pass]) end end
  6. CONFERENCIA RAILS 2016 10 PASSWORD RESET PROBLEM - ? PUT

    /users/reset '{"user":{"token":”23a982”,"pass":"hacked","pass_confirm":"hacked"}}'
  7. CONFERENCIA RAILS 2016 11 PASSWORD RESET PROBLEM – ? PUT

    /users/reset '{"user":{"token":”23a982”,"pass":"hacked","pass_confirm":"hacked"}}' '{"user":{"token":”0”,"pass":"hacked","pass_confirm":"hacked"}}'
  8. CONFERENCIA RAILS 2016 12 PASSWORD RESET PROBLEM – ? PUT

    /users/reset '{"user":{"token":”23a982”,"pass":"hacked","pass_confirm":"hacked"}}' '{"user":{"token":”0”,"pass":"hacked","pass_confirm":"hacked"}}' '{"user":{"token":0,"pass":"hacked","pass_confirm":"hacked"}}'
  9. CONFERENCIA RAILS 2016 14 CONVERT PARAMS TO TYPES PROBLEM –

    SQL TYPECASTING MATCHES WRONG RECORDS '{"user":{"token":0,"pass":"hacked","pass_confirm":"hacked"}}' '{"user":{"token":[0],"pass":"hacked","pass_confirm":"hacked"}}' def reset user = User.find_by_token(params[:user][:token]) if user.present? user.reset_password(params[:user][:pass]) end end
  10. CONFERENCIA RAILS 2016 15 CONVERT PARAMS TO TYPES PROBLEM –

    SQL TYPECASTING MATCHES WRONG RECORDS String vs String comparison mysql> SELECT reset_token FROM users WHERE reset_token=”0”; 0 row in set (0.00 sec)
  11. CONFERENCIA RAILS 2016 16 CONVERT PARAMS TO TYPES PROBLEM –

    SQL TYPECASTING MATCHES WRONG RECORDS “1aC” is casted to 0 (invalid integer) 0=0 retrieves all records mysql> SELECT reset_token FROM users WHERE reset_token=0; +-------------+ | reset_token | +-------------+ | 1aC | +-------------+ 1 row in set (0.00 sec)
  12. CONFERENCIA RAILS 2016 17 CONVERT PARAMS TO TYPES PROBLEM –

    SQL TYPECASTING MATCHES WRONG RECORDS “1aC” is casted to 0 (invalid integer) 0=0 retrieves all records mysql> SELECT reset_token FROM users WHERE 0=0; +-------------+ | reset_token | +-------------+ | 1aC | +-------------+ 1 row in set (0.00 sec)
  13. CONFERENCIA RAILS 2016 18 CONVERT PARAMS TO TYPES WORKAROUND –

    CAST MANUALLY TO KNOWN TYPE user = User.find_by_token params[:user][:token].to_s
  14. CONFERENCIA RAILS 2016 21 UPDATING USER def update user =

    User.where("name = '#{params[:name]}'") user.update_attributes(user_params) end
  15. CONFERENCIA RAILS 2016 22 SQL INJECTION PROBLEM – USER INPUT

    NOT ESCAPED Using params directly on SQL queries – huge mistake. Hardly a problem on most Rails apps thanks to sane defaults. User.where("name = '#{params[:name]}'")
  16. CONFERENCIA RAILS 2016 23 SQL INJECTION PROBLEM – USER INPUT

    NOT ESCAPED Using params directly on SQL queries – huge mistake. Hardly a problem on most Rails apps thanks to sane defaults. User.where("name = '#{params[:name]}'") params[:name] = “' OR 1 --“ SELECT * FROM users WHERE name = '' OR 1 –'
  17. CONFERENCIA RAILS 2016 24 SQL INJECTION PROBLEM – USER INPUT

    NOT ESCAPED Using params directly on SQL queries – huge mistake. Hardly a problem on most Rails apps thanks to sane defaults. User.where("name = '#{params[:name]}'") params[:name] = “'; DELETE FROM employees --“ SELECT * FROM users WHERE name = ''; DELETE FROM employees ' –
  18. CONFERENCIA RAILS 2016 25 SQL INJECTION SOLUTION – USE RAILS

    BUILT-IN FILTERS Rails auto sanitizes input in SQL queries User.where(:name => params[:name]) User.where('name = ? AND password = ?', params[:name], params[:pass])
  19. CONFERENCIA RAILS 2016 26 SQL INJECTION VULNERABLE METHODS .calculate .order

    .delete_all .all .destroy_all .pluck .exists? .reorder .find .first .find_by .where .from .update_all .group .having .joins .lock
  20. CONFERENCIA RAILS 2016 27 SQL INJECTION VULNERABLE METHODS .calculate .order

    .delete_all .all .destroy_all .pluck .exists? .reorder .find .first .find_by .where .from .update_all .group .having .joins Check out rails-sqli.org .lock
  21. CONFERENCIA RAILS 2016 29 SESSIONS DATA WHAT TO STORE IN

    A SESSION • last_login • session timeouts • user preferences • account ID • privilege level • access rights • language preferences
  22. CONFERENCIA RAILS 2016 30 SESSIONS DATA WHAT TO STORE IN

    A SESSION • last_login • session timeouts • user preferences • account ID • privilege level • access rights • language preferences
  23. CONFERENCIA RAILS 2016 31 SESSIONS DATA WHAT TO STORE IN

    A SESSION • A session ID • Do “session ID user matching” server side →
  24. CONFERENCIA RAILS 2016 32 DON'T STORE DATA IN COOKIES PROBLEM

    – DECODING A SESSION COOKIE In Rails 2 and 3, decoding a session cookie is this simple: Marshal.load( Base64.decode64( URI.decode( cookie.split('--').first )))
  25. CONFERENCIA RAILS 2016 33 DON'T STORE DATA IN COOKIES PROBLEM

    – DECODING A SESSION COOKIE In Rails 2 and 3, decoding a session cookie is this simple: Marshal.load( Base64.decode64( URI.decode( cookie.split('--').first )))
  26. CONFERENCIA RAILS 2016 34 DON'T STORE DATA IN COOKIES PROBLEM

    – DECODING A SESSION COOKIE In Rails 4 it's a bit harder, 1000 iterations of PBKDF2 with a salt: bit.ly/1M1suyK
  27. CONFERENCIA RAILS 2016 35 DON'T STORE DATA IN COOKIES PROBLEM

    – DECODING A SESSION COOKIE In Rails 4 it's a bit harder, 1000 iterations of PBKDF2 with a salt: – Did you create secret_key_base on config/secrets.yml? – If not, your app supports legacy Rails 3 cookies.
  28. CONFERENCIA RAILS 2016 36 DON'T STORE DATA IN COOKIES PROBLEM

    – DECODING A SESSION COOKIE With session data in our hands, we can alter it trivially.
  29. CONFERENCIA RAILS 2016 37 DON'T STORE DATA IN COOKIES PROBLEM

    – DECODING A SESSION COOKIE With session data in our hands, we can alter it trivially.
  30. CONFERENCIA RAILS 2016 38 DON'T STORE DATA IN COOKIES PROBLEM

    – DECODING A SESSION COOKIE With session data in our hands, we can alter it trivially. Not really, because of the session digest. You can only read it. So don’t store anything other than the session ID there!!!
  31. CONFERENCIA RAILS 2016 39 DON'T STORE DATA IN COOKIES SOLUTION

    – USE ALTERNATIVE STORAGE rails/activerecord-session_store (ActiveRecord) redis-store/redis-rails (Redis) mperham/dalli (memcached)
  32. CONFERENCIA RAILS 2016 40 EXPIRE SESSIONS PROBLEM – LONG-RUNNING SESSIONS

    Stolen session IDs should be rendered unusable.
  33. CONFERENCIA RAILS 2016 41 EXPIRE SESSIONS PROBLEM – LONG-RUNNING SESSIONS

    Stolen session IDs should be rendered unusable. Sniffing, XSS, etc…
  34. CONFERENCIA RAILS 2016 42 EXPIRE SESSIONS SOLUTION – USE “EXPIRES”

    & SWEEP Set the “Expires” and “Max-Age” HTTP headers – client side Run a cron job – server side
  35. CONFERENCIA RAILS 2016 46 IMAGETRAGICK “LET’S CROP THE USER PROFILE

    IMAGE” Using Rmagick, MiniMagick or Paperclip? You’re EXPOSED
  36. CONFERENCIA RAILS 2016 47 IMAGETRAGICK PROBLEM: EXOTIC IMAGE FILETYPES Certain

    image encoders accepted by ImageMagick open you to arbitrary remote execution of code
  37. CONFERENCIA RAILS 2016 48 IMAGETRAGICK PROBLEM: EXOTIC IMAGE FILETYPES -

    .mvg push graphic-context viewbox 0 0 640 480 image over 0,0 0,0 'label:@/Users/fco/.ssh/id_rsa' pop graphic-context
  38. CONFERENCIA RAILS 2016 49 IMAGETRAGICK PROBLEM: EXOTIC IMAGE FILETYPES -

    .svg <image xlink:href="https://me.com/ me.jpg&quot;; eval ls; echo &quot;vulnerable" x="0" y="0" height="640px" width="480px"/>
  39. CONFERENCIA RAILS 2016 50 IMAGETRAGICK PROBLEM: EXOTIC IMAGE FILETYPES -

    .mvg push graphic-context viewbox 0 0 640 480 image over 0,0 0,0 'label:@/Users/fco/.ssh/id_rsa' pop graphic-context
  40. CONFERENCIA RAILS 2016 51 IMAGETRAGICK SOLUTIONS: • TEST MAGIC BYTES

    OF USER PROVIDED IMAGES • DISABLE UNCOMMON CODERS (/etc/ImageMagick/policy.xml)
  41. CONFERENCIA RAILS 2016 53 INSECURE FILE REFERENCES PROBLEM – INDIRECT

    FILE REFERENCE send_file “docs/#{params[:doc_name]}.pdf”
  42. CONFERENCIA RAILS 2016 54 INSECURE FILE REFERENCES PROBLEM – INDIRECT

    FILE REFERENCE What happens if doc_name is '../'? send_file “docs/#{params[:doc_name]}.pdf” Attackers can freely traverse the server filesystem.
  43. CONFERENCIA RAILS 2016 55 INSECURE FILE REFERENCES SOLUTION – JUST

    DON'T Whitelist params[:doc_name] # sanitize params[:doc_name] send_file “docs/#{params[:doc_name]}.pdf”
  44. CONFERENCIA RAILS 2016 56 INSECURE FILE REFERENCES SOLUTION – JUST

    DON'T Whitelist params[:doc_name] # sanitize params[:doc_name] send_file “docs/#{params[:doc_name]}.pdf” The user running your app should have minimal permissions!
  45. CONFERENCIA RAILS 2016 57 INSECURE FILE REFERENCES SOLUTION – JUST

    DON'T Whitelist params[:doc_name] # sanitize params[:doc_name] send_file “docs/#{params[:doc_name]}.pdf” The user running your app should have minimal permissions! I keep a headcount of people who run their apps as root.
  46. CONFERENCIA RAILS 2016 59 PROTECT LINK_TO HREF PROBLEM – HREF

    IS HTML_SAFE <%= link_to "Personal blog", user.blog_url %>
  47. CONFERENCIA RAILS 2016 60 PROTECT LINK_TO HREF PROBLEM – HREF

    IS HTML_SAFE Users can set a blog URL to be displayed on their profiles <%= link_to "Personal blog", user.blog_url %>
  48. CONFERENCIA RAILS 2016 61 PROTECT LINK_TO HREF PROBLEM – HREF

    IS HTML_SAFE Users can set a blog URL to be displayed on their profiles <%= link_to "Personal blog", user.blog_url %> equivalent to <%= link_to "Personal blog", user.blog_url.html_safe %>
  49. CONFERENCIA RAILS 2016 62 PROTECT LINK_TO HREF PROBLEM – HREF

    IS HTML_SAFE Users can set a blog URL to be displayed on their profiles <%= link_to "Personal blog", user.blog_url %> Nothing stops an user from setting blog_url to "javascript:alert('hacked!')"
  50. CONFERENCIA RAILS 2016 63 PROTECT LINK_TO HREF SOLUTION – CHECK

    THE PROTOCOL Run URI.parse on user.blog_url and check the protocol validate :blog_url, :format => { :with => HTTP_REGEX } <%= link_to "Personal blog", user.blog_url %>
  51. CONFERENCIA RAILS 2016 65 MULTILINE REGEX PROBLEM – JS INJECTION

    validates :blog_url, :format => { :with => /^http(s)*\S+$/i }
  52. CONFERENCIA RAILS 2016 66 MULTILINE REGEX PROBLEM – JS INJECTION

    Ruby matches regexes by default on multi-line mode. If you're trying to validate, a user name, or an URL: validates :blog_url, :format => { :with => /^http(s)*\S+$/i }
  53. CONFERENCIA RAILS 2016 67 MULTILINE REGEX PROBLEM – JS INJECTION

    Ruby matches regexes by default on multi-line mode. If you're trying to validate, a user name, or an URL: validates :blog_url, :format => { :with => /^http(s)*\S+$/i } $ in the above regex would stop at \n
  54. CONFERENCIA RAILS 2016 68 MULTILINE REGEX PROBLEM – JS INJECTION

    Multi-line regex validations can easily be bypassed javascript:alert('hacked!')/*\nhttp://*/ validates :blog_url, :format => { :with => /^http(s)*?:+$/i }
  55. CONFERENCIA RAILS 2016 69 MULTILINE REGEX PROBLEM – JS INJECTION

    Multi-line regex validations can easily be bypassed javascript:alert('hacked!')/*\nhttp://*/ validates :blog_url, :format => { :with => /^http(s)*?:+$/i } link_to "User blog", @user.blog_url # renders XSS
  56. CONFERENCIA RAILS 2016 70 MULTILINE REGEX SOLUTION – MATCH START/END

    OF EXPRESSION Rails 4 warns you about this validates :blog_url, :format => { :with => / \Ahttp(s)*?:+ \z/i }
  57. CONFERENCIA RAILS 2016 72 REFLECTIONS PROBLEM – SEND/EVAL ANY PARAMETERS

    Imagine you have an API that depends on other API Example: power operations on servers api :PUT, "/hosts/:id/power" @host.power.send(params[:power_action])
  58. CONFERENCIA RAILS 2016 73 REFLECTIONS PROBLEM – SEND/EVAL ANY PARAMETERS

    Attacker supplies power_action= eval&b=whatever%20ruby%20code%20we%20like api :PUT, "/hosts/:id/power" @host.power.send(params[:power_action])
  59. CONFERENCIA RAILS 2016 74 REFLECTIONS PROBLEM – SEND/EVAL ANY PARAMETERS

    Attacker supplies power_action= eval&b=FileUtils.rm_rf(%22%2f%22) # rm -rf / api :PUT, "/hosts/:id/power" @host.power.send(params[:power_action])
  60. CONFERENCIA RAILS 2016 75 REFLECTIONS PROBLEM – SEND/EVAL ANY PARAMETERS

    Real example, on Spree (popular Rails e-commerce framework) api/orders.json?search[instance_eval]= Kernel.fork%20do%60#{command}%60end
  61. CONFERENCIA RAILS 2016 76 REFLECTIONS PROBLEM – SEND/EVAL ANY PARAMETERS

    Attacker supplies power_action= eval&b=FileUtils.rm_rf(%22%2f%22) # rm -rf / api :PUT, "/hosts/:id/power" @host.power.send(params[:power_action])
  62. CONFERENCIA RAILS 2016 77 REFLECTIONS SOLUTION – AVOID OR WHITELIST

    Note commands can be chained (&&, ||, etc...) if PowerManager::SUPPORTED_ACTIONS.include? params[:power_action] @host.power.send(params[:power_action]) else 422, 'available methods are…'
  63. CONFERENCIA RAILS 2016 78 THROTTLE SOME REQUESTS PROBLEM – BRUTE

    FORCE LOGIN ATTEMPTS Your application gets hundreds of requests per second trying to brute force a password for a certain user.
  64. CONFERENCIA RAILS 2016 79 THROTTLE SOME REQUESTS PROBLEM – BRUTE

    FORCE LOGIN ATTEMPTS Your application gets hundreds of requests per second trying to brute force a password for a certain user. PROBLEM – DOS An attacker wants to throw down your site after you published something you should have not. Or just for kicks.
  65. CONFERENCIA RAILS 2016 80 THROTTLE SOME REQUESTS SOLUTION – USE

    RACK::ATTACK On config/initializers/rack-attack.rb # Throttle high volumes of requests by IP address throttle('req/ip', limit: 20, period: 20.seconds) do |req| req.ip unless req.path.starts_with?('/assets') end
  66. CONFERENCIA RAILS 2016 81 JSONP LEAKS PROBLEM – SENSITIVE DATA

    SERVED OVER JSON Rails scaffolding generates by default XML & JSON renderers curl http://example.com/users/1.json
  67. CONFERENCIA RAILS 2016 82 JSONP LEAKS PROBLEM – SENSITIVE DATA

    SERVED OVER JSON When here the JavaScript renderer emits e.g. JQuery fragments like: $("#messages").html(.. # load inbox from JSON
  68. CONFERENCIA RAILS 2016 83 JSONP LEAKS PROBLEM – SENSITIVE DATA

    SERVED OVER JSON When here the JavaScript renderer emits e.g. JQuery fragments like: $("#messages").html(.. # load inbox from JSON Attackers can just <script src="http://example/inbox/messages?format=js"> And do whatever they want with the inbox messages
  69. CONFERENCIA RAILS 2016 84 JSONP LEAKS PROBLEM – SENSITIVE DATA

    SERVED OVER JSON Phishing with JSONP leaks easy as pie → # Hi @poorSoul, have you seen what they say about you here? Link
  70. CONFERENCIA RAILS 2016 85 JSONP LEAKS PROBLEM – SENSITIVE DATA

    SERVED OVER JSON Phishing with JSONP leaks easy as pie → # Hi @poorSoul, have you seen what they say about you here? Link # * @poorSoul clicks *
  71. CONFERENCIA RAILS 2016 86 JSONP LEAKS PROBLEM – SENSITIVE DATA

    SERVED OVER JSON Phishing with JSONP leaks easy as pie → # Hi @poorSoul, have you seen what they say about you here? Link # * @poorSoul clicks * # Thanks for your inbox!
  72. CONFERENCIA RAILS 2016 87 USE SECURE HEADERS CSP, HSTS, etc...

    SOLUTION – SECURE HEADERS • github.com/twitter/secureheaders Alternatively: ActionDispatch::Response.default_headers = { 'X-Frame-Options' => 'DENY', 'X-Content-Type-Options' => 'nosniff', 'X-XSS-Protection' => '1;' }
  73. CONFERENCIA RAILS 2016 92 NEVER USE GET TO MODIFY PROBLEM

    – CROSS SITE SCRIPTING Any request that modifies a resource should be triggered GET is loaded automatically. <img src="http://example.com/projects/1/destroy“ />
  74. CONFERENCIA RAILS 2016 93 NEVER USE GET TO MODIFY PROBLEM

    – CROSS SITE SCRIPTING Any request that modifies a resource should be triggered GET is loaded automatically. <img src="http://example.com/projects/1/destroy“ /> <img src="http://example.com/users/admin/edit?password=lol“ />
  75. CONFERENCIA RAILS 2016 94 NEVER USE GET TO MODIFY PROBLEM

    – CROSS SITE SCRIPTING Real example – traffic in LA - bit.ly/1r03DpC <img src="http://latraffic.com/light/329?color=green“ />
  76. CONFERENCIA RAILS 2016 95 NEVER USE GET TO MODIFY SOLUTION

    – USE PUT, PATCH, POST If any of these routes use PUT, PATCH or POST nothing happens <img src="http://example.com/projects/destroy“/> <img src="http://example.com/users/admin“/> <img src="http://example.com/light/392/on“/>
  77. CONFERENCIA RAILS 2016 96 PROTECT PUT, POST, DELETE PROBLEM –

    UNVERIFIED REQUESTS <!---- victim browser loads our bait link ----> <img width=”300000” height=”300000” onmouseover=" var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'PUT'; f.data = '{ \'password\' : 'hacked!' }'; f.action = 'http://example.com/user/admin'; f.submit(); return false; ">
  78. CONFERENCIA RAILS 2016 97 PROTECT PUT, POST, DELETE SOLUTION –

    UNVERIFIED REQUESTS class ApplicationController protect_from_forgery :with => :exception rescue_from ActionController::InvalidAuthenticityToken do |exception| sign_out_user end
  79. CONFERENCIA RAILS 2016 98 PROTECT PUT, POST, DELETE verified_request? protect_from_forgery

    verify_authenticity_token execute request handle_unverified_request false true
  80. CONFERENCIA RAILS 2016 99 RENDERERS PROBLEM – XSS & ARBITRARY

    CODE EXECUTION render “Goodbye user!”
  81. CONFERENCIA RAILS 2016 100 RENDERERS PROBLEM – XSS & ARBITRARY

    CODE EXECUTION render “Goodbye #{params[:name]}”
  82. CONFERENCIA RAILS 2016 101 RENDERERS PROBLEM – XSS & ARBITRARY

    CODE EXECUTION Plain 'render' takes an 'inline' argument to render ERB render params[:name] + “, see you!”
  83. CONFERENCIA RAILS 2016 102 RENDERERS PROBLEM – XSS & ARBITRARY

    CODE EXECUTION Plain 'render' takes an 'inline' argument to render ERB def render(*args) render :text render :inline
  84. CONFERENCIA RAILS 2016 103 RENDERERS PROBLEM – XSS & ARBITRARY

    CODE EXECUTION Plain 'render' takes an 'inline' argument to render ERB render params[:name] curl 'example.com?name%5Binline%5D%3D%3C%25%3D%60rm+-rf %60%25%3E
  85. CONFERENCIA RAILS 2016 104 RENDERERS PROBLEM – XSS & ARBITRARY

    CODE EXECUTION Plain 'render' takes an 'inline' argument to render ERB render params[:name] curl 'example.com?name[inline]=<%=`rm -rf`%>
  86. CONFERENCIA RAILS 2016 105 RENDERERS SOLUTION – AVOID PLAIN RENDER

    I'd love to know the use case for plain render. Just use render :plain => params[:name] SOLUTION – AVOID PLAIN RENDER I'd love to know the use case for plain render. Just use render :plain => params[:name]
  87. CONFERENCIA RAILS 2016 106 RENDERERS SOLUTION – UPDATE RAILS :)

    5.0.0.beta1.1, 4.2.5.1, 4.1.14.1, 3.2.22.1 stringify all params SOLUTION – UPDATE RAILS :) 5.0.0.beta1.1, 4.2.5.1, 4.1.14.1, 3.2.22.1 stringify all params
  88. CONFERENCIA RAILS 2016 109 FORCE TLS PROBLEM - POODLE attack

    When TLS is unavailable, browser downgrades to SSLv3 96.9% of top 1M websites are vulnerable Man-in-the-middle can read HTTPS requests!
  89. CONFERENCIA RAILS 2016 110 FORCE TLS PROBLEM - POODLE attack

    When TLS is unavailable, browser downgrades to SSLv3 96.9% of top 1M websites are vulnerable Man-in-the-middle can read HTTPS requests! PROBLEM – TLS DOWNGRADE
  90. CONFERENCIA RAILS 2016 111 FORCE TLS PROBLEM - POODLE attack

    When TLS is unavailable, browser downgrades to SSLv3 96.9% of top 1M websites are vulnerable Man-in-the-middle can read HTTPS requests! PROBLEM – TLS DOWNGRADE Client and server support TLSv1.2. Active man-in-the-middle forces a downgrade. TLSv1.1 TLSv1.0 SSLv3 → → → POODLE
  91. CONFERENCIA RAILS 2016 112 FORCE TLS SOLUTION - POODLE attack

    class ApplicationController force_ssl end request.options = OpenSSL::SSL::OP_NO_SSLv2 + OpenSSL::SSL::OP_NO_SSLv3 Apache vHost SSLProtocol +TLSv1.1 +TLSv1.2 Nginx.conf ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  92. CONFERENCIA RAILS 2016 113 VERIFY REDIRECTS PROBLEM – ARBITRARY URL

    REDIRECT Usual 'def login' code if login_user(user) session[:user] = user.id uri = session[:original_uri] redirect_to (uri || homepage)
  93. CONFERENCIA RAILS 2016 114 VERIFY REDIRECTS PROBLEM – ARBITRARY URL

    REDIRECT Usual 'def login' code if login_user(user) session[:user] = user.id uri = session[:original_uri] redirect_to (uri || homepage) https://example.com/login attacker.com →
  94. CONFERENCIA RAILS 2016 115 VERIFY REDIRECTS SOLUTION – ARBITRARY URL

    REDIRECT Don't allow users to set redirect URLs Whitelist valid URLs if absolutely necessary
  95. CONFERENCIA RAILS 2016 116 HIDE YOUR HEADERS PROBLEM – SERVER

    VERSION IS EXPOSED The default server header in Webrick exposes you – Server: WEBrick/1.3.1 (Ruby/1.9.3/2012-04-20) Other servers suffer from the same issue – 'Server' in Apache, Thin and Webrick – 'X-Powered-By' on Nginx
  96. CONFERENCIA RAILS 2016 117 HIDE YOUR HEADERS SOLUTION – OVERRIDE

    IT IN THE APPLICATION config.action_dispatch. default_headers.merge!('Server' => '')
  97. CONFERENCIA RAILS 2016 119 SCAN YOUR APP Vulnerabilities scanners for

    Rails applications Brakeman – github.com/presidentbeef/brakeman Dawnscanner – github.com/thesp0nge/dawnscanner
  98. CONFERENCIA RAILS 2016 120 SCAN YOUR DEPENDENCIES With Bundler, the

    danger lies within Bundler-audit – github.com/rubysec/bundler-audit Gemnasium – gemnasium.com
  99. 121 CONFERENCIA RAILS 2016 Writing about web security is always

    a dangerous exercise. There’s a good chance I’ve gotten at least one or more facts wrong in this talk despite taking a good deal of time to research the topic from various angles.