Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Authentication Security – RUBYSPB
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Sergey Nartimov
September 21, 2013
Programming
200
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Authentication Security – RUBYSPB
Sergey Nartimov
September 21, 2013
More Decks by Sergey Nartimov
See All by Sergey Nartimov
PubSub at Rails
lest
0
140
Rails in production - RubyConfBY 22 Mar 2015
lest
1
160
Sequel - BRUG 21 Feb 2015
lest
0
100
Elixir – Belarus Ruby User Group 25 Jan 2014
lest
3
670
Geospatial applications on Rails
lest
8
440
Design patterns – Belarus Ruby on Rails User Group 23 Feb 2013
lest
8
670
Ruby Stdlib – Minsk.rb October 2012
lest
10
420
Background jobs with realtime results – RailsClub'Moscow 2012
lest
5
230
Other Decks in Programming
See All in Programming
PHP初心者セッション2026 〜生成AIでは見えない裏側を知る:今だからLAMPを通して仕組みを学ぶ〜
kashioka
0
710
광주소프트웨어마이스터고등학교 DevFest 특강 - 바이브 코딩 시대에서 주니어 개발자로 살아남는 방법
utilforever
1
160
Claude Opus 4.6以後の受託開発エンジニアの変化(Claude Code開発ノウハウ大公開スペシャルbyクラスメソッド)
iidatakuma
1
890
GDG Korea Android: 2026 I/O Extended ~ What's new in Android development tools
pluu
0
190
ルールを書いて終わらせないハーネスエンジニアリング
yug1224
4
1.8k
ソフトウェア設計に溶けるインフラ ― AWS CDK のインフラ認識論
konokenj
3
670
Haskell/Servantを通してWebミドルウェアを捉え直す
pizzacat83
1
620
AIエージェントで 変わるAndroid開発環境
takahirom
2
730
Welcome to the "Parametricity" 🏙️ − Generic だけど Specific な世界 −
guvalif
PRO
1
190
Laravel Boostに学ぶ、AIにPHPを書かせる技術 〜OSSの実装から蒸留するエージェント制御の王道〜
kentaroutakeda
3
550
【やさしく解説 設計編 #0】DDDのコード、読めるのに分からない人へ
panda728
PRO
2
280
作るコストが小さくなった時代 幸せに働くために改めて考えたいこと 〜エンジニアとして価値を出し続けるために注視している二分野〜
yuppeeng
0
130
Featured
See All Featured
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
200
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
660
Designing for Timeless Needs
cassininazir
1
410
Side Projects
sachag
455
43k
Skip the Path - Find Your Career Trail
mkilby
1
170
Embracing the Ebb and Flow
colly
88
5.1k
Raft: Consensus for Rubyists
vanstee
141
7.6k
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.7k
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
440
Paper Plane (Part 1)
katiecoart
PRO
1
9.9k
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
740
Navigating the moral maze — ethical principles for Al-driven product design
skipperchong
2
430
Transcript
Безопасность аутентификации веб-приложений Сергей Нартымов Brainspec https://github.com/lest twitter: @just_lest
None
Хэш с солью
None
Хэш с солью create_table :users do |t| t.string :name t.string
:salt t.string :hashed_password end
Хэш с солью 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
Хэш с солью 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 user end
has_secure_password
create_table :users do |t| t.string :name t.string :password_digest end class
User < ActiveRecord::Base has_secure_password end
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
bcrypt
bcrypt $2a$10$vI8aWBnW3fID.ZQ4/z идентификатор алгоритма
bcrypt $2a$10$vI8aWBnW3fID.ZQ4/zo1G сложность
bcrypt $2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps соль
bcrypt o1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa
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
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
bcrypt
PBKDF2 scrypt bcrypt
PBKDF2 scrypt bcrypt
Инвалидация сессии
Инвалидация сессии 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_password end
Блокировка доступа
Блокировка доступа • для пользователя • для IP-адреса
Блокировка доступа • CAPTCHA • разблокировка по ссылке из письма
Запомнить меня
Запомнить меня • добавляем токен и время • храним токен
в 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
Перебор пользователей
• Неверный адрес 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) end end
Тайминговые атаки user = User.last Benchmark.realtime { user.valid_password?('lolwut') } #
=> 0.321346
Восстановление пароля • не стоит генерировать пароль и присылать его
на почту • лучше генерировать токен и отправлять ссылку, по которой можно задать новый пароль
Сложность пароля
Сложность пароля 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 Двухэтапная аутентификация
Open Web Application Security Project • https://www.owasp.org/ • https://www.owasp.org/index.php/ Cheat_Sheets
Спасибо https://github.com/lest twitter: @just_lest Сергей Нартымов Brainspec