Slide 1

Slide 1 text

Безопасность аутентификации веб-приложений Сергей Нартымов Brainspec https://github.com/lest twitter: @just_lest

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

Хэш с солью

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

Хэш с солью create_table :users do |t| t.string :name t.string :salt t.string :hashed_password end

Slide 6

Slide 6 text

Хэш с солью 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_s end

Slide 7

Slide 7 text

Хэш с солью def password=(pwd) @password = pwd return if pwd.blank? create_new_salt self.hashed_password = User.encrypted_password(self.password, self.salt) end

Slide 8

Slide 8 text

Хэш с солью 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 user end

Slide 9

Slide 9 text

has_secure_password

Slide 10

Slide 10 text

create_table :users do |t| t.string :name t.string :password_digest end class User < ActiveRecord::Base has_secure_password end

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

bcrypt

Slide 13

Slide 13 text

bcrypt $2a$10$vI8aWBnW3fID.ZQ4/z идентификатор алгоритма

Slide 14

Slide 14 text

bcrypt $2a$10$vI8aWBnW3fID.ZQ4/zo1G сложность

Slide 15

Slide 15 text

bcrypt $2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps соль

Slide 16

Slide 16 text

bcrypt o1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa

Slide 17

Slide 17 text

bcrypt def 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) end end def authenticate(unencrypted_password) BCrypt::Password.new(password_digest) == unencrypted_password && self end

Slide 18

Slide 18 text

bcrypt def 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) end end def authenticate(unencrypted_password) BCrypt::Password.new(password_digest) == unencrypted_password && self end

Slide 19

Slide 19 text

bcrypt

Slide 20

Slide 20 text

PBKDF2 scrypt bcrypt

Slide 21

Slide 21 text

PBKDF2 scrypt bcrypt

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

Инвалидация сессии 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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

Инвалидация сессии def serialize_into_session(record) [record.to_key, record.authenticatable_salt] end def authenticatable_salt encrypted_password[0,29] if encrypted_password end

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

Блокировка доступа • CAPTCHA • разблокировка по ссылке из письма

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

Запомнить меня • добавляем токен и время • храним токен в HttpOnly cookie

Slide 31

Slide 31 text

Запомнить меня 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

Slide 32

Slide 32 text

Запомнить меня 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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

Тайминговые атаки 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) end end

Slide 37

Slide 37 text

Тайминговые атаки user = User.last Benchmark.realtime { user.valid_password?('lolwut') } # => 0.321346

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

Сложность пароля validates :password, length: { minimum: 5, maximum: 20 }

Slide 41

Slide 41 text

SSL

Slide 42

Slide 42 text

SSL startssl.com

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

Google Facebook AWS Dropbox Двухэтапная аутентификация

Slide 48

Slide 48 text

Google Facebook AWS Dropbox GitHub Двухэтапная аутентификация

Slide 49

Slide 49 text

Open Web Application Security Project • https://www.owasp.org/ • https://www.owasp.org/index.php/ Cheat_Sheets

Slide 50

Slide 50 text

Спасибо https://github.com/lest twitter: @just_lest Сергей Нартымов Brainspec