-
Notifications
You must be signed in to change notification settings - Fork 0
sha256 password before passing to bcrypt to avoid issues with 72 bytes truncation for passwords #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…s truncation for passwords
Greptile OverviewGreptile SummaryThis PR successfully addresses a critical security vulnerability in bcrypt where passwords longer than 72 bytes are silently truncated, allowing different passwords to authenticate as the same user. The fix applies SHA256 hashing to passwords before bcrypt, ensuring all passwords are reduced to a consistent 64-character hex string (well under the 72-byte limit). Key changes:
The implementation is sound and maintains backward compatibility by trying the new SHA256 approach first, then falling back to the original direct bcrypt method for existing user passwords. Confidence Score: 4/5
Important Files ChangedFile Analysis
Sequence DiagramsequenceDiagram
participant User
participant Devise
participant Encryptor
participant SHA256
participant BCrypt
Note over User,BCrypt: Password Registration (New)
User->>Devise: Set password
Devise->>Encryptor: digest(klass, password)
Encryptor->>Encryptor: Apply pepper if present
Encryptor->>SHA256: hexdigest(password+pepper)
SHA256-->>Encryptor: 64-char hex string
Encryptor->>BCrypt: create(hex_string)
BCrypt-->>Encryptor: hashed_password
Encryptor-->>Devise: encrypted_password
Note over User,BCrypt: Password Validation (New Hash)
User->>Devise: Login with password
Devise->>Encryptor: compare(klass, hash, password)
Encryptor->>Encryptor: Apply pepper if present
Encryptor->>SHA256: hexdigest(password+pepper)
SHA256-->>Encryptor: 64-char hex string
Encryptor->>BCrypt: hash_secret(hex_string, salt)
BCrypt-->>Encryptor: new_style_hash
Encryptor->>Encryptor: secure_compare(new_style_hash, stored_hash)
Encryptor-->>Devise: true/false
Note over User,BCrypt: Password Validation (Old Hash - Fallback)
User->>Devise: Login with password
Devise->>Encryptor: compare(klass, hash, password)
Encryptor->>Encryptor: Apply pepper if present
Encryptor->>SHA256: hexdigest(password+pepper)
SHA256-->>Encryptor: 64-char hex string
Encryptor->>BCrypt: hash_secret(hex_string, salt)
BCrypt-->>Encryptor: new_style_hash
Encryptor->>Encryptor: secure_compare(new_style_hash, stored_hash)
Note right of Encryptor: Returns false (old format)
Encryptor->>BCrypt: hash_secret(password+pepper, salt)
BCrypt-->>Encryptor: old_style_hash
Encryptor->>Encryptor: secure_compare(old_style_hash, stored_hash)
Encryptor-->>Devise: true/false
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 files reviewed, no comments
| test 'digest/compare support old bcrypt only passwords' do | ||
| password = 'example' | ||
| password_with_pepper = "#{password}#{Devise.pepper}" | ||
| old_hashed_password =::BCrypt::Password.create(password_with_pepper, cost: Devise.stretches) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@greptile 修正しなきゃいけない行ってここで合ってますか?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
はい、その通りです。26行目が修正が必要な行で合っています。
この行では、古いbcryptのみのパスワード(SHA256ハッシュを使わない従来の方式)をテストするために、直接BCrypt::Password.createを呼び出しています。
新しい実装では、Devise::Encryptorが内部でSHA256ハッシュを適用してからbcryptを使用するように変更されているので、古い形式のハッシュとの後方互換性をテストする必要があります。
この行は意図的に古い方式(SHA256を使わずに直接bcryptを適用)でパスワードハッシュを生成することで、既存のユーザーのパスワードが新しいシステムでも正しく検証できることを確認するためのテストケースです。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test/encrytor_test.rb needs minor syntax correction on line 26 ってコメントくれたけど、どんな変更が必要?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
26行目の構文エラーは、::BCryptの前にスペースが不要なことです。
| old_hashed_password =::BCrypt::Password.create(password_with_pepper, cost: Devise.stretches) | |
| old_hashed_password = ::BCrypt::Password.create(password_with_pepper, cost: Devise.stretches) |
=の後の不要なスペースを削除するだけで修正できます。
More info: bcrypt-ruby/bcrypt-ruby#283
Reproduction:
BCrypt::Password.new(BCrypt::Password.create('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1')) == 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2'
BCrypt::Password.new(BCrypt::Password.create('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1')) == 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa222333'
BCrypt::Password.new(BCrypt::Password.create('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1')) == 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa222333234234324'
All return true, so
Password 1: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1
Password 2: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2
These two users can login to each other's accounts because brcypt caps hashing to the first 72 bytes.
In this case we can reject heartcombo#5806