6

コミュニティ についての簡単な質問があります。むかしむかし、プログラミングを始めたとき、パスワードのハッシュに md5 を使用していましたが、後で md5 は簡単に解読できることがわかり、salt を使用してセキュリティを確保する必要があります。

私はmd5を信じておらず、sha1、sha256、sha512暗号化を使用したかった. しかし問題は、暗号化された形式のパスワードを持っていることです。

md5("password"+"salt")

その時点で、私はユーザーのパスワードを知りませんでした。

sha1(md5("password"+"salt"))

このフィールドで数時間後、sha1も安全すぎず、壊れていることがわかりました。何をすべきかは、bcrypt()を使用してパスワードを安全にすることです。

だから今から私は使用します

 crypt(sha1(md5("password"+"salt")))

パスワードは非常に安全になりましたが、依然として主な問題は、ハッシュ値を作成するのにかかる時間が、bcrypt("password") を使用するよりも常に大きくなることです。

ここで言いたいのは、bcrypt がハッキングされ、壊れていることが判明し、将来、より安全で新しい暗号化機能が登場したとします。このように古い値からパスワードを作成するのは、常に時間がかかります。

これに対する解決策は何でしょうか。私が知っているように、パスワードを変更するためにユーザーにメールを送信しても、常に 100% 成功するとは限りません。別の方法は、データベースに新しいハッシュ値を格納する新しいフィールドを追加することです。すべてのフィールドがいっぱいになった場合は、 md5 値を db から削除します。ただし、この方法では、以前のハッシュ値は引き続き表示されます。

それで、このことが起こっているのでしょうか、それともあなたたちは何らかの解決策を持っています. :)

4

3 に答える 3

8

PHP 5.5 では、この問題に対処する Password API が導入されています。

PHP 5.5 の新しい Secure Password Hashing API

PHP 5.5 で使用できる新しいシンプルなパスワード ハッシュ API の RFC が承認されました。RFC 自体はかなり技術的なものであり、サンプル コードのほとんどは使用すべきではないため、新しい API の概要を簡単に説明したいと思います。

なぜ新しい API が必要なのですか?

bcrypt を使用してパスワードをハッシュ化する必要があることは誰もが知っていますが、それでも驚くほど多くの開発者が安全でない md5 または sha1 ハッシュを使用しています (最近のパスワード リークを見てください)。その理由の 1 つは、crypt() API がとてつもなく使いにくく、プログラミングのミスを起こしやすいことです。

非常に使いやすい新しい API を追加することで、より多くの開発者が bcrypt に移行することを願っています。

パスワードをハッシュする方法

パスワード ハッシュの作成は、これほど簡単ではありません。

  $hash = password_hash($password, PASSWORD_DEFAULT);

これにより、デフォルトのアルゴリズム (現在は bcrypt)、デフォルトの負荷係数 (現在は 10)、および自動生成されたソルトを使用してパスワード ハッシュが作成されます。使用されたアルゴリズムとソルトも結果のハッシュの一部になるため、それらについてまったく心配する必要はありません;)

デフォルト (将来変更される可能性があります) に固執したくない場合は、アルゴリズムと負荷係数を自分で指定することもできます。

$hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);

パスワードの確認

パスワードの検証も同様に簡単です。

<?php
// $password from user, $hash from database
if (password_verify($password, $hash)) {
    // password valid!
} else {
    // wrong password :(
}

注意: ソルトとアルゴリズムはハッシュの一部であるため、別々に提供する必要はありません。

パスワードの再ハッシュ

時間が経つにつれて、パスワード ハッシュ アルゴリズムまたは負荷係数を変更したい場合や、PHP がデフォルトをより安全なものに変更する場合があります。この場合、新しいオプションを使用して新しいアカウントを作成し、ログイン時に既存のパスワードを再ハッシュする必要があります (再ハッシュを行うには元のパスワードが必要なため、ログイン時にのみこれを行うことができます)。

これを行うことも非常に簡単です。

<?php
function password_verify_with_rehash($password, $hash) {
    if (!password_verify($password, $hash)) {
        return false;
    }

    if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
        $hash = password_hash($password, PASSWORD_DEFAULT);

        // update hash in database
    }

    return true;
}

上記のスニペットは、ハッシュを PHP のデフォルトで最新の状態に保ちます。ただし、カスタム オプションを指定することもできますpassword_needs_rehash($hash, PASSWORD_BCRYPT, ['cost' => 12'])

古い PHP バージョンの互換レイヤー

新しい API は PHP 5.5 でのみ導入されますが、既に同じ API の PHP 実装を使用することができます! 5.5 にアップグレードすると、互換性の実装は自動的に無効になります。

于 2013-04-10T18:23:58.530 に答える
6

実際、MD5適切に使用すれば、パスワード ハッシュに対して完全に安全であると見なされます。MD5 に対する実際的な衝突攻撃が存在するため、デジタル署名などの安全性が損なわれますが、パスワード ハッシュを破るにはプリイメージ攻撃が必要であり、現在知られている MD5 に対するそのような攻撃はすべて純粋に理論的なものです。

(とは言っても、Bruce Schneier の言葉を言い換えると、「攻撃は常に良くなる」ため、MD5 からSHA-2SHA-3などのより信頼できるハッシュ関数に移行し始めることは、たとえそうしなくても、確かに悪い考えではありません。まだする必要はありません。)

問題は、MD5だけでは 2 つの理由でパスワードのハッシュ化に適していないことです。どちらも実際には意図的な設計機能です (SHA-2 や SHA-3 などの他のハッシュ関数によって共有されます)。

  1. MD5 はdeterministicです。つまり、MD5 で同じ入力をハッシュすると、常に同じ出力が生成されます。

    これは、パスワード ハッシュの問題です。なぜなら、一般的な (あまり一般的ではない) パスワードの MD5 ハッシュの巨大なデータベースをコンパイルできる (実際、一部の人はそうしている) ため、任意のパスワードの単純な MD5 ハッシュを知っている人なら誰でも使用できるようになります。それらのデータベースで見つかったものを調べて、元のパスワードを見つけます。

    解決策は簡単で、すでにご存知のとおり、パスワードをハッシュする前にランダムなソルトと組み合わせ、最終的なハッシュの一部としてソルトを含めて、後でパスワードを検証するために使用できるようにします。ランダムに選択するのに十分な数のソルト (たとえば、少なくとも数十億) を使用すると、ハッシュ データベースをコンパイルすることは不可能になります。便利なことに、これは、たまたま同じパスワードを持つ 2 人のユーザーがいたとしても、ハッシュを見るだけではそれを見分けることができないことも意味します。

  2. MD5 は高速です。通常、これは良いことだと考えられていますが、パスワード ハッシュでは、プロセスを高速化しすぎると、ほとんどの場合、攻撃者を助けるだけであることがわかります。正当なユーザーは、パスワードのハッシュに 10 ナノ秒または 10 ミリ秒かかるかどうかはあまり気にしませんが、攻撃者は、何百万ものパスワードを力ずくでハッシュしてパスワードを推測しようとすると、各ハッシュ計算から削られたナノ秒のすべての断片が高く評価されます。

    繰り返しになりますが、解決策は単純でよく知られています。パスワードを数千回 (またはそれ以上) 再ハッシュして、計算を遅くするだけです。PBKDF2メソッドなど、これを行うための標準化された方法さえあります。または、 bcryptscryptなどの特別な専用のパスワード ハッシュ関数を使用することもできます。これらの関数には通常、ソルティングと調整可能な反復回数が組み込まれています。

とにかく...これらすべてのポイントは、実際には、パスワードハッシュを次のように計算することです

hash = salt + bcrypt( sha1( md5( password + salt ) ) )

多少複雑であっても、完全に問題ありません。また、この一連のハッシュでは、意図的に遅くなるように設計された 3 つのハッシュ関数のうちの 1 つだけであるため、ほとんどすべての時間が bcrypt によって消費されます。したがって、その一連のハッシュと bcrypt 自体の間には、目立った速度の違いはまったくないはずです。また、いずれにせよ、パスワードのハッシュはできるだけ遅くする必要があります。

于 2013-04-10T20:00:04.760 に答える
2

データベース内のユーザーのすべてのパスワードを更新する必要がありますか? ログイン スクリプトをいじっても、何もする必要はありません。これを見てください:

Md5 パスワード ハッシュを BCRYPT ハッシュに更新しています::

$passwordFromDatabase = "0d107d09f5bbe40cade3de5c71e9e9b7"; // md5  hash of "letmein"
$passwordFromForm = $_POST['password']; // $_POST['password'] == "letmein"

if(password_needs_rehash($passwordFromDatabase, PASSWORD_BCRYPT, ["cost" => 12]) && md5($passwordFromForm) === $passwordFromDatabase){
    // generate new password
    $newPasswordHash = password_hash($passwordFromForm, PASSWORD_BCRYPT, ["cost" => 12]);
    // update hash from database - replace old hash $passwordFromDatabase with new hash $newPasswordHash
    // after update login user
    if(password_veryfi($passwordFromForm, $newPasswordHash)){
        // user has logged in successfully and hash was updated
        // redirect to user area
    }else{
        // ups something went wrong Exception
    }
}else{
    if($password_veryfi($passwordFromForm, $passwordFromDatabase)){
        // user password hash from database is already BCRYPTed no need to rehash
        // user has logged in successfully
        // redirect to user area
    }else{
        // wrong password
        // no access granted - stay where you are
    }
}

上記の例は普遍的です。それ以外の

... && md5($passwordFromForm) === ...){

保存されたパスワードに対して行ったネストされたハッシュの組み合わせを使用できます。いずれにせよ、最終的には BCRYP ハッシュになります。暗号化とセキュリティ、およびユーザー パスワードをハッシュするためのコスト パラメーターの正しい値を定義する方法については、以下をお読みください。

遅いアルゴリズム

現在の標準は、低速ハッシュ アルゴリズムを使用することです。PBKDF2、bcrypt、または scrypt はすべて、入力としてパスワードとソルトの両方を受け取り、構成可能な作業係数を使用します。この作業係数は、サーバーのハードウェアへのログイン時にユーザーが受け入れるだけ高く設定してください。参照

  • PBKDF2は単純に反復処理された高速ハッシュです (つまり、効率的に並列化できます)。(これは、さまざまな基本アルゴリズムで使用できるスキームです。システムで使用しているアルゴリズムを使用してください。)
  • Bcryptはいくらか (4KB) の作業メモリを必要とするため、プロセッサあたりのキャッシュが 4KB 未満の GPU では効率的に実装できません。
  • Scryptは処理時間に加えて (構成可能な) 大量のメモリを使用するため、GPU やカスタム ハードウェアでの並列化には非常にコストがかかりますが、「通常の」コンピュータには通常十分な RAM が用意されています。

良いパスワード

パスワードの長さは 8 文字以上で、少なくとも 1 つを使用する必要があります。

  • 大文字
  • 1つの数字と
  • 1 つの特殊文字

大文字と小文字、および特殊文字を含む 8 文字の長さのパスワードを設定すると、6 634 204 312 890 625 の組み合わせを作成できます。ただし、パスワードが 1 週間である場合、たとえば 6 文字の小文字のみを使用すると、308,915,776 の組み合わせしか得られません。アカウントを安全にするために、パスワードの長さは 12 文字以上にすることをお勧めします。パスワードの組み合わせ数シミュレーターはこちら

CRACKING SPEED (クラッカーが GPU の処理能力を向上させたり、クラウド コンピューティングをより強力にしたりするために、毎年変更されます)

パスワードを設計するときは、将来の処理能力の向上と、ハッカーが入手するツールについて考えてください。

このプログラム IGHASHGPU v0.90 は、単一の ATI HD5870 GPU で毎秒約 13 億回の SHA-1 ハッシュ (つまり、2^30 以上) を実行できると主張しています。

40 ビットのエントロピーのパスワードを想定すると、これには 2^10 秒、つまり約 17 分かかります。

エントロピーが 44 ビットのパスワード (有名な XKCD コミックのパスワードなど) は 68 分かかります (最悪の場合、平均的な場合はこの半分です)。

複数の GPU で並列に実行すると、これが比例して高速化されます。

したがって、高速ハッシュを使用した総当たり攻撃は、理論上の危険ではなく、実際の危険です。また、多くのパスワードはエントロピーがはるかに低いため、総当たり攻撃がさらに高速になります。参照

解決

コストを操作することで、アルゴリズムの速度をカスタマイズできます。コストが高いほど、パスワードのコーディングとエンコードに時間がかかります。攻撃者がパスワードをブルート フォース攻撃するのを非常に困難にするために、おそらく約 500 ml を目標とするのが最善でしょう。

12 文字以上のパスワード + 低速のアルゴリズムは、パスワードがクラックされる前にブルート フォース攻撃を受ける適切な量の組み合わせを保証します。まともなパスワードを取得すると、パスワードの検証プロセスが非常に困難になり、時間/リソースを消費するものになるまで遅くすることで、システムに侵入しようとする誰かの生活をはるかに困難にすることができます. コストを、ユーザー パスワードの確認にかかる約 0.5 秒の時間に影響する数値に設定します。

コスト値をカスタマイズ

スクリプトの実行は処理能力とトラフィックに基づいてサーバーごとに異なるため、コストをどれくらい高く設定する必要があるかをどのように判断しますか?

検証プロセスにかかる時間を測定し、適切なコストに合わせてカスタマイズする必要があります。

<?php
/**
 * This code will benchmark your server to determine how high of a cost you can
 * afford. You want to set the highest cost that you can without slowing down
 * you server too much. 8-10 is a good baseline, and more is good if your servers
 * are fast enough. The code below aims for ≤ 50 milliseconds stretching time,
 * which is a good baseline for systems handling interactive logins.
 */
$timeTarget = 0.50; // 500 milliseconds 

$cost = 8; //start to measure from cost = 8
do {
    $cost++;
    $start = microtime(true);
    password_hash("Ajd_hsk-K87&", PASSWORD_BCRYPT, ["cost" => $cost]);
    $end = microtime(true);
} while (($end - $start) < $timeTarget);

echo "Appropriate Cost Found: " . $cost . "\n";
?>

参照

上記の関数は、安全要件を満たすために使用する必要があるコストの X 数を返します。

Appropriate Cost Found: 13 //this result will be different based on your server machine.

このスクリプトは、php マニュアルから取得され、10 倍長く処理するように拡張されています。ほとんどの場合、これは一般的に安全な方法ですが、管理者およびスーパー管理者のログインについては、実際のハッカーにとってより興味深い場所であるため、さらに時間のかかる (約 1 秒) ようにすることを検討します。

于 2016-02-07T09:47:48.223 に答える