Authentication security

Post on 24-Dec-2014

438 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

Сергей Нартымов (Sortware Engineer в Brainspec, Rails, Rubinius, Elixir contributor) Доклад: Безопасность аутентификации веб-приложений.

Transcript

Безопасность аутентификациивеб-приложений

Сергей НартымовBrainspec

https://github.com/lesttwitter: @just_lest

Хэш с солью

Хэш с солью

create_table :users do |t| t.string :name t.string :salt t.string :hashed_passwordend

Хэш с солью

def self.encrypted_password(password, salt) string_to_hash = password + "wibble" + salt Digest::SHA1.hexdigest(string_to_hash)end

def create_new_salt self.salt = self.object_id.to_s + rand.to_send

Хэш с солью

def password=(pwd) @password = pwd return if pwd.blank? create_new_salt self.hashed_password = User.encrypted_password(self.password, self.salt)end

Хэш с солью

def self.authenticate(name, password) user = self.find_by_name(name) if user expected_password = encrypted_password(password, user.salt) if user.hashed_password != expected_password user = nil end end userend

has_secure_password

create_table :users do |t| t.string :name t.string :password_digestend

class User < ActiveRecord::Base has_secure_passwordend

user = User.new(name: "david")user.password = "mUc3m00RsqyRe"user.password_digest# => "$2a$10$4LEA7r4YmNHtvlAvHhsYAeZmk/xeUVtMTYqwIvYY76EW5GUqDiP4."

user.save

user.authenticate("notright") # => falseuser.authenticate("mUc3m00RsqyRe") # => user

bcrypt

bcrypt

$2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa

идентификатор алгоритма

bcrypt

$2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa

сложность

bcrypt

$2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa

соль

bcrypt

$2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa

bcryptdef password=(unencrypted_password) unless unencrypted_password.blank? @password = unencrypted_password cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine::DEFAULT_COST self.password_digest = BCrypt::Password.create(unencrypted_password, cost: cost) endend

def authenticate(unencrypted_password) BCrypt::Password.new(password_digest) == unencrypted_password && selfend

bcryptdef password=(unencrypted_password) unless unencrypted_password.blank? @password = unencrypted_password cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine::DEFAULT_COST self.password_digest = BCrypt::Password.create(unencrypted_password, cost: cost) endend

def authenticate(unencrypted_password) BCrypt::Password.new(password_digest) == unencrypted_password && selfend

bcrypt

PBKDF2

scryptbcrypt

PBKDF2

scryptbcrypt

Перебор пользователей

• Неверный адрес e-mail или пароль.

• Если ваш адрес e-mail есть в нашей базе данных, то в течение нескольких минут вы получите письмо с инструкциями по восстановлению вашего пароля.

Тайминговые атаки

Тайминговые атаки

def authenticate! resource = valid_password? && mapping.to.find_for_database_authentication(authentication_hash) return fail(:not_found_in_database) unless resource

if validate(resource){ resource.valid_password?(password) } resource.after_database_authentication success!(resource) endend

Тайминговые атаки

user = User.last

Benchmark.realtime { user.valid_password?('lolwut') }# => 0.321346

Блокировка доступа

Блокировка доступа

• для пользователя• для IP-адреса

Блокировка доступа

• CAPTCHA

• разблокировка по ссылке из письма

Инвалидация сессии

Инвалидация сессии

user = User.authenticate(params[:name], params[:password])if user session[:user_id] = user.id redirect_to(:action => "index")else flash.now[:notice] = "Invalid user/password combination"end

Инвалидация сессии

• хранить в сессии данные, которые изменяются при изменении пароля

• например, соль пароля (так делает devise)

Инвалидация сессии

def serialize_into_session(record) [record.to_key, record.authenticatable_salt]end

def authenticatable_salt encrypted_password[0,29] if encrypted_passwordend

Запомнить меня

Запомнить меня

• добавляем токен и время

• храним токен в HttpOnly cookie

Запомнить меня

def remember_me!(extend_period=false) self.remember_token = self.class.remember_token if generate_remember_token? self.remember_created_at = Time.now.utc if generate_remember_timestamp?(extend_period) save(:validate => false) if self.changed?end

Запомнить меня

cookies.signed[remember_key(resource, scope)] = remember_cookie_values(resource)

def remember_cookie_values(resource) options = { :httponly => true } # ... options.merge!( :value => resource.class.serialize_into_cookie(resource), :expires => resource.remember_expires_at )end

Восстановление пароля

• не стоит генерировать пароль и присылать его на почту

• лучше генерировать токен и отправлять ссылку, по которой можно задать новый пароль

Сложность пароля

Сложность пароля

validates :password, length: { minimum: 5, maximum: 20 }

SSL

SSL

startssl.com

Двухэтапная аутентификация

Google

Двухэтапная аутентификация

Google

Facebook

Двухэтапная аутентификация

Google

Facebook

Dropbox

Двухэтапная аутентификация

Google

Facebook

AWS

Dropbox

Двухэтапная аутентификация

Google

Facebook

AWS

Dropbox

GitHub

Двухэтапная аутентификация

Спасибо

https://github.com/lesttwitter: @just_lest

Сергей НартымовBrainspec

top related