【PHP8.x】sodium_crypto_pwhash()関数の使い方
sodium_crypto_pwhash関数の使い方について、初心者にもわかりやすく解説します。
基本的な使い方
sodium_crypto_pwhash関数は、ユーザーのパスワードを安全にハッシュ化するために使用される関数です。パスワードをデータベースなどにそのまま保存することは、セキュリティ上の大きなリスクを伴います。この関数は、元のパスワードから復元できないハッシュ値を生成することで、万が一データベースが漏洩した場合でも、実際のパスワードが容易に推測・解析されることを防ぎます。
この関数は、現代のセキュリティ基準に合致した強力な鍵導出関数であるArgon2idアルゴリズムを利用しており、時間をかけて試行錯誤するブルートフォース攻撃や、一般的な単語リストを用いる辞書攻撃といったパスワード解析攻撃に対して、高い防御性能を発揮します。ハッシュ化を行う際には、元のパスワードの他に、パスワードごとに異なる「ソルト」と呼ばれる予測不可能なランダムな値と、計算の複雑さやメモリの使用量を調整する「操作制限値(opslimit)」および「メモリ制限値(memlimit)」を指定します。これにより、攻撃者が効率的にハッシュを計算することを困難にし、セキュリティ強度を高めます。
引数には、ハッシュ化したいパスワード、一意なソルト、計算量とメモリ使用量の制約、そして使用するハッシュアルゴリズム(通常はSODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13)を渡します。ソルトは必ず安全な方法で毎回異なる値を生成し、パスワードごとに異なるハッシュが生成されるようにすることが極めて重要です。opslimitとmemlimitは、システムの性能とセキュリティのバランスを考慮して適切な値を設定する必要がありますが、PHPのSodium拡張には推奨される定数も用意されています。この関数は、生成されたパスワードのバイナリハッシュを返します。このバイナリハッシュは、そのままではデータベースへの保存に適さない場合があるため、保存する際には適切な形式に変換する必要があります。
構文(syntax)
1<?php 2$password = 'your_secret_password'; 3$salt = random_bytes(SODIUM_CRYPTO_PWHASH_SALTBYTES); // SODIUM_CRYPTO_PWHASH_SALTBYTES (16バイト) 4$out_len = 32; // 生成するキーのバイト長 (例: 32バイト) 5$opslimit = SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE; // 処理速度の制限 (対話的な用途向け) 6$memlimit = SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE; // メモリ使用量の制限 (対話的な用途向け) 7$alg = SODIUM_CRYPTO_PWHASH_ALG_DEFAULT; // 使用するハッシュアルゴリズム (デフォルトはArgon2id) 8 9$derived_key = sodium_crypto_pwhash( 10 $out_len, 11 $password, 12 $salt, 13 $opslimit, 14 $memlimit, 15 $alg 16);
引数(parameters)
int $length, string $password, string $salt, int $opslimit, int $memlimit, int $algo = SODIUM_CRYPTO_PWHASH_ALG_DEFAULT
- int $length: 生成するハッシュのバイト長を指定します。
- string $password: ハッシュ化するパスワードを指定します。
- string $salt: パスワードハッシュ化に使用するソルトを指定します。
- int $opslimit: 処理の実行回数制限を指定します。
- int $memlimit: 使用するメモリの制限をバイト単位で指定します。
- int $algo = SODIUM_CRYPTO_PWHASH_ALG_DEFAULT: 使用するアルゴリズムを指定します。デフォルトは SODIUM_CRYPTO_PWHASH_ALG_DEFAULT です。
戻り値(return)
string
指定されたパスワードハッシュアルゴリズムを用いて、パスワードを安全なハッシュ値に変換した文字列を返します。
サンプルコード
PHP Sodiumでパスワードハッシュ化と検証する
1<?php 2 3// PHPのエラー表示設定。開発環境でのデバッグを助けます。 4ini_set('display_errors', 1); 5ini_set('display_startup_errors', 1); 6error_reporting(E_ALL); 7 8/** 9 * PHPのSodium拡張を使用してパスワードを安全にハッシュ化し、検証する一連の処理を示します。 10 * SodiumはLibsodiumライブラリのPHPバインディングで、暗号化処理を安全かつ簡単に利用できるようにします。 11 * 12 * 「php sodium と は」という問いに対し、Sodium拡張が提供するパスワードハッシュ機能は、 13 * Webアプリケーションのセキュリティにおいて非常に重要です。 14 * データベースに直接パスワードを保存するのではなく、強力なアルゴリズムでハッシュ化して保存することは、 15 * データ漏洩時のリスクを最小限に抑える上で最も重要なセキュリティ対策の一つです。 16 * 17 * この関数では、`sodium_crypto_pwhash` を中心に、パスワードハッシュの生成、 18 * そしてそのハッシュを使ったパスワードの検証方法を初心者にも分かりやすく解説します。 19 */ 20function demonstratePasswordHashingWithSodium(): void 21{ 22 // ユーザーが登録時に入力したパスワードと仮定します。 23 $originalPassword = 'MySuperSecurePassword123!'; 24 echo "元のパスワード: " . $originalPassword . PHP_EOL . PHP_EOL; 25 26 // --- 1. パスワードのハッシュ化(ユーザー登録時を想定) --- 27 28 // ハッシュのバイト長を設定します。 29 // ここでは Libsodium が推奨する最小値 (32バイト) を使用します。 30 // 一般的に、ハッシュの長さが長いほど、衝突攻撃に対する耐性が高まります。 31 $hashLength = SODIUM_CRYPTO_PWHASH_BYTES_MIN; 32 33 // ソルト(salt)を生成します。 34 // ソルトは、同じパスワードであっても毎回異なるハッシュを生成するために使用されるランダムなデータです。 35 // これにより、レインボーテーブル攻撃(事前に計算されたハッシュのデータベースを使った攻撃)を防ぎます。 36 // `random_bytes` は暗号学的に安全なランダムなバイト列を生成します。 37 $salt = random_bytes(SODIUM_CRYPTO_PWHASH_SALTBYTES); 38 39 // 運用制限(opslimit)とメモリ制限(memlimit)を設定します。 40 // これらは、ハッシュ計算にかかるCPU時間とメモリ消費量を制御するパラメータです。 41 // これらの値を適切に設定することで、ブルートフォース攻撃(総当たり攻撃)を遅らせ、 42 // 攻撃者がパスワードを推測するコストを高くすることができます。 43 // Libsodiumが推奨する定数を使用するのが最も簡単で安全な方法です。 44 $opslimit = SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE; // 中程度のCPU時間 45 $memlimit = SODIUM_CRYPTO_PWHASH_MEMLIMIT_MODERATE; // 中程度のメモリ 46 47 // `sodium_crypto_pwhash` 関数を使用してパスワードをハッシュ化します。 48 // 第6引数のアルゴリズムは、デフォルトで `SODIUM_CRYPTO_PWHASH_ALG_DEFAULT` (Argon2id) が使用され、 49 // これは現在最も安全なパスワードハッシュアルゴリズムの一つとされています。 50 $hashedPasswordBinary = sodium_crypto_pwhash( 51 $hashLength, // 生成されるハッシュのバイト長 52 $originalPassword, // ハッシュ化する元のパスワード 53 $salt, // 各パスワードに対してユニークなソルト 54 $opslimit, // CPU時間の制限 55 $memlimit // メモリ使用量の制限 56 // $algo はデフォルトで SODIUM_CRYPTO_PWHASH_ALG_DEFAULT が使用されるため省略可能 57 ); 58 59 // データベースなどに保存するため、バイナリ形式のハッシュとソルトを16進数文字列に変換します。 60 // バイナリデータをそのままデータベースの文字列カラムに保存すると、文字化けや互換性の問題が発生する可能性があります。 61 $storedHashHex = sodium_bin2hex($hashedPasswordBinary); 62 $storedSaltHex = sodium_bin2hex($salt); 63 64 echo "--- パスワードのハッシュ化(ユーザー登録時を想定)---" . PHP_EOL; 65 echo "保存されるハッシュ (16進数): " . $storedHashHex . PHP_EOL; 66 echo "保存されるソルト (16進数): " . $storedSaltHex . PHP_EOL . PHP_EOL; 67 68 // --- 2. パスワードの検証(ユーザーログイン時を想定) --- 69 70 // ユーザーがログインフォームに入力したパスワードと仮定します。 71 $inputPasswordLogin = 'MySuperSecurePassword123!'; 72 73 echo "--- パスワードの検証(ユーザーログイン時を想定)---" . PHP_EOL; 74 echo "ログイン入力パスワード: " . $inputPasswordLogin . PHP_EOL; 75 76 // データベースから取得したと仮定されるソルトとハッシュを16進数からバイナリ形式に戻します。 77 $retrievedSalt = sodium_hex2bin($storedSaltHex); 78 $retrievedHash = sodium_hex2bin($storedHashHex); 79 80 // ユーザーが入力したパスワードと、データベースから取得したソルトを使って、再度ハッシュを生成します。 81 // このとき、ハッシュ化時と同じ $hashLength, $opslimit, $memlimit を使用する必要があります。 82 $rehashedPasswordBinary = sodium_crypto_pwhash( 83 $hashLength, 84 $inputPasswordLogin, 85 $retrievedSalt, 86 $opslimit, 87 $memlimit 88 ); 89 90 // 生成された新しいハッシュと、データベースに保存されていたハッシュを比較します。 91 // 比較には `hash_equals()` を使用することが非常に重要です。 92 // `hash_equals()` は、比較する両方の文字列の長さが異なる場合でも、常に同じ時間で比較処理を完了させます。 93 // これにより、攻撃者が比較にかかる時間のわずかな差から情報を推測する「タイミング攻撃」を防ぎます。 94 $isPasswordCorrect = hash_equals($retrievedHash, $rehashedPasswordBinary); 95 96 if ($isPasswordCorrect) { 97 echo "検証結果: パスワードが一致しました。ログイン成功!" . PHP_EOL; 98 } else { 99 echo "検証結果: パスワードが一致しませんでした。ログイン失敗!" . PHP_EOL; 100 } 101 102 // 間違ったパスワードで検証を試みる例 103 $wrongPasswordLogin = 'WrongPassword456!'; 104 echo PHP_EOL . "間違ったパスワードでの試行: " . $wrongPasswordLogin . PHP_EOL; 105 106 $rehashedWrongPasswordBinary = sodium_crypto_pwhash( 107 $hashLength, 108 $wrongPasswordLogin, 109 $retrievedSalt, 110 $opslimit, 111 $memlimit 112 ); 113 $isWrongPasswordCorrect = hash_equals($retrievedHash, $rehashedWrongPasswordBinary); 114 115 if ($isWrongPasswordCorrect) { 116 echo "検証結果: 間違ったパスワードなのに一致しました。(!!!セキュリティ上の問題!!!)" . PHP_EOL; 117 } else { 118 echo "検証結果: 間違ったパスワードは一致しませんでした。期待通り。" . PHP_EOL; 119 } 120} 121 122// パスワードハッシュのデモンストレーションを実行します。 123demonstratePasswordHashingWithSodium(); 124 125?>
PHPのsodium_crypto_pwhash関数は、LibsodiumライブラリのPHP拡張であるSodiumが提供する、パスワードを安全にハッシュ化するための重要な関数です。Webアプリケーションのセキュリティにおいて、パスワードをデータベースにそのまま保存するのではなく、この関数で強力なアルゴリズムを用いてハッシュ化して保存することは、情報漏洩時のリスクを最小限に抑えるための必須の対策となります。
この関数は、$lengthで指定されたバイト長のハッシュを生成します。元の$passwordを、ランダムに生成される$salt、計算にかかるCPU時間の$opslimit、使用するメモリ量の$memlimitというパラメータと共にハッシュ化します。これにより、同じパスワードでも常に異なるハッシュが生成され、ブルートフォース攻撃やレインボーテーブル攻撃に対する耐性を高めます。$algo引数でハッシュアルゴリズムを指定できますが、デフォルトのSODIUM_CRYPTO_PWHASH_ALG_DEFAULT(Argon2id)は現在非常に強力とされています。戻り値はハッシュ化されたパスワードのバイナリ文字列です。
サンプルコードでは、ユーザー登録時にパスワードをハッシュ化し、データベースに保存する流れを示しています。また、ログイン時にはユーザーが入力したパスワードと保存済みのソルトなどの情報を用いて再度ハッシュを生成し、hash_equals関数で安全に比較して認証を行う一連のプロセスを解説しています。特にhash_equalsの使用は、比較にかかる時間の差から情報を推測される「タイミング攻撃」を防ぐ上で非常に重要です。
このコードは、パスワードを安全にハッシュ化するsodium_crypto_pwhashの利用法を示しています。パスワードは生のまま保存せず、必ずハッシュ化してデータベースに格納してください。sodium_crypto_pwhashの戻り値はバイナリデータなので、保存時にはsodium_bin2hexで16進数に変換し、取り出し時にsodium_hex2binで元に戻す必要があります。ソルトはrandom_bytesで毎回ユニークなものを生成し、ハッシュと一緒に保存します。opslimitやmemlimitは、ブルートフォース攻撃に対する耐性を高めるための重要な設定です。パスワード検証時は、ハッシュ化時と同じソルトと設定値を使用し、比較にはタイミング攻撃を防ぐため必ずhash_equals()関数を利用してください。開発環境のエラー表示設定は、本番環境ではセキュリティ上の理由で無効にすることを忘れないでください。
PHP Sodium: パスワードを安全にハッシュ化する
1<?php 2 3/** 4 * PHP Sodium拡張のsodium_crypto_pwhash関数を使用してパスワードをハッシュ化する例。 5 * 6 * この関数は、指定されたパスワードを安全にハッシュ化します。 7 * CPUやメモリのコストを意図的に高く設定することで、 8 * ブルートフォース攻撃や辞書攻撃に対する耐性を高めます。 9 * 10 * @param string $password ハッシュ化する元のパスワード 11 * @return string 生成されたバイナリハッシュ文字列 12 * @throws Exception 暗号論的に安全なソルトの生成に失敗した場合 13 */ 14function generatePasswordHash(string $password): string 15{ 16 // 生成するハッシュの推奨される長さ(バイト数) 17 $length = SODIUM_CRYPTO_PWHASH_BYTES; 18 19 // 暗号論的に安全なランダムなソルトを生成します。 20 // ソルトは毎回異なる値を生成し、ハッシュと一緒にデータベースなどに保存・利用する必要があります。 21 // SODIUM_CRYPTO_PWHASH_SALTBYTES はソルトの推奨サイズです。 22 $salt = random_bytes(SODIUM_CRYPTO_PWHASH_SALTBYTES); 23 24 // CPUコスト制限とメモリコスト制限を設定します。 25 // これらの定数はSodium拡張によって提供され、セキュリティとパフォーマンスのバランスを表します。 26 // SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE は一般的なWebアプリケーションに適した推奨設定です。 27 $opslimit = SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE; 28 $memlimit = SODIUM_CRYPTO_PWHASH_MEMLIMIT_MODERATE; 29 30 // sodium_crypto_pwhash関数を呼び出してパスワードをハッシュ化します。 31 // SODIUM_CRYPTO_PWHASH_ALG_DEFAULT はデフォルトの強力なアルゴリズムを使用します。 32 $hashedPasswordBinary = sodium_crypto_pwhash( 33 $length, 34 $password, 35 $salt, 36 $opslimit, 37 $memlimit, 38 SODIUM_CRYPTO_PWHASH_ALG_DEFAULT 39 ); 40 41 // 実際のアプリケーションでは、$salt と $hashedPasswordBinary をデータベースに保存します。 42 // ユーザーがログインを試みる際は、保存された $salt と入力されたパスワードを使って 43 // 再度ハッシュを生成し、$hashedPasswordBinary と比較してパスワードの正当性を検証します。 44 // (今回のサンプルコードには検証ロジックは含まれていません) 45 46 return $hashedPasswordBinary; 47} 48 49// ---- コード実行例 ---- 50 51// テスト用のサンプルパスワード 52$userPassword = 'MySuperSecretPassword123!'; 53 54try { 55 // パスワードをハッシュ化 56 $hashedPassword = generatePasswordHash($userPassword); 57 58 echo "元のパスワード: " . $userPassword . PHP_EOL; 59 // sodium_crypto_pwhashはバイナリデータを返すため、 60 // 人間が読める形式(16進数文字列)に変換して表示します。 61 echo "ハッシュ化されたパスワード (16進数): " . bin2hex($hashedPassword) . PHP_EOL; 62 63} catch (Exception $e) { 64 // エラーが発生した場合の処理 65 echo "エラーが発生しました: " . $e->getMessage() . PHP_EOL; 66}
sodium_crypto_pwhash関数は、ユーザーのパスワードを安全な形式でハッシュ化するために使用されます。この機能は、ブルートフォース攻撃や辞書攻撃といった不正な試みからパスワードを守る上で非常に重要です。
サンプルコードでは、まずハッシュ化したい元のパスワードを$password引数として渡します。次に、セキュリティをさらに高めるため、毎回異なるランダムな値である$saltが生成され、パスワードと一緒にハッシュ化処理に利用されます。$opslimitと$memlimit引数は、CPUとメモリに意図的に負荷をかけるための設定です。これにより、攻撃者が効率的にパスワードを推測するのを困難にしています。$length引数で生成するハッシュの長さを、$algo引数でハッシュアルゴリズムを指定しますが、通常はセキュリティとパフォーマンスのバランスが取れた推奨デフォルト値を使用します。
この関数は、ハッシュ化されたバイナリ形式の文字列を戻り値として返します。実際のアプリケーションでは、このバイナリハッシュと生成に使用した$saltをデータベースなどに保存します。そして、ユーザーがログインを試みる際に、入力されたパスワードと保存された$saltを使って再度ハッシュを生成し、保存済みのハッシュと比較することでパスワードの正当性を検証します。サンプルコードの実行例では、generatePasswordHash関数を使ってパスワードをハッシュ化し、得られたバイナリデータをbin2hex関数で人間が読みやすい16進数文字列に変換して表示しています。これにより、本関数がパスワードセキュリティを強化するのに役立つことが示されています。
このサンプルコードで生成されるソルトは、パスワードごとにランダムに生成され、生成されたハッシュと一緒にデータベースへ保存する必要があります。パスワードを検証する際には、保存したソルトとユーザーが入力したパスワードを用いてハッシュを再生成し、保存されたハッシュと一致するか確認する検証ロジックが別途必要です。sodium_crypto_pwhashの戻り値はバイナリデータですので、そのまま文字列として扱ったり表示したりする際は、bin2hex()などの関数で16進数文字列に変換してください。opslimitやmemlimitなどのコスト定数は、ハッシュ化にかかるCPUやメモリの消費量、ひいてはセキュリティレベルに影響しますので、安易に変更せず推奨値の使用をお勧めします。