PHPパスワードの安全なハッシュとソルト


1174

現在、MD5は部分的に安全ではないと言われています。これを考慮して、パスワード保護に使用するメカニズムを知りたいのですが。

この質問は、「ダブルハッシュ」は1回だけハッシュするよりも安全性が低いですか。 複数回のハッシュが良い考えかもしれないが、個々のファイルにパスワード保護を実装する方法は?塩の使用を提案しています。

PHPを使用しています。安全で高速なパスワード暗号化システムが必要です。パスワードを100万回ハッシュする方が安全な場合がありますが、速度も遅くなります。速度と安全性のバランスをどのようにして実現するのですか?また、結果の文字数が一定であることを望みます。

  1. ハッシュメカニズムがPHPで使用可能である必要があります
  2. 安全である必要があります
  3. 塩を使用できます(この場合、すべての塩が同等に良いですか?良い塩を生成する方法はありますか?)

また、データベースに2つのフィールドを保存する必要がありますか(たとえば、1つはMD5を使用し、もう1つはSHAを使用)。それはそれをより安全または安全ではないでしょうか?

私が十分に明確でない場合は、安全で高速なパスワード保護メカニズムを実現するために、使用するハッシュ関数と適切なソルトを選択する方法を知りたいです。

私の質問を完全にカバーしない関連質問:

PHPのSHAとMD5の違いは何ですか?
単純なパスワード暗号化
キー、asp.netのパスワードを保存する安全な方法Tomcat 5.5 でソルトパスワードを
どのように実装しますか


13
openwall.com/phpassも非常に優れたライブラリです
Alfred

51
Md5は完全に安全ではなくなりました
JqueryToAddNumbers

3
@NSAwesomeGuyそれはあなたがそれを何のために使っているかに依存します。レインボーマッチやソルトされていないMD5パスワードをブルートフォースにするのは簡単ですが、適切なソルト処理を行うと、レインボーテーブルを作成してパスワードのセットを高速にクラックすることは非常に非現実的であり、ブルートフォースを使用することはできません。
クレイグリンガー


回答:


982

免責事項:この回答は2008年に書かれました。

それ以来、PHPは私たちpassword_hashpassword_verifyし、その紹介以来、それらは推奨されるパスワードのハッシュとチェックの方法です。

答えの理論はまだ良い読みです。

TL; DR

しない

  • ユーザーがパスワードに入力できる文字を制限しないでください。馬鹿だけがこれを行います。
  • パスワードの長さを制限しないでください。ユーザーがsupercalifragilisticexpialidociousを含む文を必要とする場合は、使用を妨げないでください。
  • パスワードのHTMLや特殊文字を取り除いたりエスケープしたりしないでください。
  • ユーザーのパスワードをプレーンテキストで保存しないでください。
  • ユーザーがパスワードを紛失して、一時的なパスワードを送信した場合を除いて、ユーザーにパスワードを電子メールで送信しないでください
  • 決して、決してパスワードをログに記録しないでください。
  • SHA1またはMD5、さらにはSHA256でパスワードをハッシュしないでください!現代のクラッカーは、(それぞれ)60および1,800億ハッシュ/秒を超える可能性があります。
  • bcryptとhash()の生の出力を混在させないでください。16進出力を使用するか、base64_encodeを使用してください。(これは、\0セキュリティが大幅に低下する可能性のある不正が含まれている可能性があるすべての入力に適用されます。)

ドス

  • 可能な場合はscryptを使用してください。できない場合はbcrypt。
  • SHA2ハッシュでbcryptまたはscryptを使用できない場合は、PBKDF2を使用します。
  • データベースが危険にさらされたときに全員のパスワードをリセットします。
  • 妥当な8-10文字の最小長を実装し、さらに、少なくとも1つの大文字、1つの小文字、数字、および記号を必要とします。これにより、パスワードのエントロピーが向上し、クラックが困難になります。(いくつかの議論については、「何が良いパスワードを作るのか?」セクションを参照してください。)

とにかくパスワードをハッシュするのはなぜですか?

パスワードのハッシュの目的は単純です。データベースを危険にさらすことにより、ユーザーアカウントへの悪意のあるアクセスを防止します。したがって、パスワードハッシュの目標は、プレーンテキストのパスワードを計算するのに時間やお金がかかりすぎることで、ハッカーやクラッカーを阻止することです。そして、時間/コストはあなたの武器の最高の抑止力です。

ユーザーアカウントに適切で堅牢なハッシュが必要なもう1つの理由は、システム内のすべてのパスワードを変更するのに十分な時間を与えるためです。データベースが危険にさらされている場合、データベースのすべてのパスワードを変更しない場合でも、少なくともシステムをロックダウンするのに十分な時間が必要です。

Whitehat SecurityのCTOであるJeremiah Grossman がWhite Hat Securityのブログで、パスワード保護のブルートフォースでの破壊を必要とした最近のパスワード回復について述べています。

興味深いことに、この悪夢を生き抜くことで、パスワードの解読、保存、複雑さについては知らなかったたくさんのことを学びました。パスワードの保存が、パスワードの複雑さよりもはるかに重要である理由を理解するようになりました。パスワードの保存方法がわからない場合、本当に頼りになるのは複雑さだけです。これは、パスワードと暗号の専門家には一般的な知識かもしれませんが、平均的なInfoSecまたはWebセキュリティの専門家にとっては、私はそれを非常に疑っています。

(エンファシス鉱山。)

とにかく良いパスワードを作るものは何ですか?

エントロピー。(私がRandallの見解に完全に同意しているわけではありません。)

つまり、エントロピーとは、パスワード内の変動量です。パスワードが小文字のローマ字のみの場合、それは26文字だけです。それはあまり変化ではありません。英数字パスワードの方がよく、36文字です。ただし、記号を使用して大文字と小文字を区別できるのは、およそ96文字です。それは単なる文字よりもはるかに優れています。1つの問題は、パスワードを覚えやすくするために、パターンを挿入することです。これにより、エントロピーが減少します。おっとっと!

パスワードエントロピーは概算です簡単にできます。ascii文字の全範囲(約96の入力可能な文字)を使用すると、1文字あたり6.6のエントロピーが得られます。これは、パスワードの8文字では、将来のセキュリティにはまだ低すぎる(52.679ビットのエントロピー)です。しかし、朗報です。長いパスワード、およびUnicode文字を含むパスワードは、パスワードのエントロピーを実際に増加させ、解読を困難にします。

Crypto StackExchangeサイトには、パスワードエントロピーに関するより長い議論があります。優れたGoogle検索でも多くの結果が表示されます。

私が@popnoodlesと話したコメントで、Xの長さのパスワードポリシーをX個の文字、数字、記号などで強制すると、パスワードスキームをより予測可能にして実際にエントロピーを減らすことができると指摘しました。私は同意しますよ。Randomessは、可能な限り真にランダムであり、常に最も安全ですが最も記憶に残る解決策です。

私が知る限り、世界最高のパスワードを作成するのはCatch-22です。覚えにくい、予測し難い、短すぎる、Unicode文字が多すぎる(Windows /モバイルデバイスでは入力が難しい)、長すぎるなどのいずれかです。私たちの目的には本当に十分なパスワードがないため、パスワードを保護する必要があります。フォートノックスにいた。

ベストプラクティス

Bcryptとscryptは現在のベストプラクティスです。Scryptは時間の経過とともにbcryptよりも優れていますが、Linux / UnixやWebサーバーによる標準としての採用は見られておらず、そのアルゴリズムの詳細なレビューはまだ投稿されていません。しかし、それでも、アルゴリズムの将来は有望に見えます。Rubyを使用している場合は、scrypt gemが役立ちます。Node.jsには、独自のscryptパッケージがあります。PHPでScryptを使用するには、Scrypt拡張機能またはLibsodium拡張機能を使用します(どちらもPECLで使用できます)。

bcryptの使用方法を理解したい場合、またはより良いラッパーを見つけたり、よりレガシーな実装にPHPASSのようなものを使用したりする場合は、crypt関数のドキュメントを読むことを強くお勧めします。15から18ではないにしても、最低12ラウンドのbcryptをお勧めします。

bcryptは、コストメカニズムが可変で、blowfishのキースケジュールのみを使用することを知ったとき、bcryptの使用に関する考え方を変更しました。後者では、blowfishのすでに高価なキースケジュールを増やすことにより、パスワードを総当たりにするコストを増やすことができます。

平均的な慣行

このような状況はもうほとんど想像できません。PHPASSはPHP 3.0.18から5.3をサポートしているため、考えられるほとんどすべてのインストールで使用できます。また、環境がbcryptをサポートしているどうか不明な場合は、使用する必要があります。

ただし、bcryptやPHPASSをまったく使用できないとします。それで?

実装試しPDKBF2をしてラウンドの最大数は、ご使用の環境/アプリケーション/ユーザーの認識が許容できます。私がお勧めする最低数は2500ラウンドです。また、操作の再現を困難にすることが可能な場合は、hash_hmac()を使用してください

今後の実践

PHP 5.5で登場するのは、bcryptでの作業の苦痛を取り除く完全なパスワード保護ライブラリです。私たちのほとんどは、ほとんどの一般的な環境、特に共有ホストでPHP 5.2と5.3を使い続けていますが、@ ircmaxellは、PHP 5.3.7と下位互換性のあるAPIの互換性レイヤーを構築しています。

暗号の要約と免責事項

ハッシュされたパスワードを実際に解読するために必要な計算能力は存在しません。コンピュータがパスワードを「解読」する唯一の方法は、パスワードを再作成して、パスワードを保護するために使用されるハッシュアルゴリズムをシミュレートすることです。ハッシュの速度は、ブルートフォースされる能力と線形的に関連しています。さらに悪いことに、ほとんどのハッシュアルゴリズムは簡単に並列化してさらに高速に実行できます。これが、bcryptやscryptなどのコストのかかるスキームが非常に重要である理由です。

あなたはおそらく攻撃のすべての脅威や道を予見することはできません、ので、あなたのユーザーを保護するためにあなたの最善の努力しなければなりませんフロントアップ。そうしないと、手遅れになるまで攻撃されたという事実を見逃す可能性があります ... そしてあなたは責任を負います。そのような状況を回避するには、まずは偏執的な行動をとります。自分のソフトウェアを(内部で)攻撃し、ユーザーの資格情報を盗んだり、他のユーザーのアカウントを変更したり、データにアクセスしたりしようとします。システムのセキュリティをテストしないと、自分以外の誰かを責めることはできません。

最後に、私は暗号学者ではありません。私が言ったことは私の意見ですが、私はたまたまそれが良識の常識に基づいていると思います...そしてたくさんの読書。できるだけ偏執狂的で、侵入をできるだけ難しくすることを忘れないでください。それでも心配な場合は、ハットハッカーまたは暗号技術者に連絡して、コード/システムについて彼らが何を言っているかを確認してください。


9
パスワードDBはとにかく秘密であるはずなので、秘密は役に立ちません-彼らがそのDBを手に入れることができれば、彼らはあなたが使っているどんな秘密も見つけることができます。ただし、塩はランダムであることが重要です。
frankodwyer 2008

2
「解読するための計算能力」がまだ存在していないことは実際には真実ではないことに注意してください。ほとんどのパスワードは辞書の単語または辞書から派生したものであるため、通常、辞書ベースの攻撃は非常に効果的です(したがって、パスワードポリシーと反復回数の使用)。
frankodwyer 2008

6
@邪悪なノミ、私はあなたと議論していません。私たちの仕事のこの領域がいかに複雑で複雑であるかを指摘するだけです。私は、小さなWebサイトのコンテンツ管理システムをセットアップするための、結局のところすべてが最もスマートでベストプラクティスになることを期待しています。私はまだここで学んでいます。...意味のあるものを読むたびに、それと矛盾する他の5つの投稿にすぐに気づきます。ぐるぐる回るとめまいがします:)
m42 2009年

4
興味深い改訂。ユーザーID(たとえば、自動インクリメントBIGINT)は適切なナンスですか?それともランダムではないので良くありませんか?また、各ユーザーのnonceをデータベースに保存する必要があります...サイトキー+ nonce + HMACは、salted(ユーザーID付き)ハッシュを複数回反復することでセキュリティを大幅に向上させますか?同様に、HMACを複数回繰り返すと、セキュリティに優れていますか?
luiscubal 2010

4
ユーザーが初めて使用するときにパスワードを変更する必要のある一時的なパスワードを電子メールで送信することと、パスワードを設定できるようにする電子メールで「安全な」リンクを送信することも同様に危険です。どちらの場合でも、電子メールを傍受した人は、目的の受信者がアクセスする前にリンクまたはパスワードを使用する限り、アカウントにアクセスできます。
Tim Gautier、2012

138

はるかに短く安全な答え- 独自のパスワードメカニズムをまったく作成せず、実証済みのメカニズムを使用してください

  • PHP 5.5以降:password_hash()は良質でPHPコアの一部です。
  • 古いバージョンのPHP:OpenWallのphpassライブラリは、ほとんどのカスタムコードよりもはるかに優れています-WordPress、Drupalなどで使用されます。

ほとんどのプログラマーは、脆弱性を導入せずに暗号関連のコードを安全に作成する専門知識を持っていません。

クイックセルフテスト:パスワードストレッチとは何ですか?あなたは答えがわからない場合は、使用する必要がありますpassword_hash()ストレッチパスワードが現在のパスワードメカニズムの重要な特徴であるとして原因はるかに高速CPUとの使用に、GPUをとのFPGAのレートでパスワードクラックする毎秒推測の十億のGPUと( )。

たとえば、5台のデスクトップPCにインストールされた25個のGPUを使用すると、8文字のWindowsパスワードすべてを6時間で解読できます。これはブルートフォースです。つまり、特殊文字を含むすべての8文字のWindowsパスワードを列挙およびチェックするものであり、辞書攻撃ではありません。それは2012年でしたが、2018年の時点で、使用するGPUの数を減らすか、25個のGPUでクラックを速くすることができました。

また、通常のCPUで実行され、非常に高速なWindowsパスワードへの多数のレインボーテーブル攻撃があります。Windowsがあるためこのすべては、まだ 塩またはストレッチしない、そのパスワードをしてもWindowsの10にマイクロソフトがやったのと同じ間違いをしないでください- !

以下も参照してください。

  • 理由についての優れた回答password_hash()またはphpass最善の方法です。
  • bcrypt、scrypt、PBKDF2などの主要なアルゴリズムに推奨される「作業要素」(反復回数)を示す優れたブログ記事

1
しかし、これらのシステムはよく知られており、おそらくすでに侵害されています。しかし、自分が何をしているのかわからないときは、自分で作る方がいいです。
JqueryToAddNumbers

14
「これらのシステムはよく知られており、すでに侵害されている可能性があります」-認証のために適切に設計されたシステムが、すでに知られているという理由だけで「すでに侵害されている」必要がある理由はありません。phpassなどのライブラリは、専門家によって作成され、多くの人々によって詳細にレビューされています。それらがよく知られているという事実は、さまざまな人々による詳細なレビューに沿っており、安全であることを意味する可能性が高くなります。
RichVel

LinkedIn、Last.fmなどからの最近のパスワードハッシュダンプを考えると、これは非常に話題です。あなたは自分のパスワードメカニズムを書く方法を知らないので良い仲間です!
RichVel

3
@PP-NSAバックドアを持つピアレビュー済みパスワードハッシュアルゴリズムの可能性は非常に低いと私は考えています。実際の暗号の専門家ではない誰かが他の脆弱性なしに新しいパスワードハッシュメカニズムを作成する可能性ははるかに低くなります。そして典型的なwebappはMD5またはSHA-1ハッシュのみを使用します。これはひどいです
-Chris

1
@RichVel-password_hash()関数。前述したように、PHPコア(別名/ ext / standard)に組み込まれています。
CubicleSoft 2015年

43

システムは少なくとも使用中のハッシュアルゴリズムの中で最も弱いものと同じくらい弱いため、2つの異なる方法でハッシュされたパスワードを保存しません。


パスワードハッシュ用ではありません。攻撃者は、パスワードを取得するために1つのハッシュを分割するだけで済みます。MD5もSHA1もパスワードシナリオで実用的なブレークを利用できないので、要点はとにかく意味がありません。
frankodwyer 2008

2
申し訳ありませんが、2つのハッシュを使用することをお勧めします。実際は正しいです。2つのハッシュを使用すると、弱いハッシュを壊すだけでよいため、パスワードの場合にシステムが弱くなります。
frankodwyer 2008

40

PHP 5.5以降、PHPにはパスワードのハッシュ化と検証のためのシンプルで安全な関数、password_hash()password_verify()があります。

$password = 'anna';
$hash = password_hash($password, PASSWORD_DEFAULT);
$expensiveHash = password_hash($password, PASSWORD_DEFAULT, array('cost' => 20));

password_verify('anna', $hash); //Returns true
password_verify('anna', $expensiveHash); //Also returns true
password_verify('elsa', $hash); //Returns false

際にpassword_hash()使用され、それは、(使用されるコストおよびアルゴリズムと共に。)ランダム塩を生成し、出力ハッシュに含めpassword_verify()、そのハッシュを読み取り、使用する塩及び暗号化方式を決定し、提供平文パスワードに対する検証を。

の提供 PASSWORD_DEFAULTPHPに、インストールされているバージョンのPHPのデフォルトのハッシュアルゴリズムを使用ように指示します。正確にはどのアルゴリズムが将来のバージョンで時間の経過とともに変更されることを意図しているため、常に最も強力な利用可能なアルゴリズムの1つになります。

コスト(デフォルトでは10)を増やすと、ハッシュの総当たりが難しくなりますが、ハッシュを生成し、それに対するパスワードを検証することは、サーバーのCPUの負荷が大きくなります。

デフォルトのハッシュアルゴリズムは変更される可能性がありますが、使用されるアルゴリズムはハッシュに格納されているため、古いハッシュは引き続き正常に検証されます。 password_verify()それをされます。


33

質問には回答しましたが、ハッシュに使用するソルトはランダムであり、最初の回答で提案されている電子メールアドレスとは異なるものであることを繰り返し述べたいと思います。

詳細については、http: //www.pivotalsecurity.com/blog/password-hashing-salt-should-it-be-random/をご覧ください。

最近、ランダムビットでソルトされたパスワードハッシュが、推測可能なソルトまたは既知のソルトでソルトされたものよりも安全かどうかについて話し合いました。見てみましょう:パスワードを保存するシステムとランダムなソルトを保存するシステムが侵害された場合、攻撃者はソルトだけでなくハッシュにもアクセスできるため、ソルトがランダムかどうかは関係ありません。攻撃者は、事前に計算されたレインボーテーブルを生成してハッシュをクラックすることができます。ここで興味深い部分があります。事前に計算されたテーブルを生成することはそれほど簡単ではありません。WPAセキュリティモデルの例を見てみましょう。WPAパスワードが実際にワイヤレスアクセスポイントに送信されることはありません。代わりに、SSID(Linksys、Dlinkなどのネットワーク名)でハッシュされます。これがどのように機能するかについての非常に良い説明がここにあります。ハッシュからパスワードを取得するために、パスワードとソルト(ネットワーク名)を知っておく必要があります。Church of Wifiは、上位1000のSSIDと約100万のパスワードを持つハッシュテーブルを事前に計算しています。すべてのテーブルのサイズは約40 GBです。あなたのサイトで読むことができるように、誰かが15のFGPAアレイを3日間使用してこれらのテーブルを生成しました。被害者がSSIDを「a387csf3」、パスワードを「123456」として使用しているとすると、これらのテーブルによってクラックされますか?番号!.. できない。パスワードが弱い場合でも、テーブルにはSSID a387csf3のハッシュがありません。これがランダムな塩の美しさです。事前に計算されたテーブルで成功するクラッカーを阻止します。断固としたハッカーを止めることはできますか?おそらく違います。しかし、ランダムな塩を使用すると、追加の防御層が提供されます。このトピックについては、ランダムな塩を別のシステムに保存することの追加の利点について説明します。シナリオ#1:パスワードハッシュはシステムXに格納され、ハッシュに使用されるソルト値はシステムYに格納されます。これらのソルト値は推測可能または既知(例:ユーザー名)シナリオ#2:パスワードハッシュはシステムXに格納され、ソルト値はハッシュはシステムYに格納されます。これらのソルト値はランダムです。ご想像のとおり、システムXが侵害された場合、別のシステムでランダムソルトを使用することには大きなメリットがあります(シナリオ#2)。攻撃者は、ハッシュをクラックするために追加の値を推測する必要があります。32ビットのソルトを使用する場合、推測される各パスワードに対して2 ^ 32 = 4,294,967,296(約42億)の反復が必要になる可能性があります。パスワードハッシュはシステムXに保存され、ハッシュに使用されるソルト値はシステムYに保存されます。これらのソルト値は推測可能または既知(ユーザー名など)シナリオ#2:パスワードハッシュはシステムXに保存され、ハッシュに使用されるソルト値はシステムY。これらのソルト値はランダムです。ご想像のとおり、システムXが侵害された場合、別のシステムでランダムソルトを使用することには大きなメリットがあります(シナリオ#2)。攻撃者は、ハッシュをクラックするために追加の値を推測する必要があります。32ビットのソルトを使用する場合、推測される各パスワードに対して2 ^ 32 = 4,294,967,296(約42億)の反復が必要になる可能性があります。パスワードハッシュはシステムXに保存され、ハッシュに使用されるソルト値はシステムYに保存されます。これらのソルト値は推測可能または既知(ユーザー名など)シナリオ#2:パスワードハッシュはシステムXに保存され、ハッシュに使用されるソルト値はシステムY。これらのソルト値はランダムです。ご想像のとおり、システムXが侵害された場合、別のシステムでランダムソルトを使用することには大きなメリットがあります(シナリオ#2)。攻撃者は、ハッシュをクラックするために追加の値を推測する必要があります。32ビットのソルトを使用する場合、推測される各パスワードに対して2 ^ 32 = 4,294,967,296(約42億)の反復が必要になる可能性があります。これらのソルト値はランダムです。ご想像のとおり、システムXが侵害された場合、別のシステムでランダムソルトを使用することには大きなメリットがあります(シナリオ#2)。攻撃者は、ハッシュをクラックするために追加の値を推測する必要があります。32ビットのソルトを使用する場合、推測される各パスワードに対して2 ^ 32 = 4,294,967,296(約42億)の反復が必要になる可能性があります。これらのソルト値はランダムです。ご想像のとおり、システムXが侵害された場合、別のシステムでランダムソルトを使用することには大きなメリットがあります(シナリオ#2)。攻撃者は、ハッシュをクラックするために追加の値を推測する必要があります。32ビットのソルトを使用する場合、推測される各パスワードに対して2 ^ 32 = 4,294,967,296(約42億)の反復が必要になる可能性があります。


7
攻撃者がソルトを取得した場合でも、「sitesalt:usersalt:password」文字列は、事前計算されたテーブルに対して耐性があります。これは、攻撃者がすべてのユーザーのテーブルを生成する必要があるためです(当然、特定のユーザーを除く)がターゲットにされています...
luiscubal 2010

「攻撃者がソルトを取得したとしても、「sitesalt:usersalt:password」文字列はまだ事前計算されたテーブルに対して耐性がある」と、完全に同意します。私のポイントは、サイトソルトはランダムで長い場合、予測可能である(サイトソルト)よりもシステムをより安全にするということです。電子メールIDなどをソルトとして使用することを推奨している人がいるのを見たことがあります。
Gaurav Kumar

あなたは私が最初に書いたものを逃しました。私は、レコードと一緒に保存されたランダムなナンスに加えてメールアドレスを使用すると述べました。電子メールアドレスの追加により、ハッカーが取り組むエントロピーが追加されます。私はそれ以来bcryptを支持して私の答えを書き直しました。
Robert K

28

PHP 5.5には、ラッパーを提供するパスワードハッシュAPIが含まれていることを指摘しておきますcrypt()。このAPIは、パスワードハッシュのハッシュ、検証、および再ハッシュのタスクを大幅に簡略化します。著者は、PHP 5.3.7以降を使用していて、今すぐ使用したいユーザー向けの互換パック(単一のpassword.phpファイルの形式で)もリリースしましたrequire

現時点ではBCRYPTのみをサポートしていますが、他のパスワードハッシュ手法を含めるように簡単に拡張できることを目指しています。手法とコストはハッシュの一部として保存されるため、好みのハッシュ手法/コストを変更しても現在のハッシュ、フレームワークは無効になりません自動的に、検証時に正しい手法/コストを使用します。また、独自のソルトを明示的に定義しない場合は、「安全な」ソルトの生成も処理します。

APIは4つの関数を公開します。

  • password_get_info() -指定されたハッシュに関する情報を返します
  • password_hash() -パスワードハッシュを作成します
  • password_needs_rehash()-指定されたハッシュが指定されたオプションと一致するかどうかを確認します。ハッシュが現在の手法/コストスキームに準拠しているかどうかを確認するのに役立ち、必要に応じてハッシュを再作成できます。
  • password_verify() -パスワードがハッシュと一致することを確認します

現時点では、これらの関数はPASSWORD_BCRYPTおよびPASSWORD_DEFAULTパスワード定数を受け入れます。これらは現在のところ同義語です。PASSWORD_DEFAULTは、「新しい強力なハッシュアルゴリズムがサポートされている場合、新しいPHPリリースで変更される可能性があります。」ログイン時にPASSWORD_DEFAULTとpassword_needs_rehash()を使用して(必要に応じて再ハッシュして)、ハッシュがブルートフォース攻撃に対して適度に回復力を持ち、ほとんど何もしないようにします。

編集:私はこれがロバートKの答えで簡単に述べられていることに気づきました。この答えは、セキュリティの仕組みがわからない方や、セキュリティがわからない場合の使いやすさについて、もう少し情報が得られると思うので、ここでは残しておきます。


19

私はPhpassを使用しています。これは、ほぼすべてのPHPプロジェクトで非常に簡単に実装できる単純な1ファイルのPHPクラスです。Hも参照してください。

デフォルトでは、Phpassに実装されている利用可能な最も強力な暗号化を使用しました。これはbcrypt、Wordpressなどのフレームワークに下位互換性を提供するために、MD5までの他の暗号化にフォールバックします。

返されたハッシュはそのままデータベースに格納できます。ハッシュを生成するための使用例は次のとおりです。

$t_hasher = new PasswordHash(8, FALSE);
$hash = $t_hasher->HashPassword($password);

パスワードを確認するには、以下を使用できます。

$t_hasher = new PasswordHash(8, FALSE);
$check = $t_hasher->CheckPassword($password, $hash);

14

覚えておくべきこと

PHPのパスワード暗号化については多くのことが言われていますが、そのほとんどは非常に良いアドバイスですが、パスワード暗号化にPHPを使用するプロセスを開始する前に、次のものが実装されているか、実装の準備ができていることを確認してください。

サーバ

ポート

PHPとDBを実行するサーバーを適切に保護しなければ、暗号化がどれほど優れていても、すべての努力は無駄になります。ほとんどのサーバーは比較的同じように機能します。FTPまたはシェルを介してリモートでサーバーにアクセスできるようにポートが割り当てられています。アクティブになっているリモート接続のデフォルトポートを必ず変更してください。これを行わないことにより、実際には、攻撃者がシステムにアクセスする際の手順が1つ少なくなります。

ユーザー名

世界中で良いことのすべてのために、ユーザー名admin、root、または同様のものを使用しないでください。また、UNIXベースのシステムを使用している場合は、rootアカウントのログインをアクセス可能にしないでください。常にsudoのみにする必要があります。

パスワード

ハッキングを回避するために適切なパスワードを作成するようユーザーに指示します。バックドアを大きく開いた状態でフロントドアをロックするためのすべての作業を行うポイントは何ですか。

データベース

サーバ

理想的には、DBとアプリケーションを別々のサーバーに配置する必要があります。これはコストが原因で常に可能であるとは限りませんが、攻撃者がシステムに完全にアクセスするために2つの手順を実行する必要があるため、ある程度の安全性が得られます。

ユーザー

アプリケーションには常に、DBにアクセスするための独自のアカウントを持たせ、必要な権限のみを付与します。

次に、アプリケーション内ではなく、サーバー上のどこにも保存されていない別のユーザーアカウントを用意します。

いつものように、このルートまたは類似のものを作成しないでください。

パスワード

すべての適切なパスワードと同じガイドラインに従ってください。また、同じシステムのSERVERまたはDBアカウントで同じパスワードを再利用しないでください。

PHP

パスワード

決してパスワードをDBに保存するのではなく、ハッシュと一意のソルトを保存してください。理由は後で説明します。

ハッシング

ONE WAY HASHING !!!!!!!、パスワードを元に戻すことができる方法でハッシュしないでください。ハッシュは一方向でなければなりません。つまり、ハッシュを逆にしてパスワードと比較せず、代わりに入力したパスワードをハッシュします。同じ方法で、2つのハッシュを比較します。これは、攻撃者がDBにアクセスしても、実際のパスワードが何であるかを知らなくても、結果として得られるハッシュだけであることを意味します。つまり、最悪のシナリオでユーザーのセキュリティが強化されます。

優れたハッシュ関数はたくさんあります(password_hashhashなどが...)しかし、あなたはハッシュを有効にするには良いアルゴリズムを選択する必要があります。(bcryptとそれに似たものはまともなアルゴリズムです。)

ハッシュ速度が重要な場合、遅いほどブルートフォース攻撃への耐性が高くなります。

ハッシュの最も一般的な誤りの1つは、ハッシュがユーザーに固有ではないことです。これは主に、塩が一意に生成されないためです。

塩漬け

パスワードは常にハッシュする前にソルト処理する必要があります。Saltingはランダムな文字列をパスワードに追加するため、DB内で類似したパスワードが同じように表示されません。ただし、ソルトが各ユーザーに固有でない場合(つまり、ハードコードされたソルトを使用する場合)は、ソルトの価値がほとんどなくなります。攻撃者が1つのパスワードソルトを見つけたら、彼はそれらすべてのソルトを持っているからです。

ソルトを作成するときは、ソルトするパスワードに対して一意であることを確認してから、完成したハッシュとソルトの両方をDBに保存してください。これにより、攻撃者は各ソルトとハッシュを個別にクラックしてアクセスできるようになります。これは、攻撃者にとってより多くの作業と時間を意味します。

パスワードを作成するユーザー

ユーザーがフロントエンドを介してパスワードを作成している場合は、サーバーに送信する必要があります。これは、暗号化されていないパスワードがサーバーに送信されていること、および攻撃者がリッスンしてPHPのすべてのセキュリティにアクセスできない場合に、セキュリティの問題を引き起こすことになります。常に安全にデータを送信します。これはSSLを介して行われますが、SSLも完璧ではありません(OpenSSLのHeartbleedの欠陥がその例です)。

また、ユーザーに安全なパスワードを作成させます。これは簡単で常に実行する必要があります。ユーザーは最終的にそれを感謝します。

最後に、何もしないセキュリティ対策が100%安全であるとしても、保護するテクノロジーが高度になるほど、攻撃も高度になります。ただし、これらの手順に従うと、サイトがより安全になり、攻撃者が狙うのがはるかに望ましくなくなります。

これは、パスワードのハッシュとソルトを簡単に作成するPHPクラスです

http://git.io/mSJqpw


1
SHA512は速すぎるため、まともなハッシュアルゴリズムのリストから削除する必要があります。PBKDF2と組み合わせてのみ使用してください。BCryptはフグに基づいていますが、フグ自体はハッシュではなく暗号化のアルゴリズムです。
martinstoeckli 14

1
どのようにランダムソルトをDBに保存しますか?ハッシュ化(検証に使用できない)したり、平文で保存したりしないと思います(攻撃者がDBを読み取れる場合は、実際のメリットはありません)。それで、あなたはそれをどのように行うのですか?
Iazel 2014年

wmfranciaは次のように書いている:「ソルティングはランダムな文字列をパスワードに追加するので、類似したパスワードがDBで同じように表示されないようにします」。これは私には意味がありません。DBのハッシュはハッシュ関数のプロパティであるため、すでに異なるように見えます。
H2ONaCl 2015

wmfanciaはコンスタントソルトに関して次のように書いています。「攻撃者が1つのパスワードソルトを見つけたら、すべてのソルトを持っています」。同じことは、ハッカーがどのDBフィールドがソルトであるかを見つけた場合、すべてのソルトを持っていると言えます。定数ソルトはおそらくDBにないので、定数ソルトについてはそれが良いことです。
H2ONaCl 2015

もちろん、これらのコメントは、ユーザーごとにランダムなソルトがアプリケーションごとに1つのソルトよりも良くないことを示唆するものではありません。それはさらにいいです。
H2ONaCl 2015

12

Googleは、SHA256がPHPで利用可能であると述べています。

必ず塩を使うべきです。ランダムなバイトを使用することをお勧めします(文字と数字に制限されません)。通常、選択する時間が長いほど、安全で遅くなります。64バイトで大丈夫だと思います。


13
誰にとっても64ビットで十分でしょうか?
Konerak 2011年

@Konerak、私は20年後にこれに戻ります。:)しかし、確かにSHA256は利用可能です。:あなたはSHA256がどのように安全なお知りになりたい場合は、このチェックアウトする場合がありますsecurity.stackexchange.com/questions/90064/...
ヴィンセント・エドワードGedaria Binua

8

結局、ダブルハッシュは数学的には何のメリットもありません。ただし、実際には、レインボーテーブルベースの攻撃を防ぐのに役立ちます。言い換えると、ソルトを使用したハッシュよりもメリットはありません。ソルトを使用すると、アプリケーションまたはサーバーのプロセッサ時間を大幅に短縮できます。


2
複数のハッシュは、辞書攻撃やブルートフォース攻撃からも保護します。つまり、単に計算時間が長くなります。
frankodwyer 2008

6
ダブルハッシュを使用しても大きな利点はありませんが、マルチラウンドハッシュの繰り返しは、辞書攻撃やブルースフォース攻撃に対する実行可能な防御策です。産業用強度のパスワードハッシュは1000回以上のラウンドを使用します。PKCS#5のPBKDF1は、最低1000ラウンドを提案します。
バークD.デミール

8

私はここでこの問題に関する完璧なトピックを見つけました:https : //crackstation.net/hashing-security.htm、あなたはそれから利益を得てほしかった、これも時間ベースの攻撃に対する防止を提供したソースコードです。

<?php
/*
 * Password hashing with PBKDF2.
 * Author: havoc AT defuse.ca
 * www: https://defuse.ca/php-pbkdf2.htm
 */

// These constants may be changed without breaking existing hashes.
define("PBKDF2_HASH_ALGORITHM", "sha256");
define("PBKDF2_ITERATIONS", 1000);
define("PBKDF2_SALT_BYTES", 24);
define("PBKDF2_HASH_BYTES", 24);

define("HASH_SECTIONS", 4);
define("HASH_ALGORITHM_INDEX", 0);
define("HASH_ITERATION_INDEX", 1);
define("HASH_SALT_INDEX", 2);
define("HASH_PBKDF2_INDEX", 3);

function create_hash($password)
{
    // format: algorithm:iterations:salt:hash
    $salt = base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTES, MCRYPT_DEV_URANDOM));
    return PBKDF2_HASH_ALGORITHM . ":" . PBKDF2_ITERATIONS . ":" .  $salt . ":" . 
        base64_encode(pbkdf2(
            PBKDF2_HASH_ALGORITHM,
            $password,
            $salt,
            PBKDF2_ITERATIONS,
            PBKDF2_HASH_BYTES,
            true
        ));
}

function validate_password($password, $good_hash)
{
    $params = explode(":", $good_hash);
    if(count($params) < HASH_SECTIONS)
       return false; 
    $pbkdf2 = base64_decode($params[HASH_PBKDF2_INDEX]);
    return slow_equals(
        $pbkdf2,
        pbkdf2(
            $params[HASH_ALGORITHM_INDEX],
            $password,
            $params[HASH_SALT_INDEX],
            (int)$params[HASH_ITERATION_INDEX],
            strlen($pbkdf2),
            true
        )
    );
}

// Compares two strings $a and $b in length-constant time.
function slow_equals($a, $b)
{
    $diff = strlen($a) ^ strlen($b);
    for($i = 0; $i < strlen($a) && $i < strlen($b); $i++)
    {
        $diff |= ord($a[$i]) ^ ord($b[$i]);
    }
    return $diff === 0; 
}

/*
 * PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
 * $algorithm - The hash algorithm to use. Recommended: SHA256
 * $password - The password.
 * $salt - A salt that is unique to the password.
 * $count - Iteration count. Higher is better, but slower. Recommended: At least 1000.
 * $key_length - The length of the derived key in bytes.
 * $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise.
 * Returns: A $key_length-byte key derived from the password and salt.
 *
 * Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
 *
 * This implementation of PBKDF2 was originally created by https://defuse.ca
 * With improvements by http://www.variations-of-shadow.com
 */
function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
    $algorithm = strtolower($algorithm);
    if(!in_array($algorithm, hash_algos(), true))
        die('PBKDF2 ERROR: Invalid hash algorithm.');
    if($count <= 0 || $key_length <= 0)
        die('PBKDF2 ERROR: Invalid parameters.');

    $hash_length = strlen(hash($algorithm, "", true));
    $block_count = ceil($key_length / $hash_length);

    $output = "";
    for($i = 1; $i <= $block_count; $i++) {
        // $i encoded as 4 bytes, big endian.
        $last = $salt . pack("N", $i);
        // first iteration
        $last = $xorsum = hash_hmac($algorithm, $last, $password, true);
        // perform the other $count - 1 iterations
        for ($j = 1; $j < $count; $j++) {
            $xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
        }
        $output .= $xorsum;
    }

    if($raw_output)
        return substr($output, 0, $key_length);
    else
        return bin2hex(substr($output, 0, $key_length));
}
?>

使用法なしで使用法なしでソリューションを提供してください
Michael

6

私は通常、ユーザーID(またはその他のユーザー固有の情報)とともにSHA1とソルトを使用します。時々、追加で定数ソルトを使用します(ソルトに2つの部分があります)。

SHA1は現在やや妥協されていると見なされていますが、MD5よりもはるかに劣っています。ソルト(任意のソルト)を使用することで、ハッシュを攻撃するための一般的なレインボーテーブルの使用を防ぐことができます(ハッシュを検索することで、Googleを一種のレインボーテーブルとして使用することに成功した人もいます)。攻撃者はおそらくソルトを使用してレインボーテーブルを生成する可能性があるため、ユーザー固有のソルトを含める必要があります。そうすれば、システム全体の1つではなく、システム内のすべてのレコードについてレインボーテーブルを生成する必要があります。このタイプのソルティングを使用すると、MD5でもかなり安全です。


2
一定の塩は素晴らしいアイデアではありません...おそらく致命的な欠陥ではありませんが、それは不必要にスキームを弱めます。
frankodwyer 2008

MD5とSHA1は高速なので、これは悪い考えです。
CodesInChaos 2014年

4

SHA1とソルトで十分なはずです(当然、Fort Knox用にコーディングするか、ショッピングリスト用のログインシステムにコーディングするかによって異なります)。SHA1では不十分な場合は、SHA256を使用してください

ソルトの考え方は、言うまでもなく、ハッシュ結果のバランスを崩すことです。たとえば、空の文字列のMD5ハッシュはであることがわかっていますd41d8cd98f00b204e9800998ecf8427e。したがって、十分なメモリを持つ誰かがそのハッシュを見て、それが空の文字列のハッシュであることを知っている場合。しかし、文字列がソルト化されている場合(たとえば、文字列 " MY_PERSONAL_SALT"を使用)、 '空の文字列'(つまり " MY_PERSONAL_SALT")のハッシュはになりaeac2612626724592271634fb14d3ea6、バックトレースからは見えなくなります。私が言おうとしていることは塩を使用するよりも使用する方が良いということです。したがって、それは知っているあまり重要ではありませんどの使用する塩。

実際にこれを行うウェブサイトがありますます。(md5)ハッシュをフィードすると、その特定のハッシュを生成する既知のプレーンテキストを吐き出します。プレーンなmd5ハッシュを格納するデータベースにアクセスする場合、管理者がそのようなサービスにハッシュを入力してログインするのは簡単です。しかし、パスワードがソルトされている場合、そのようなサービスは次のようになります。効果がない。

また、ダブルハッシュは結果空間を縮小するため、一般に悪い方法と見なされます。すべての一般的なハッシュは固定長です。したがって、この固定長の有限値のみを持つことができ、結果のばらつきは少なくなります。これ別の形式の塩漬けと見なすことできますが、お勧めしません。


ターゲットサイトには機密性の高いものが含まれていてはいけません(銀行ではありません)が、セキュリティで保護する必要があります。
luiscubal 2008

1
ダブルハッシングは結果スペースを減らしません。反復ハッシュは、辞書攻撃やブルートフォース攻撃に対する一般的なコントロールです(パスワードチェックが遅くなるよりもはるかに遅くなります)。
frankodwyer 2008

2
@frankodwyer:はい、それは悪いです。sha1(sha1($foo))内部関数の衝突は自動的に外部関数の衝突になるため、出力スペースを効果的に削減します。低下は線形ですが、それでも問題です。反復ハッシュ法は、などの各ラウンドでデータをフィードバックし$hash = sha1(sha1($salt . $password) . $salt)ます。しかし、それはまだ良くありません... PBKDF2またはBcryptを使用してください...
ircmaxell

-7

塩味がユニークでなければならないので、それを生成してみましょう

   /**
     * Generating string
     * @param $size
     * @return string
     */
    function Uniwur_string($size){
        $text = md5(uniqid(rand(), TRUE));
        RETURN substr($text, 0, $size);
    }

また、私たちはsha512を使用しているハッシュが必要ですそれは最高で、それはphpです

   /**
     * Hashing string
     * @param $string
     * @return string
     */
    function hash($string){
        return hash('sha512', $string);
    }

これで、この関数を使用して安全なパスワードを生成できます

// generating unique password
$password = Uniwur_string(20); // or you can add manual password
// generating 32 character salt
$salt = Uniwur_string(32);
// now we can manipulate this informations

// hashin salt for safe
$hash_salt = hash($salt);
// hashing password
$hash_psw = hash($password.$hash_salt);

次に、$ hash_psw変数値と$ salt変数をデータベースに保存する必要があります

承認のために、同じ手順を使用します...

クライアントのパスワードを保護する最良の方法です...

最後の2つのステップのPsは、独自のアルゴリズムを使用できますが、ユーザーを認証する必要がある場合は、将来このハッシュされたパスワードを生成できることを確認してください...


4
この質問は、パスワードのハッシュについてでした。sha512(saltされていても)1回実行すると、パスワード保護には不十分であると広く考えられています。(また、RNGは暗号的に安全ではないため、パスワード生成に使用するのは危険です)。
luiscubal

2
あなたは何をしているのか分かりません。この投稿の上位の回答を読むと、コードが安全でないだけでなく、意味がない理由がわかります。
不可解なツオクト

OK。私のコードは安全ではありません。それで、なぜあなたはあなたのアルゴリズムでshay256を使っているのか教えてください?私はsha512が最高であることを知っています、なぜそれを使用しないのですか?
shalvasoft

1
@shalvasoft sha512は汎用のハッシュにはかなり良いですが、パスワード保護には非常に特定のプロパティを持つハッシュが必要です(たとえば、「遅い」は奇妙に良いことであり、sha512はかなり高速です)。一部の人々はパスワードハッシュ関数を作成するためにビルディングブロックとしてsha512を使用していますが、現在推奨されているアプローチは「bcryptを使用してscryptを監視する」です。
luiscubal
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.