パスワード暗号化(ハッシュ化)生成サンプル

パスワードファイル(.htpasswd)に記述する暗号化されたパスワードを生成するサンプルページです。

更新日:2025年05月20日

作成日:2019年05月10日

パスワードハッシュ生成サンプル(AJAX + アルゴリズム選択)

注意:このツールは検証用(学習目的)であり、入力内容はサーバーに保存されません。

パスワードの暗号化には PHP の password_hash() 関数を使用しています。アルゴリズムは bcrypt と Argon2 のいずれかを選択できます。




生成結果

サンプルのコード

以下は上記生成サンプルのコードです。

HTML と JavaScript

  • await fetchToken() を送信後に呼び出すことで、毎回トークンを更新する「使い捨てトークン方式」を使用しています。
  • JavaScript でも PHP 側でもトークンを使い捨てにしており、同一トークンの再利用による攻撃を防ぎます。
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>パスワードハッシュ生成</title>
</head>
<body>
<form id="hashForm">
  <div><label for="id">ユーザー名(ID)</label><br>
    <input type="text" name="id" id="id" class="form-control" value="" required>
  </div>
  <div><label for="pass">パスワード:</label><br>
    <input type="text" name="pass" id="pass" class="form-control" value="" required>
  </div>
  <div>
    <label for="algo">ハッシュアルゴリズム:</label><br>
    <select name="algo" id="algo" class="form-control" required>
      <option value="" disabled>アルゴリズムを選択</option>
      <option value="bcrypt" selected>bcrypt(推奨)</option>
      <option value="argon2id">Argon2id(高セキュリティ)</option>
    </select>
  </div>
  <input type="hidden" name="csrf_token" id="csrf_token">
  <div>
    <button type="submit">ハッシュ生成</button>
  </div>
</form>
<div class="output" id="result"></div>

<script>
  // CSRFトークンをサーバーから取得し、hiddenフィールドにセットする関数
  async function fetchToken() {
    try {
      // GETリクエストでCSRFトークンを取得
      const res = await fetch('pass_hash.php?action=get_token');
      // レスポンスが正常(HTTP 200番台)でない場合はエラーをスロー
      if (!res.ok) {
        throw new Error('トークン取得エラー(HTTPステータス ' + res.status + ')');
      }
      // JSONとしてレスポンスを解析
      const data = await res.json();
      // フォームの hidden フィールドにトークンを代入
      document.getElementById('csrf_token').value = data.token;
    } catch (err) {
      // エラー時は画面にメッセージを表示
      document.getElementById('result').innerHTML = '<p class="error">' + err.message + '</p>';
    }
  }

  // ページロード完了時にトークンを自動取得
  document.addEventListener('DOMContentLoaded', fetchToken);

  // フォーム送信時の処理
  document.getElementById('hashForm').addEventListener('submit', async function (e) {
    e.preventDefault(); // デフォルトのフォーム送信(ページ遷移)を防止
    // フォームデータを FormData オブジェクトに変換
    const formData = new FormData(this);
    try {
      // POSTリクエストでフォームデータを送信
      const res = await fetch('pass_hash.php', {
        method: 'POST',
        body: formData
      });
      // レスポンスが正常でない場合はエラーをスロー
      if (!res.ok) {
        throw new Error('ハッシュ生成エラー(HTTPステータス ' + res.status + ')');
      }
      // JSON形式でレスポンスを取得
      const data = await res.json();
      const result = document.getElementById('result');
      // サーバー側からのエラーがある場合は表示
      if (data.error) {
        result.innerHTML = '<p class="error">' + data.error + '</p>';
      } else {
        // 正常にハッシュが返ってきた場合は結果を表示
        result.innerHTML = '<p><strong>ハッシュ:</strong><br><code>' + data.hash + '</code></p>';
      }
      // 使用済みトークンは破棄されるため、新たにトークンを再取得
      await fetchToken();
    } catch (err) {
      // 通信エラーやJSONパースエラー等が発生した場合は表示
      document.getElementById('result').innerHTML =
        '<p class="error">通信エラー:' + err.message + '</p>';
    }
  });

</script>
</body>
</html>

PHP

  • CSRFトークンのワンタイム化:トークンをunset()することで、再利用を防ぎ安全性を高めています。
  • NULLバイトやUTF-8チェックなど、セキュリティ対策を行っています。
  • フロントエンドから argon2id または bcrypt を選べる実装になっています。

<?php
session_start(); // セッションを開始(CSRFトークンの保存に使用)
header('Content-Type: application/json'); // 応答形式をJSONに指定

// ---------------------
// CSRFトークンの発行処理(GETリクエスト)
// ---------------------
if (isset($_GET['action']) && $_GET['action'] === 'get_token') {
  // トークンが未生成なら新しく生成(32バイト → 64文字の16進数)
  if (empty($_SESSION['csrf_token'])) {
      $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
  }
  // JSONでクライアントにトークンを返す
  echo json_encode(['token' => $_SESSION['csrf_token']]);
  exit;
}

// ---------------------
// POSTリクエスト以外は拒否
// ---------------------
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
  http_response_code(405); // 405 Method Not Allowed
  echo json_encode(['error' => '不正なリクエストです。']);
  exit;
}

// ---------------------
// 入力検証関数(文字コードとNULLバイトをチェック)
// ---------------------
function checkInput($var) {
  if (is_array($var)) return array_map('checkInput', $var); // 再帰的にチェック
  if (preg_match('/\0/', $var)) die(json_encode(['error' => '不正な入力です。'])); // NULLバイトは不正
  if (!mb_check_encoding($var, 'UTF-8')) die(json_encode(['error' => '文字エンコーディングエラー。'])); // UTF-8でない場合は拒否
  return trim($var); // 前後の空白を除去
}

$_POST = checkInput($_POST); // POSTデータを検証

// ---------------------
// CSRFトークン検証
// ---------------------
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== ($_SESSION['csrf_token'] ?? '')) {
  echo json_encode(['error' => '不正なリクエストです(CSRFトークンが無効)。']);
  exit;
}

// ---------------------
// 入力データの取得と基本バリデーション
// ---------------------
$id   = $_POST['id'] ?? '';          // ユーザー名
$pass = $_POST['pass'] ?? '';        // パスワード
$algo = $_POST['algo'] ?? 'bcrypt';  // アルゴリズムの種類(デフォルト: bcrypt)

// 入力必須チェック
if ($id === '' || $pass === '') {
  echo json_encode(['error' => 'ユーザー名とパスワードを入力してください。']);
  exit;
}

// ---------------------
// アルゴリズム選択とオプション設定
// ---------------------
$options = [];

if ($algo === 'argon2id') {
  // サーバーがArgon2idに対応しているか確認
  if (!defined('PASSWORD_ARGON2ID')) {
    echo json_encode(['error' => 'このサーバーは Argon2id に対応していません。']);
    exit;
  }

  // Argon2idの設定(セキュリティ強度はサーバー性能に合わせて調整可)
  $algorithm = PASSWORD_ARGON2ID;
  $options = [
    'memory_cost' => 1 << 17, // 131072KB(=128MB)
    'time_cost' => 4,         // 処理回数(計算時間)
    'threads' => 2            // 並列スレッド数
  ];
} else {
  // デフォルトはbcryptを使用
  $algorithm = PASSWORD_BCRYPT;
  $options = ['cost' => 12]; // コスト(値が高いほど計算が重くなる=安全)
}

// ---------------------
// パスワードハッシュ生成
// ---------------------
$hashed = password_hash($pass, $algorithm, $options);

// CSRFトークンは使い捨てのため、ここで無効化
unset($_SESSION['csrf_token']);

// 結果(ハッシュ)をJSONで返す
echo json_encode(['hash' => $hashed]);

bcrypt vs Argon2

bcrypt と Argon2 はどちらも安全なパスワードハッシュアルゴリズムですが、それぞれに特徴と使い分けがあります。以下は両者の主な違いです。

特徴 bcrypt Argon2(特に Argon2id)
開発時期 1999年(Blowfish ベース) 2015年(Password Hashing Competition 優勝)
PHPサポート password_hash($pass, PASSWORD_BCRYPT) password_hash($pass, PASSWORD_ARGON2ID)
安全性 現在も安全だが設計は古い 最新の設計、より強力な攻撃耐性がある
実行速度 比較的早い 重いが安全(メモリ・CPUを大量に使う)
調整パラメータ cost(計算回数) memory_cost、time_cost、threads(細かい調整可)
メモリ使用 少ない(軽量) 多い(DoS耐性、GPU攻撃に強い)
将来性 安全性は保たれるが古い 今後主流になる可能性が高い
選び方の目安
使う場面 推奨
古いPHPバージョン(< 7.2) bcrypt(Argon2未対応)
軽量なアプリ、レスポンスタイム重視 bcrypt
セキュリティ最優先 Argon2id(PHP 7.3+)
WebアプリでDoS攻撃やGPU対策したい場合 Argon2id

PHPでの使い方

詳細は PHP マニュアルの password_hash を参照ください。

bcrypt

password_hash() のアルゴリズムに PASSWORD_BCRYPT を指定します。

$password はユーザーのパスワード文字列です。

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

cost パラメータは、ハッシュ生成にかかる計算量(時間)を制御するためのオプションです。

値を大きくするとセキュリティは上がるが、処理時間も増加し、小さくすると高速になるが、総当たり攻撃(ブルートフォース)に弱くなります。

PHP 8.4.0 からデフォルトの cost オプションの値が 10 から 12 に引き上げられています。

Argon2id

Argon2id ハッシュアルゴリズムを使う場合は、アルゴリズムに PASSWORD_ARGON2ID を指定します。

$hash = password_hash($password, PASSWORD_ARGON2ID, [
  'memory_cost' => 1 << 17,  // ビットシフト演算子を使った書き方(2 の 17 乗(= 131072KB = 128MB)
  'time_cost'   => 4,
  'threads'     => 2,
]);
memory_cost (int)
  • 意味: Argon2 ハッシュの計算に使うメモリ使用量(キロバイト単位)。
  • デフォルト値 : PASSWORD_ARGON2_DEFAULT_MEMORY_COST = 65536(= 64 MB)
  • 推奨値の例: 1 << 17(= 131072 KB = 128 MB)。131072 と書いても同じこと
  • 目的: GPUやASICによる高速な総当たり攻撃を防ぐためにメモリを多く使う。
time_cost (int)
  • 意味: 内部で繰り返すハッシュ計算の回数(ループ数)。
  • デフォルト値: PASSWORD_ARGON2_DEFAULT_TIME_COST = 4
  • 推奨値の例: 4
  • 目的: 攻撃者に対する 時間的コストを上げる。
threads (int)
  • 意味: 並列処理に使うスレッド数(CPUコア数に応じて設定)
  • デフォルト値: PASSWORD_ARGON2_DEFAULT_THREADS = 1
  • 推奨値: サーバーの CPU論理コア数に合わせて 2 以上がおすすめのようです
  • 注意: Linux では実際にはスレッド数よりもプロセス数で制限される場合もある

デフォルト値は定数で定義されていますが、上記に記載している値はバージョンにより異なります。