[PHP]password_verify関数の使い方を徹底解説!安全なログイン認証の実装方法

PHP

PHPでログイン機能を実装する際、パスワードの照合処理は避けて通れない重要な要素です。この記事では、PHPのpassword_verify関数について、初心者の方にも分かりやすく詳しく解説していきます。

password_verify関数とは?

password_verifyは、PHPでハッシュ化されたパスワードと平文のパスワードを安全に比較するための関数です。PHP 5.5.0以降で利用可能で、セキュアなパスワード認証システムを構築する上で欠かせない関数となっています。

基本的な構文

bool password_verify(string $password, string $hash)

パラメータ:

  • $password: ユーザーが入力した平文のパスワード
  • $hash: データベースなどに保存されているハッシュ化されたパスワード

戻り値:

  • パスワードが一致する場合はtrue
  • 一致しない場合はfalse

なぜpassword_verify関数が必要なのか?

パスワードを直接比較するのではなく、password_verifyを使う理由は主に3つあります。

1. セキュリティの確保

パスワードはデータベースにハッシュ化して保存するのが基本です。ハッシュ化されたパスワードは元に戻せないため、データベースが漏洩しても実際のパスワードは守られます。

2. ソルトの自動処理

password_hash関数で生成されたハッシュには、ソルト(ランダムな文字列)が含まれています。password_verifyはこのソルトを自動的に抽出して検証を行うため、開発者が手動でソルトを管理する必要がありません。

3. タイミング攻撃への対策

単純な文字列比較では、比較処理にかかる時間からパスワードの一部を推測される可能性があります。password_verifyはこのようなタイミング攻撃に対して安全な比較を行います。

実際の使用例

基本的な使い方

<?php
// ユーザー登録時:パスワードをハッシュ化してデータベースに保存
$password = "MySecurePassword123";
$hash = password_hash($password, PASSWORD_DEFAULT);
// $hashをデータベースに保存

// ログイン時:入力されたパスワードを検証
$inputPassword = $_POST['password']; // ユーザーが入力したパスワード
$storedHash = "データベースから取得したハッシュ"; // 実際にはDBから取得

if (password_verify($inputPassword, $storedHash)) {
    echo "ログイン成功!";
    // セッションの開始などの処理
} else {
    echo "パスワードが間違っています";
}
?>

実践的なログイン処理の例

<?php
session_start();

// データベース接続(PDOを使用)
try {
    $pdo = new PDO('mysql:host=localhost;dbname=myapp', 'username', 'password');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    die("接続エラー: " . $e->getMessage());
}

// ログイン処理
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $email = $_POST['email'] ?? '';
    $password = $_POST['password'] ?? '';
    
    // ユーザー情報を取得
    $stmt = $pdo->prepare("SELECT id, email, password_hash FROM users WHERE email = ?");
    $stmt->execute([$email]);
    $user = $stmt->fetch(PDO::FETCH_ASSOC);
    
    if ($user && password_verify($password, $user['password_hash'])) {
        // パスワードが正しい場合
        $_SESSION['user_id'] = $user['id'];
        $_SESSION['email'] = $user['email'];
        
        // パスワードハッシュの再ハッシュ化が必要かチェック
        if (password_needs_rehash($user['password_hash'], PASSWORD_DEFAULT)) {
            $newHash = password_hash($password, PASSWORD_DEFAULT);
            $updateStmt = $pdo->prepare("UPDATE users SET password_hash = ? WHERE id = ?");
            $updateStmt->execute([$newHash, $user['id']]);
        }
        
        header('Location: dashboard.php');
        exit;
    } else {
        $error = "メールアドレスまたはパスワードが正しくありません";
    }
}
?>

よくある間違いと注意点

間違い1: ハッシュを直接比較してしまう

// ❌ 悪い例
if ($inputPassword === $storedHash) {
    // これは絶対に動作しません
}

// ✅ 正しい例
if (password_verify($inputPassword, $storedHash)) {
    // 正しい検証方法
}

間違い2: ハッシュ化せずにパスワードを保存

// ❌ 絶対にやってはいけない
$stmt = $pdo->prepare("INSERT INTO users (email, password) VALUES (?, ?)");
$stmt->execute([$email, $password]); // 平文で保存

// ✅ 必ずハッシュ化してから保存
$hash = password_hash($password, PASSWORD_DEFAULT);
$stmt = $pdo->prepare("INSERT INTO users (email, password_hash) VALUES (?, ?)");
$stmt->execute([$email, $hash]);

間違い3: エラーメッセージで情報を漏らす

// ❌ セキュリティリスクあり
if (!$user) {
    echo "このメールアドレスは登録されていません";
} elseif (!password_verify($password, $user['password_hash'])) {
    echo "パスワードが間違っています";
}

// ✅ 情報を明かさない
if (!$user || !password_verify($password, $user['password_hash'])) {
    echo "メールアドレスまたはパスワードが正しくありません";
}

password_needs_rehashとの組み合わせ

セキュリティ標準は時間とともに変化します。password_needs_rehash関数を使うことで、古いハッシュアルゴリズムで作成されたパスワードを自動的に更新できます。

if (password_verify($password, $hash)) {
    // ログイン成功
    
    // ハッシュの更新が必要かチェック
    if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
        // 新しいハッシュを生成
        $newHash = password_hash($password, PASSWORD_DEFAULT);
        
        // データベースを更新
        $stmt = $pdo->prepare("UPDATE users SET password_hash = ? WHERE id = ?");
        $stmt->execute([$newHash, $userId]);
    }
}

パフォーマンスの考慮事項

password_verifyは意図的に処理に時間がかかるように設計されています。これはブルートフォース攻撃(総当たり攻撃)を困難にするためです。通常、1回の検証には0.1〜0.3秒程度かかります。

これは正常な動作なので、心配する必要はありません。むしろ、このコストがセキュリティを高めています。

まとめ

password_verify関数は、PHPで安全なパスワード認証を実装するための必須ツールです。以下のポイントを押さえておきましょう。

  • パスワードは必ずpassword_hashでハッシュ化して保存する
  • ログイン時の検証には必ずpassword_verifyを使用する
  • 平文のパスワードを直接比較しない
  • password_needs_rehashでハッシュを定期的に更新する
  • エラーメッセージで不要な情報を漏らさない

これらの基本を守ることで、ユーザーのパスワードを安全に管理できるシステムを構築できます。セキュリティは妥協してはいけない重要な要素です。正しい方法でパスワード認証を実装しましょう!

タイトルとURLをコピーしました