devise tree
by Tiago Alves
由蒂亞戈·阿爾維斯(Tiago Alves)
Devise如何確保您的Rails應用密碼安全 (How Devise keeps your Rails app passwords safe)
Devise is an incredible authentication solution for Rails with more than 40 million downloads. However, since it abstracts most of the cryptographic operations, it’s not always easy to understand what’s happening behind the scenes.
Devise是Rails令人難以置信的身份驗證解決方案, 下載量超過4000萬 。 但是,由于它抽象了大多數密碼操作,因此了解幕后發生的事情并不總是那么容易。
One of those abstractions culminates in the persistence of an encrypted_password
directly on the database. So I’ve always been curious about what it actually represents. Here’s an example:
這些抽象之一最終導致直接在數據庫上encrypted_password
了password_password。 因此,我一直對它真正代表什么感到好奇。 這是一個例子:
$2a$11$yMMbLgN9uY6J3LhorfU9iuLAUwKxyy8w42ubeL4MWy7Fh8B.CH/yO
$2a$11$yMMbLgN9uY6J3LhorfU9iuLAUwKxyy8w42ubeL4MWy7Fh8B.CH/yO
But what does that gibberish mean?
但是那胡言亂語是什么意思呢?
Devise uses Bcrypt to securely store information. On its website it mentions that it uses “OpenBSD bcrypt() password hashing algorithm, allowing you to easily store a secure hash of your users’ passwords”. But what exactly is this hash? How does it work and how does it keep stored passwords safe?
Devise使用Bcrypt安全地存儲信息。 它在其網站上提到它使用“ OpenBSD bcrypt()密碼哈希算法,使您可以輕松地存儲用戶密碼的安全哈希 ”。 但是這個哈希到底是什么? 它是如何工作的以及如何確保存儲的密碼安全?
That’s what I want to show you today.
那就是我今天想告訴你的。
Let’s work backwards — from the stored hash on your database to the encryption and decryption process.
讓我們倒退一下-從數據庫上存儲的哈希到加密和解密過程。
That hash $2a$11$yMMbLgN9uY6J3LhorfU9iuLAUwKxyy8w42ubeL4MWy7Fh8B.CH/yO
is actually comprised of several components:
哈希$2a$11$yMMbLgN9uY6J3LhorfU9iuLAUwKxyy8w42ubeL4MWy7Fh8B.CH/yO
實際上由幾個組成部分組成:
Bcrypt version (
2a
) - the version of the bcrypt() algorithm used to produce this hash (stored after the first$
sign)Bcrypt版本 (
2a
)-用于產生此哈希值的bcrypt()算法的版本(存儲在第一個$
符號之后)Cost (
11
) - the cost factor used to create the hash (stored after the second$
sign)成本 (
11
)-用于創建哈希的成本因子(存儲在第二個$
符號之后)Salt (
$2a$11$yMMbLgN9uY6J3LhorfU9iu
) - a random string that when combined with your password makes it unique (first 29 characters)Salt (
$2a$11$yMMbLgN9uY6J3LhorfU9iu
)-一個隨機字符串,與您的密碼結合使用時會使其唯一(前29個字符)Checksum (
LAUwKxyy8w42ubeL4MWy7Fh8B.CH/yO
) - the actual hash portion of the storedencrypted_password
(remaining string after the 29 chars)校驗和 (
LAUwKxyy8w42ubeL4MWy7Fh8B.CH/yO
) -所存儲的實際的哈希部encrypted_password
(29個字符之后剩余字符串)
Let’s explore the last 3 parameters:
讓我們探索最后三個參數:
When using Devise, the
Cost
value is set by a class variable called stretches and the default value is11
. It specifies the number of times the password is hashed. (On your devise.rb initializer, you can configure this to a lower value for the test environment to make your test suite run faster.) *使用Devise時,
Cost
值由一個稱為stretchs的類變量設置,默認值為11
。 它指定密碼被哈希的次數。 ( 在devise.rb初始化程序上 ,可以將其配置為測試環境的較低值,以使測試套件運行更快。 )The salt is the random string used to combine with the original password. This is what makes the same password have different values when stored encrypted. (See more below about why that matters and what are Rainbow Table Attacks.) **
鹽是用于與原始密碼組合的隨機字符串。 這就是在加密存儲時使同一密碼具有不同值的原因。 ( 請參閱下面的更多內容,以了解為何如此重要以及什么是Rainbow Table Attack 。)**
The checksum is the actual generated hash of the password after being combined with the random salt.
校驗和是密碼與隨機鹽組合后實際生成的哈希值。
When a user registers on your app, they must set a password. Before this password is stored in the database, a random salt is generated via BCrypt::Engine.generate_salt(cost) by taking into account the cost factor previously mentioned. (Note: if the pepper
class variable value is set it will append its value to the password before salting it.)
用戶在您的應用上注冊時,必須設置密碼。 在將此密碼存儲在數據庫中之前,考慮到前面提到的成本因素,會通過BCrypt :: Engine.generate_salt(cost)生成隨機鹽。 (注意:如果設置了pepper
類變量值 ,它將在鹽腌之前將其值附加到密碼上 。)
With that salt (ex. $2a$11$yMMbLgN9uY6J3LhorfU9iu
, which includes the cost factor) it will call BCrypt::Engine.hash_secret(password, salt) that computes the final hash to be stored using the generated salt and the password selected by the user. This final hash (for example, $2a$11$yMMbLgN9uY6J3LhorfU9iuLAUwKxyy8w42ubeL4MWy7Fh8B.CH/yO
) will in turn be stored in the encrypted_password
column of the database.
使用該鹽(例如$2a$11$yMMbLgN9uY6J3LhorfU9iu
,其中包括成本因素),它將調用BCrypt :: Engine.hash_secret(password,salt) ,使用生成的鹽和由密碼選擇的密碼來計算要存儲的最終哈希用戶。 此最終散列(例如, $2a$11$yMMbLgN9uY6J3LhorfU9iuLAUwKxyy8w42ubeL4MWy7Fh8B.CH/yO
)將被依次存儲在encrypted_password
數據庫的列。
But if this hash is nonreversible and the salt is randomly generated on the BCrypt::Password.create
call by BCrypt::Engine.generate_salt(cost)
, how can it be used to sign in the user?
但是,如果此哈希不可逆并且鹽在BCrypt::Engine.generate_salt(cost)
的BCrypt::Password.create
調用中隨機生成, 如何將其用于登錄用戶?
That’s where those different hash components are useful. After finding the record that matches the email supplied by the user to sign in, the encrypted password is retrieved and broken down into the different components mentioned above (Bcrypt version, Cost, Salt and Checksum).
那是那些不同的哈希組件有用的地方。 找到與用戶提供的用于登錄的電子郵件匹配的記錄后,將檢索加密的密碼并將其分解為上述不同的組成部分( Bcrypt版本 , Cost , Salt和Checksum )。
After this initial preparation, here’s what happens next:
初步準備之后,接下來將發生以下情況:
Fetch the input password (
1234
)獲取輸入的密碼 (
1234
)Fetch the salt of the stored password (
$2a$11$yMMbLgN9uY6J3LhorfU9iu
)獲取存儲的密碼的鹽 (
$2a$11$yMMbLgN9uY6J3LhorfU9iu
)Generate the hash from the password and salt using the same bcrypt version and cost factor (
BCrypt::Engine.hash_secret(“1234”, “$2a$11$yMMbLgN9uY6J3LhorfU9iu”)
)使用相同的bcrypt版本和成本因子(
BCrypt::Engine.hash_secret(“1234”, “$2a$11$yMMbLgN9uY6J3LhorfU9iu”)
從密碼和salt生成哈希 。Check if the stored hash is the same one as the computed on step 3 (
$2a$11$yMMbLgN9uY6J3LhorfU9iuLAUwKxyy8w42ubeL4MWy7Fh8B.CH/yO
)檢查存儲的哈希值是否與步驟3上計算的哈希值相同(
$2a$11$yMMbLgN9uY6J3LhorfU9iuLAUwKxyy8w42ubeL4MWy7Fh8B.CH/yO
)
And that’s how Devise stores passwords securely and protects you from a range of attacks even if your database is compromised.
這樣一來,即使數據庫受到威脅,Devise仍可以安全地存儲密碼并保護您免受一系列攻擊。
Get in touch on Twitter @alvesjtiago and let me know if you found this article interesting! Thank you for reading.
在Twitter @alvesjtiago上保持聯系,如果您發現本文有趣,請告訴我! 感謝您的閱讀。
PS: I’m by no means a security or cryptography expert so please do reach out if you find something wrong. I’m hoping that by simplifying some of the concepts it will be easier to understand what’s happening.
PS:我絕不是安全或加密專家,所以如果發現錯誤,請務必與我們聯系。 我希望通過簡化一些概念,可以更輕松地了解正在發生的事情。
Thank you @filipepina, @ivobenedito, @jackveiga, @joao_mags and @pedrosmmoreira for the reviews and suggestions. This article is also available at http://blog.tiagoalves.me/how-does-devise-keep-your-passwords-safe.
感謝@filipepina , @ivobenedito , @jackveiga , @joao_mags和@pedrosmmoreira的評論和建議。 本文也可以從http://blog.tiagoalves.me/how-does-devise-keep-your-passwords-safe獲得 。
More information about some of the topics.
有關某些主題的更多信息。
Cost factor *
成本因素*
Perils of the default bcrypt cost factor
默認bcrypt成本因素的風險
Recommended number of rounds for bcrypt
建議的bcrypt輪數
Rainbow Table Attacks **
彩虹桌攻擊**
Rainbow table — Wikipedia
彩虹桌—維基百科
What are rainbow tables and how are they used?
什么是彩虹桌,如何使用?
翻譯自: https://www.freecodecamp.org/news/how-does-devise-keep-your-passwords-safe-d367f6e816eb/
devise tree