ホームページ  >  記事  >  バックエンド開発  >  php ハッシュ関数を理解してパスワードのセキュリティを強化する_PHP チュートリアル

php ハッシュ関数を理解してパスワードのセキュリティを強化する_PHP チュートリアル

WBOY
WBOYオリジナル
2016-07-21 15:31:57684ブラウズ

1. 免責事項
未確認動物学は複雑なテーマであり、私はその専門家ではありません。多くの大学や研究機関がこの分野で長期にわたる研究を行っています。この記事では、Web アプリケーションのパスワードをできるだけシンプルでわかりやすい方法で安全に保存する方法を紹介したいと思います。
2.「ハッシュ」は何をしますか?
「ハッシュは、データの一部 (小さいデータまたは大きいデータ) を文字列や整数などの比較的短いデータに変換します。これは、一方向ハッシュ関数に依存することで実現されます。」いわゆる一方通行とは、元に戻すことが難しい(または実際には不可能)ことを意味します。ハッシュ関数の一般的な例は md5() で、さまざまなコンピューター言語やシステムでよく使われています。

コードをコピーします コードは次のとおりです:
$data = "Hello World";
$hash = md5($data); // b10a8db164e0754105b7a99be72e3fe5


md5( ) 結果は常に 32 文字の文字列ですが、技術的には 128 ビット (16 バイト) の整数として表すこともできます。 md5() を使用して非常に長い文字列やデータを処理できますが、常に取得されるのは固定長のハッシュ値であり、この関数が「一方向」である理由を理解するのにも役立ちます。
3. ハッシュ関数を使用してパスワードを保存します

一般的なユーザー登録プロセス: ユーザーがパスワードフィールドを含む登録フォームに入力します
ユーザーが入力したすべての情報がデータベースに保存されます。 、ハッシュ関数による暗号化処理の前に、パスワードはデータベースに保存されません。
元のパスワードはどこにも保存されなくなるか、破棄されます。
ユーザーログインプロセス:
ユーザーはユーザー名とパスワードを入力します。
プログラムは、登録されているものと同じハッシュ関数を使用してパスワードを暗号化します。
プログラムはデータベースからユーザーを検索し、ハッシュされたパスワードを読み取ります。
プログラムはユーザー名とパスワードを比較します。 , if 一致した場合、ユーザーは承認されています。
パスワードを暗号化する適切な方法を選択する方法については、この記事の後半で説明します。

4. 質問 1: ハッシュ衝突

ハッシュ衝突とは、2 つの異なるコンテンツがハッシュされ、同じハッシュ値が得られることを意味します。ハッシュ衝突の可能性は、使用されるハッシュ アルゴリズムによって異なります。
どうやって作られるの? たとえば、一部の旧式のプログラムは crc32() を使用してパスワードをハッシュします。このアルゴリズムはハッシュ結果として 32 ビット整数を生成します。これは、可能な出力結果が 2^32 (つまり 4,294,967,296) しかないことを意味します。
パスワードをハッシュしましょう:



コードをコピーします
コードは次のとおりです: echo crc32('supersecretpassword') // 出力: 323322056

次に、人が盗んだと仮定します。データベースハッシュ化されたパスワードを取得します。 323322056 を「supersecretpassword」に復元することはできないかもしれませんが、同じ値にハッシュできる別のパスワードを見つけることはできます。これには非常に単純なプログラムのみが必要です:


コードをコピー
コードは次のとおりです: set_time_limit(0); while (true) {
if (crc32(base64_encode($) i)) ) == 323322056) {
echobase64_encode($i);
}
$i++;
}


このプログラムは実行に時間がかかる場合がありますが、最終的には文字列を返します。この文字列を「supersecretpassword」の代わりに使用し、そのパスワードを使用してユーザー アカウントに正常にログインすることができます。
たとえば、上記のプログラムをコンピューターで数か月間実行した後、「MTIxMjY5MTAwNg==」という文字列が得られました。テストしてみましょう:


コードをコピーします

コードは次のとおりです:
echo crc32('supersecretpassword'); // 出力: 323322056 echo crc32('MTIxMjY5MTAwNg=='); //出力: 323322056

どうやって解決しますか?
現在、もう少し強力な家庭用 PC はハッシュ関数を 1 秒あたり 10 億回実行できるため、より広範囲の結果を生成できるハッシュ関数が必要です。たとえば、md5() は 128 ビットのハッシュ値を生成できるため、340,282,366,920,938,463,463,374,607,431,768,211,456 個の出力が可能になります。したがって、ハッシュの衝突を見つけるためにこれほど多くのループを実行することは一般に不可能です。ただし、まだこれを行う方法を見つけている人もいます。詳細については例を参照してください。
sha1() は最大 160 ビットのハッシュ値を生成するため、より良い代替手段です。
5. 問題 2: レインボーテーブル
衝突の問題が解決されたとしても、まだ十分に安全ではありません。
「レインボー テーブルは、一般的に使用される単語とその組み合わせのハッシュ値を計算して構築されたテーブルです。」
このテーブルには数百万、さらには数十億のデータが格納される可能性があります。ストレージが非常に安価になったので、非常に大きなレインボー テーブルを構築できるようになりました。
ここで、ある人がデータベースを盗み、何百万ものハッシュ化されたパスワードを取得したとします。泥棒はレインボー テーブルでこれらのハッシュを 1 つずつ簡単に検索し、元のパスワードを取得できます。すべてのハッシュ値がレインボー テーブルで見つかるわけではありませんが、いくつかは確実に見つかります。
どうやって解決しますか?
次の例のように、パスワードに何らかの干渉を追加してみることができます。
コードをコピーします コードは次のとおりです:

$password = "easypassword"
// これは次のとおりです。レインボーテーブルで見つかりました
// パスワードには一般的な単語が 2 つ含まれているため
echo sha1($password); // 6c94d3b42518febd4ad747801d50a8972022f956
// ランダムな文字を使用し、これよりも長くなる可能性があります
$salt = "f#@V )Hu^%Hgfds";
// これは、事前に構築されたレインボー テーブルには見つかりません
echo sha1($salt . $password); // cd56a16759623378628c0d9336af69b74d9d71a5

ここで行うのは、それぞれの前に干渉文字列を追加することだけですパスワード ハッシュの場合、添付された文字列が十分に複雑である限り、ハッシュされた値は事前に構築されたレインボー テーブルには絶対に見つかりません。しかし、今でも十分に安全とは言えません。
6. 質問 3: まだ虹のテーブルです
虹のテーブルは文字列を盗んだ後に最初から作成される可能性があることに注意してください。干渉文字列もデータベースと一緒に盗まれる可能性があり、その後、この干渉文字列を使用してレインボー テーブルを最初から作成することができます。たとえば、「easypassword」のハッシュ値は通常のレインボー テーブルに存在する可能性がありますが、新しいレインボー テーブルには存在します。レインボーテーブルには「f#@V)Hu^%Hgfdseasypassword」のハッシュ値も存在します。
どうやって解決しますか?
各ユーザーに固有の気を散らす文字列を使用できます。利用可能な解決策の 1 つは、データベース内のユーザー ID を使用することです:
コードをコピーします コードは次のとおりです:

$hash = sha1($user_id . $password);

この前提この方法は、ユーザー ID が定数値であるということです (これは一般的なアプリケーションの場合です)
ユーザーごとに一意の干渉文字列をランダムに生成することもできますが、この文字列を保存する必要もあります:
コードをコピー コードは次のとおりです:

// 22 文字の長さのランダムな文字列を生成します
function unique_salt() {
return substr(sha1(mt_rand()),0,22)
}
$unique_salt = unique_salt( );
$ hash = sha1($unique_salt . $password);
// そして $unique_salt をユーザー レコードとともに保存します
// ...

この方法は、各パスワードが異なる文字列に干渉されるため、レインボー テーブルによる被害を防ぎます。攻撃者はパスワードと同じ数のレインボー テーブルを作成する必要がありますが、これは現実的ではありません。
7. 質問 4: ハッシュ速度
ほとんどのハッシュ アルゴリズムは、一般に大規模なデータまたはファイルのハッシュ値を計算してデータの正確性と整合性を検証するために使用されるため、速度を念頭に置いて設計されています。
どうやって作られるの?
前に述べたように、強力な PC は 1 秒あたり数十億回の計算を実行できるため、ブルート フォースを使用してあらゆるパスワードを試すことが簡単になります。 8 文字を超えるパスワードを使用すればブルート フォース クラッキングを回避できると思うかもしれませんが、本当にそうなのかを見てみましょう:
パスワードに小文字、大文字、数字を含めることができる場合、62 (26+26+10) になります。 ) 文字はオプションです。
8 桁のパスワードには 62^8 通りの組み合わせがあり、これは 218 兆をわずかに超えます。
1 秒あたり 10 億のハッシュ値を計算する速度に基づくと、解決にかかる時間はわずか 60 時間です。
これも非常に一般的なパスワードである 6 桁のパスワードの場合、解読にはわずか 1 分しかかかりません。 9 ~ 10 桁のパスワードを要求する方が安全かもしれませんが、ユーザーによっては面倒に感じる場合もあります。
どうやって解決しますか?
より遅いハッシュ関数を使用してください。
「同じハードウェア条件下で、1 秒あたり 10 億回実行できるアルゴリズムの代わりに、1 秒あたり 100 万回しか実行できないアルゴリズムを使用すると、攻撃者はブルート フォース クラッキングに 1,000 倍の時間を費やす必要がある可能性があります。」 、60時間 たったの7年になります!」
このメソッドは自分で実装できます:
コードをコピーします コードは次のとおりです:

function myhash($password, $unique_salt) {
$salt = "f#@V )Hu^%Hgfds";
$hash = sha1($unique_salt . $password);
// 1000 倍の時間がかかります
for ($i = 0; $i $hash = sha1($hash);
}
return $hash;
}

BLOWFISH などの「コスト パラメーター」をサポートするアルゴリズムを使用することもできます。 crypt() 関数を使用して php で実装できます:
コードをコピー コードは次のとおりです:

function myhash($password, $unique_salt) {
// フグの塩は 22 である必要があります文字数
return crypt ($password, '$2a$10.$unique_salt');
}

この関数の 2 番目のパラメーターには、「$」記号で区切られた複数の値が含まれます。最初の値は「$2a」で、BLOWFISH アルゴリズムを使用する必要があることを示します。 2 番目のパラメーター「$10」はここではコスト パラメーターであり、底 2 の対数で、計算ループの反復数 (10 => 2^10 = 1024) を示し、値は 04 ~ 31 です。
例:
コードをコピーします コードは次のとおりです:

function myhash($password, $unique_salt) {
return crypt($password, '$2a$10.$unique_salt');
}
function unique_salt() {
return substr(sha1(mt_rand()),0,22);
}
$password = "verysecret";
// 結果: $2a$10 $dfda807d832b094184faeu1elwhtR2Xhtuvs3R9J1nfRGBCudCCzC

結果のハッシュ値には、$2a アルゴリズム、コスト パラメーター $10、および使用した 22 ビット干渉文字列が含まれています。残りは計算されたハッシュ値です。テスト プログラムを実行してみましょう:

コードをコピーします コードは次のとおりです:
// これがデータベースから取得されたものと仮定します
$hash = '$2a$10$ dfda807d832b094184faeu1elwhtR2Xhtuvs3R9J 1nfRGBCudCCzC ';
// これがユーザーが再度ログインするために入力したパスワードであると仮定します
$password = "verysecret";
if (check_password($hash, $password)) {
echo "アクセスが許可されました!";
} else {
echo "アクセスが拒否されました!";
}
function check_password($hash, $password) {
// 最初の 29 文字にはアルゴリズム、コスト、ソルトが含まれます
// $full_salt と呼びましょう
$full_salt = substr($ hash, 0, 29);
// $password でハッシュ関数を実行します
$new_hash = crypt($password, $full_salt);
// true または false を返します
return ($hash == $new_hash);


実行すると、「Access Granted!」が表示されます

8. 統合します
上記の議論に基づいて、ツール クラスを作成しました:

コードをコピーします コードは次のとおりです。

class PassHash {
// フグ
private static $algo = '$2a';
// コストパラメータ
private static $cost = '$10';
// 主に内部使用用
public static function unique_salt() {
return substr(sha1(mt_rand()),0,22);
}
// これはハッシュの生成に使用されます
public static function hash($password) {
return crypt($password,
self::$algo .
self::$cost .
'$'.self ::unique_salt());
}
// これはパスワードとハッシュを比較するために使用されます
public static function check_password($hash, $password) {
$full_salt = substr($hash, 0, 29);
$new_hash = crypt($password, $full_salt);
return ($hash == $new_hash);
}
}

以下は注册時の使用法:
复制番号 代码如下:

// クラス
require ("PassHash.php") をインクルードします。
// $_POST からすべてのフォーム入力を読み取ります
// ...
// 通常のフォーム検証作業を実行します
// ...
// パスワードをハッシュします
$pass_hash = PassHash::hash($_POST['パスワード']);
// $_POST['password'] を除くすべてのユーザー情報を DB に保存します
// 代わりに $pass_hash を保存します
// ...

以下は登录時の使用法:
复制發代码如下:

// クラス
require ("PassHash.php"); をインクルードします。
// $_POST からすべてのフォーム入力を読み取ります
// ...
// $_POST['username'] または同様のものに基づいてユーザー レコードを取得します
// ...
// ユーザーが試行したパスワードを確認します
if (PassHash::check_password($user['pass_hash'], $_POST['password']) {
// アクセスを許可
// ...
} else {
// アクセスを拒否
// でログインします...
}

9.加密がサポートされているかどうか
并不是全システム统都サポートBlowfish加密算法,虽然它现在已经很普及了,你可以以下代码来检查你的システム统がサポートされているかどうか:
复制代代码如下:

if (CRYPT_BLOWFISH == 1) {
echo "Yes";
} else {
echo "No";

php5.3 では不过对背負う心この方法が組み込まれているため、この方法で暗号化された暗号は、ほとんどの Web アプリケーション プログラムに対して十分に安全であると考えられます。用人使用安全度最小ビット数が必要な場合など、より高度な暗号には、文字、数字、特殊文字の混合暗号などが使用されます。


http://www.bkjia.com/PHPjc/322921.html
www.bkjia.com

tru​​e

技術記事 1. セキュリティコード学は複雑な問題であり、私たちもこの分野の専門家ではありません。多くの高校と研究機関がこの点で長期にわたる研究を行っています。
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。