Dorian Lupu
Young father, freelance, experienced dev, (favorite stack #RubyonRails & #ReactJS)
5 April 2016
> params[:column] = "age) FROM users WHERE name = 'Bob';"
> Order.calculate(:sum, params[:column])
SELECT SUM(age) FROM users WHERE name = 'Bob';) FROM "orders"
62
> User.find_by(:name => 'Bob').age
SELECT "users".* FROM "users" WHERE "users"."name" = ? LIMIT 1 [["name", "Bob"]]
62
Learn :
* rails-sqli.org - SQL injection examples with rails 3 & 4
Play :
* presidentbeef/inject-some-sql - Rails 3 and 4 apps
Detect :
* presidentbeef/brakeman - Static analysis security vulnerability scanner
Stop using CookieStore for sessions
* by default, Rails sessions never expire on the server-side
* you should use : rails/activerecord-session_store
# ne faites pas ça dans les fichier .erb %>
raw @product.name
@product.name.html_safe
link_to “Personal Website”, @user.website
# <a href=”javascript:alert(‘XSS’)”>Personal Website</a>
* It is very easy to bypass the template.erb sanitization mechanisms. (The example below should not be done)
* By default, no sanitization for json responses
* Another attack vehicle : the href attribute
Do not put any critical information about security inside the code
* secret key base for cookies
* third party API tokens (mailjet, S3, and so on)
Use environment variables instead
Always use HTTPS
* josh/rack-ssl - force ssl connection
* mark all cookies as "Secure"
* add the Strict-Transport-Security (HSTS) header
* The default value is : "max-age=0, private, must-revalidate"
* sensible data can be access simply by clicking on the back button (even after a logout)
* you should use "no-cache, no-store"
You should use UUID instead of auto increment IDs
Be careful with json responses, by default, all database fields are exposed
class PostController < ApplicationController
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
@post = Post.find(params[:id])
if @post.update(post_params)
redirect_to post_path(@post), notice: 'Post was successfully updated.' }
else
render :edit
end
end
end
class PostController < ApplicationController
before_action :authenticate_user!, unless: :devise_controller? # !!!
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
@post = Post.find(params[:id])
if @post.update(post_params)
redirect_to post_path(@post), notice: 'Post was successfully updated.' }
else
render :edit
end
end
end
class PostController < ApplicationController
before_action :authenticate_user!, unless: :devise_controller?
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
@post = current_user.posts.find(params[:id]) # !!!
if @post.update(post_params)
redirect_to post_path(@post), notice: 'Post was successfully updated.' }
else
render :edit
end
end
end
# app/controllers/posts_controller.rb
class PostController < ApplicationController
before_action :authenticate_user!, unless: :devise_controller?
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
@post = current_user.posts.find(params[:id])
authorize! :update, @post # !!! helper from cancancan gem
if @post.update(post_params)
redirect_to post_path(@post), notice: 'Post was successfully updated.' }
else
render :edit
end
end
end
# app/models/ability.Rb
class Ability
include CanCan::Ability
def initialize(current_user)
current_user ||= User.new # guest user (not logged in)
can :update, Post do |post|
post.user.organization_id == current_user.organization_id ||
current_user.super_admin?
end
end
end
class ApplicationController < ActionController::Base
protect_from_forgery
end
By default, Rails offers a very strong protection
The protection can be bypass by any XSS vulnerability
Add the following two lines on your CI
bundle exec bundle-audit update
bundle exec bundle-audit check
example on a "recent" application (december 2015)
talk at #parisrb by @DorianLupu
slides available online : slides.com/kundigo
By Dorian Lupu
If you are hacked via OWASP Top 10, you are not allowed to call it "sophisticated"
Young father, freelance, experienced dev, (favorite stack #RubyonRails & #ReactJS)