コードをコピー コードは次のとおりです。
$data = "Hello World"
$hash = md5 ($data ; そういえば、128ビット(16バイト)の整数でも表現できます。 md5() を使用して非常に長い文字列やデータを処理できますが、常に取得されるのは固定長のハッシュ値であり、この関数が「一方向」である理由を理解するのにも役立ちます。
3. ハッシュ関数を使用してパスワードを保存します
echo crc32('supersecretpassword' ); // 出力: 323322056
次に、ある人物がデータベースを盗み、ハッシュ化されたパスワードを取得したと仮定します。 323322056 を「supersecretpassword」に復元することはできないかもしれませんが、同じ値にハッシュできる別のパスワードを見つけることはできます。これには非常に単純なプログラムのみが必要です。
set_time_limit(0); >$ i = 0; while (true) { if (crc32(base64_encode($i)) == 323322056) {
echo base64_encode($i); }$i++;
}
このプログラムは実行に時間がかかる場合がありますが、最終的には文字列を返します。この文字列を「supersecretpassword」の代わりに使用し、そのパスワードを使用してユーザー アカウントに正常にログインすることができます。
たとえば、上記のプログラムをコンピューターで数か月間実行した後、「MTIxMjY5MTAwNg==」という文字列が得られました。テストしてみましょう:
コードをコピー
echo crc32('MTIxMjY5MTAwNg==') // 出力: 323322056 コードをコピーします コードは次のとおりです。 コードをコピー コードは次のとおりです: コードをコピー コードは次のとおりです: コードをコピーします コードは次のとおりです。 コードをコピー コードは次のとおりです。 // フグのソルトは 22 文字である必要があります コードは次のとおりです: function myhash($password, $unique_salt) { } コードは次のとおりです。 // これはデータベースから取得されたものであると仮定します // これはユーザーが再度ログインするために入力したパスワードであると仮定します 复制代 代码如下: 复制代 代码如下: 复制代 代码如下:
どうやって解決しますか?
現在、もう少し強力な家庭用 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 が定数値であることです (これは一般的なアプリケーションの場合です)
それぞれをランダム化することもできますuser 固有の干渉文字列を生成しますが、この文字列も保存する必要があります:
// 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 倍の時間を費やす必要がある可能性があります。
このメソッドは自分で実装できます:
関数 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 などの「コスト パラメーター」をサポートするアルゴリズムを使用することもできます。 PHP では、crypt() 関数を使用できます。
return crypt($password, '$2a$10.$unique_salt')
this 関数の 2 番目のパラメーターには、「$」記号で区切られた複数の値が含まれます。最初の値は「$2a」で、BLOWFISH アルゴリズムを使用する必要があることを示します。 2 番目のパラメーター「$10」はここではコスト パラメーターであり、底 2 の対数で、計算ループの反復数 (10 => 2^10 = 1024) を示し、値は 04 ~ 31 です。
例:
コードをコピー
function unique_salt() {
return substr(sha1(mt_rand()),0,22);
}
$password = "verysecret";
echo myhash($password, unique_salt());
// 結果: $2a$10$dfda807d832b094184faeu1elwhtR2Xhtuvs3R9J1nfRGBCudCCzC
結果ハッシュ値には、$2a アルゴリズム、コスト パラメーター $10、および使用した 22 ビット干渉文字列が含まれます。残りは計算されたハッシュ値です。 テスト プログラムを実行してみます。
コードをコピーします。
$password = "verysecret";
if (check_password($hash, $password)) {
echo "アクセスが許可されました!";
} else {
echo "アクセスが拒否されました!";
関数 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 アプリケーション プログラムに対して十分に安全になっています。また、ユーザーは、最小ビット数を必要とする、文字、数字、および特殊文字の混合暗号などを使用することもできます。