ホームページ >バックエンド開発 >PHPチュートリアル >開発者セキュリティ ガイド: ユーザー パスワードを安全に保存する方法
まず、暗号の概念と使用法に精通していない場合、または暗号に関するガイダンスが必要な場合は、このコンテンツを読むことをお勧めします。
安全性に関する推奨事項にも有効期限があるべきであることは以前に明らかにしました。したがって、これまでに公開したほとんどのブログ投稿とは異なり、上記のコンテンツは実際には「継続的に更新」されており、セキュリティのニーズが変化し、新しい攻撃形態が発見されると、それに応じて変更に対応します。
ここで、パスワード セキュリティの観点を提案します。プレーン テキストのパスワードを保存せず、パスワードのハッシュ値を保存します。
実際、安全なパスワード ハッシュの生成は非常に簡単になりました。
しかし、ここで問題が発生します。このアカウントとパスワードを通じて、他の人があなたのプログラムにログインできるようにする必要があるかもしれません。
この問題の解決策も非常に簡単です - libsodium を使用します。ほとんどの言語に安全なパスワード ハッシュ API を提供します。バージョン 1.0.8 より前は scrypt アルゴリズムを使用していましたが、バージョン 1.0.9 からは、ハッシュ化されたパスワードの最近の比較から慎重に選択されたアルゴリズムである Argon2 も提供します。 Libsodium は、ほとんどのプログラミング言語にバインディングを提供します。
Libsodium ファイル
Libsodium ソース コード
注: Argon2i (Argon2 ユニバーサル パスワード ハッシュのバリアント表現) に対する攻撃がここで発表されます。実際にはその影響は深刻ではありませんが、新しい亜種につながる可能性があります (これらの攻撃を軽減するためにメモリを上書きする代わりに XOR を使用する可能性があるため、おそらく Argon2x)。
さまざまな理由で libsodium のインストールと要件を調和させることができない場合は、他の選択肢があります。このブログを準備するにあたり、私たちのチームは複数のプログラミング言語でいくつかのパスワード ハッシュ ライブラリを研究しました。ここではサンプル コードを使用してそれらを紹介します。
現在受け入れられているパスワード ハッシュ アルゴリズムは次のとおりです:
パスワード ハッシュ コンペティションの勝者である Argon2
bcrypt
scrypt
およびパスワード ハッシュ コンペティションに参加しているその他のアルゴリズム (Catena、Lyra2、Makwa、yescrypt)
PBKDF2 最悪の選択肢
まず、使用しているバージョンが PHP をサポートしているかどうかを確認してください。サポートされている場合、PHP パスワード API が使用できるようになります。サポートされていない場合は、アップグレードを試みてください。それでも動作しない場合は、password_compat を確認してください。
うわーどうやら、password_hash() はソルト付きハッシュ値を使用しているようです。実際の状況に応じて調整してください。ハードウェアがサポートしている場合は、絶対値の最小値 10.12 を使用するのが適切です。デフォルトは 10 です。
$hash = password_hash($userPassword, PASSWORD_DEFAULT);
実際、パスワードのハッシュされたストレージを検証するのは非常に簡単です:
$hash = password_hash($userPassword, PASSWORD_DEFAULT, ['cost' => 12]);
PHP7 では、PASSWORD_DEFAULT は依然として bcrypt を使用します。将来のバージョンでは、徐々に Argon2 になる可能性があります
libsodium にアクセスできない場合でも (もちろんアクセスすることを強くお勧めします)、PHP で暗号化ハッシュを使用できます。 Dominic Black の PECL からの Scrypt PHP 拡張機能。
そうです次に、PHP ラッパーをプロジェクトにバンドルします。
if (password_verify($userPassword, $hash)) { // Login successful. if (password_needs_rehash($userPassword, PASSWORD_DEFAULT, ['cost' => 12])) { // Recalculate a new password_hash() and overwrite the one we stored previously }}
libsodium に加えて、bcrypt パスワード ハッシュ アルゴリズムを提供できる jBCrypt もあります。
#If you don't have PECL installed, get that first.pecl install scryptecho "extension=scrypt.so" > /etc/php5/mods-available/scrypt.iniphp5enmod scrypt
Java で bcrypt ハッシュを検証します:
# Hashing$hash = \Password::hash($userProvidedPassword);# Validationif (\Password::check($userProvidedPassword, $hash)) { // Logged in successfully.}
scrypt の Java 実装がありますが、パラメータを指定する必要があり、デフォルト値は提供されません。
String hash = BCrypt.hashpw(userProvidedPassword, BCrypt.gensalt());
PBKDF2-SHA1 である System.Security.Cryptography.Rfc2898DeriveBytes の代わりに Martin Steel の BCrypt.NET フォークをお勧めします (PBKDF2 ではありません) -SHA1 は安全ではありませんが、bcrypt の方が比較的優れています
if (BCrypt.checkpw(userProvidedPassword, hash)) { // Login successful.}
NuGET には Scrypt パッケージもあります
# Calculating a hashint N = 16384;int r = 8;int p = 1;String hashed = SCryptUtil.scrypt(passwd, N, r, p);# Validating a hashif (SCryptUtil.check(passwd, hashed)) { // Login successful}
いつものように。 、これは bcrypt パスワード ハッシュ用の Ruby gem です
// Calculating a hashstring hash = BCrypt.HashPassword(usersPassword, BCrypt.GenerateSalt());// Validating a hashif (BCrypt.Verify(usersPassword, hash)) { // Login successful}
この記事の公開時点では、このライブラリはまだ暗号化エンコードのベスト プラクティスに従っていないことに注意してください。そのため、これを考慮する必要があります。パッチする時間
rubyの2番目のオプションAPI の名前が間違っているにもかかわらず (「ハッシュ」ではなく「暗号化」)、Python 開発者は通常 passlib (Bitbucket) を好みます。
from passlib.hash import bcrypt# Calculating a hashhash = bcrypt.encrypt(usersPassword, rounds=12)# Validating a hashif bcrypt.verify(usersPassword, hash): # Login successful
目前我们发现除了libsodium以外只有 django-scrypt package .可以较为健全的实现。其他的我们还在寻找中。
在Node.js上bcrypt( https://www.npmjs.com/package/bcrypt)有两种安全的实现方式,尽管bcrypt看起来是首选。
在下面的例子中,我们大量的使用了Promises来简化错误处理:
var Promise = require("bluebird");var bcrypt = Promise.promisifyAll(require("bcrypt"));function addBcryptType(err) { // Compensate for `bcrypt` not using identifiable error types err.type = "bcryptError"; throw err;}// Calculating a hash:Promise.try(function() { return bcrypt.hashAsync(usersPassword, 10).catch(addBcryptType);}).then(function(hash) { // Store hash in your password DB.});// Validating a hash:// Load hash from your password DB.Promise.try(function() { return bcrypt.compareAsync(usersPassword, hash).catch(addBcryptType);}).then(function(valid) { if (valid) { // Login successful } else { // Login wrong }});// You would handle errors something like this, but only at the top-most point where it makes sense to do so:Promise.try(function() { // Generate or compare a hash here}).then(function(result) { // ... some other stuff ...}).catch({type: "bcryptError"}, function(err) { // Something went wrong with bcrypt});
我们推荐 scrypt for humans,这是一个对开发人员很友好的 node-scrypt 包装器,非常容易使用。
var Promise = require("bluebird");var scrypt = require("scrypt-for-humans");// Calculating a hash:Promise.try(function() { return scrypt.hash(usersPassword);}).then(function(hash) { // Store hash for long term use});// Validating a hash:Promise.try(function() { return scrypt.verifyHash(usersPassword, hash);}).then(function() { // Login successful}).catch(scrypt.PasswordError, function(err) { // Login failed});
*原文地址: paragonie ,东二门陈冠希/编译 0xroot后期整理,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)