Heiko Webers, bauland42


Ruby on Rails Security Updated
Heiko Webers




 CEO of bauland42: Secure and innovative web
  applications, security code audits:
  http://www.bauland4...
Cross-Site Scripting in Rails 3
   Before: <%= h @project.name %>
    @project.name #=> <script>
    h(@project.name) #=>...
Cross-Site Scripting in Rails 3
 @project.name.html_safe? #=> false
 h(@project.name).html_safe? #=> true
 link_to(...)...
Cross-Site Scripting in Rails 3
 safe + safe = safe
 safe.concat(safe) = safe
 (safe << safe) = safe


   safe + unsaf...
Cross-Site Scripting in Rails 3
 String interpolation
 <%= "#{link_to(@product.title, @product)}
  #{link_to(@product.ti...
Cross-Site Scripting in Rails 3
   textilize() and simple_format() do not return
    safe strings
    textilize(‘*bold*‘)...
Cross-Site Scripting in Rails 3
 Know what you‘re doing
 <%= auto_link(@product.description) %>
  # => unsafe, so escape...
Cross-Site Scripting in Rails 3
 Know what you‘re doing
 Strings aren't magic:
  value = sanitize(@product.description)
...
Cross-Site Scripting in Rails 3
 Rails helper are becoming stable now
 There were problems with content_tag(), tag(),
  ...
Cross-Site Scripting in Rails 3
 xml.instruct!
  xml.description do
   xml << "The description: "
   xml << @product.desc...
Ajax and XSS
 No automatic escaping in RJS templates
 page.replace_html :notice,
   "Updated product #{@product.title}"
...
Sanitization
 Don‘t write it on your own:
  value = self.description.gsub("<script>", "")
  <scr<script>ipt>
 sanitize()...
Sanitization
 Use parsers like Nokogiri or Woodstox (JRuby)
 Gem sanitize: http://github.com/rgrove/sanitize
  Sanitize....
Sql-Injection in Rails 3
 No find() anymore, no :conditions hash, ...
  But: Product.find(params[:id])
 User.order('user...
Sql-Injection in Rails 3
 NO: User.order(params[:order]).all
 raise "SQLi" unless ["id asc", "id desc"].include?
  (para...
Other changes in Rails 3
 config/initializers/session_store.rb
  Rails.application.config.session_store
  :cookie_store, ...
Other changes in Rails 3
   Keep a value in a signed cookie:
    cookies.signed[:discount] = "12"

 filter_parameter_log...
Respond_with in Rails 3
 class ProductsController < ApplicationController
    respond_to :html, :xml, :json
    def index...
Bits and pieces
 You can deploy with a SSH key:
  ssh_options[:keys] = ["/path/to/id_rsa.ppk"]
 Secure the admin panel w...
Bits and pieces
 Check what they‘re downloading
  File.dirname(requested_filename) ==
   expected_directory
 /download?f...
Privilege escalation
 def update
 @doc = Doc.find(params[:id])
 end


 before_filter :load_project
 before_filter :de...
Authorization
 def deny_if_no_access_to_doc
 @doc.may_edit?(current_user)
 end


 def may_edit?(usr)
 self.creator ==...
That‘s it
 Questions?
 42@bauland42.de




                    24
Upcoming SlideShare
Loading in …5
×

Ruby on Rails Security Updated (Rails 3) at RailsWayCon

21,543 views
21,439 views

Published on

Published in: Technology
0 Comments
5 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
21,543
On SlideShare
0
From Embeds
0
Number of Embeds
15,586
Actions
Shares
0
Downloads
86
Comments
0
Likes
5
Embeds 0
No embeds

No notes for slide

Ruby on Rails Security Updated (Rails 3) at RailsWayCon

  1. 1. Heiko Webers, bauland42 Ruby on Rails Security Updated
  2. 2. Heiko Webers  CEO of bauland42: Secure and innovative web applications, security code audits: http://www.bauland42.de http://www.werkstatt42.de  Ruby on Rails Security Project: Blog and Book at http://www.rorsecurity.info
  3. 3. Cross-Site Scripting in Rails 3  Before: <%= h @project.name %> @project.name #=> <script> h(@project.name) #=> &lt;script&gt;  After: <%= @project.name %>  Unless you want to allow HTML/JS: <%= raw @project.name %>
  4. 4. Cross-Site Scripting in Rails 3  @project.name.html_safe? #=> false  h(@project.name).html_safe? #=> true  link_to(...).html_safe? #=> true  "<br />".html_safe # => "<br />" 4
  5. 5. Cross-Site Scripting in Rails 3  safe + safe = safe  safe.concat(safe) = safe  (safe << safe) = safe  safe + unsafe = unsafe ... 5
  6. 6. Cross-Site Scripting in Rails 3  String interpolation  <%= "#{link_to(@product.title, @product)} #{link_to(@product.title, @product)}" %>  Deliberately unsafe 6
  7. 7. Cross-Site Scripting in Rails 3  textilize() and simple_format() do not return safe strings textilize(‘*bold*‘) #=><strong>bold</strong>  <%= textilize(@product.description) %>  NO <%=raw textilize(@product.description)%>  OK <%=sanitize textilize(@product.description) %> 7
  8. 8. Cross-Site Scripting in Rails 3  Know what you‘re doing  <%= auto_link(@product.description) %> # => unsafe, so escaped  <%= raw auto_link(@product.description) %> # => safe, but may contain HTML  sanitize() it 8
  9. 9. Cross-Site Scripting in Rails 3  Know what you‘re doing  Strings aren't magic: value = sanitize(@product.description) value.html_safe? #=> true value.gsub!(/--product_name--/, @product.title) value.html_safe? #=> true <%= value %> 9
  10. 10. Cross-Site Scripting in Rails 3  Rails helper are becoming stable now  There were problems with content_tag(), tag(), submit_tag(), ...  SafeErb plugin doesn‘t work yet/anymore 10
  11. 11. Cross-Site Scripting in Rails 3  xml.instruct! xml.description do xml << "The description: " xml << @product.description end  Use xml.description @product.description to automatically escape 11
  12. 12. Ajax and XSS  No automatic escaping in RJS templates  page.replace_html :notice, "Updated product #{@product.title}" 12
  13. 13. Sanitization  Don‘t write it on your own: value = self.description.gsub("<script>", "") <scr<script>ipt>  sanitize(), strip_tags(), ... use the HTML::Tokenizer  Based on regular expressions  Doesn‘t always render valid HTML  Last vulnerability in Rails 2.3.5 regarding non- printable ascii characters 13
  14. 14. Sanitization  Use parsers like Nokogiri or Woodstox (JRuby)  Gem sanitize: http://github.com/rgrove/sanitize Sanitize.clean(unsafe_html)  Gem Loofah: http://github.com/flavorjones/ loofah Loofah.fragment(unsafe_html).scrub!(:strip) 14
  15. 15. Sql-Injection in Rails 3  No find() anymore, no :conditions hash, ... But: Product.find(params[:id])  User.order('users.id DESC').limit(20).all  NO: Product.where("id = #{params[:id]}")  Product.where(["id = ?", params[:id]])  Product.where({:id => params[:id]}) 15
  16. 16. Sql-Injection in Rails 3  NO: User.order(params[:order]).all  raise "SQLi" unless ["id asc", "id desc"].include? (params[:order])  Escape it yourself: Product.order(Product.connection.quote(params [:order])).all 16
  17. 17. Other changes in Rails 3  config/initializers/session_store.rb Rails.application.config.session_store :cookie_store, :key => "_app_name_session"  config/initializers/cookie_verification_secret.rb Rails.application.config.cookie_secret = 'somereallylongrandomkey'  Don‘t keep it in your SCM 17
  18. 18. Other changes in Rails 3  Keep a value in a signed cookie: cookies.signed[:discount] = "12"  filter_parameter_logging deprecated  config.filter_parameters << :password in config/application.rb 18
  19. 19. Respond_with in Rails 3  class ProductsController < ApplicationController respond_to :html, :xml, :json def index respond_with(@products = Product.all) end end  How to define what attributes to render in XML? @product.to_xml(:only => [:id]) 19
  20. 20. Bits and pieces  You can deploy with a SSH key: ssh_options[:keys] = ["/path/to/id_rsa.ppk"]  Secure the admin panel with a client SSL certificate  Remove secrets from your SCM: database.yml, ssh_config.rb 20
  21. 21. Bits and pieces  Check what they‘re downloading File.dirname(requested_filename) == expected_directory  /download?file=../config/database.yml  validates_format_of :filename, :with => /^[a-z.]+$/i  hello.txt <script>alert(1)</script>  Use A and z 21
  22. 22. Privilege escalation  def update  @doc = Doc.find(params[:id])  end  before_filter :load_project  before_filter :deny_if_not_full_access  before_filter :load_doc @doc = @project.docs.find(params[:id])  before_filter :deny_if_no_access_to_doc 22
  23. 23. Authorization  def deny_if_no_access_to_doc  @doc.may_edit?(current_user)  end  def may_edit?(usr)  self.creator == usr  end  <%= link_to(“Edit“,...) if @doc.may_edit? (current_user) %> 23
  24. 24. That‘s it  Questions?  42@bauland42.de 24

×