620 文字
3 分
PHPでワンタイムパスワードのリプレイ攻撃対策
使用済みのワンタイムパスワードを再利用できないようにするには、データベースやキャッシュに保存する方法が一般的です。以下に、PHPでデータベースとキャッシュを利用した具体的な対策例を紹介します。
データベースを利用する場合
-
データベースにテーブルを作成し、以下のカラムを定義します。
user_id
: ユーザーIDotp
: ワンタイムパスワードtimestamp
: ワンタイムパスワードの生成時刻
-
ワンタイムパスワードを生成したら、データベースにレコードを挿入します。
<?php
$userId = 1; // ユーザーID$otp = generateOTP(); // ワンタイムパスワードを生成$timestamp = time(); // 現在時刻を取得
$db = new PDO('mysql:host=localhost;dbname=test', 'username', 'password');$stmt = $db->prepare('INSERT INTO otps (user_id, otp, timestamp) VALUES (:user_id, :otp, :timestamp)');$stmt->bindParam(':user_id', $userId);$stmt->bindParam(':otp', $otp);$stmt->bindParam(':timestamp', $timestamp);$stmt->execute();
?>
- ワンタイムパスワードを検証する前に、データベースにレコードが存在するか確認します。
<?php
$userId = 1; // ユーザーID$otp = '123456'; // 入力されたワンタイムパスワード$timestamp = time(); // 現在時刻を取得
$db = new PDO('mysql:host=localhost;dbname=test', 'username', 'password');$stmt = $db->prepare('SELECT * FROM otps WHERE user_id = :user_id AND otp = :otp AND timestamp >= :timestamp - 30'); // 過去30秒以内に生成されたワンタイムパスワードのみ検証$stmt->bindParam(':user_id', $userId);$stmt->bindParam(':otp', $otp);$stmt->bindParam(':timestamp', $timestamp);$stmt->execute();
$result = $stmt->fetchAll();
if (count($result) > 0) { // ワンタイムパスワードが有効 echo 'Valid OTP';
// 使用済みのワンタイムパスワードを削除 $stmt = $db->prepare('DELETE FROM otps WHERE user_id = :user_id AND otp = :otp'); $stmt->bindParam(':user_id', $userId); $stmt->bindParam(':otp', $otp); $stmt->execute();} else { // ワンタイムパスワードが無効 echo 'Invalid OTP';}
?>
キャッシュを利用する場合
-
Memcached や Redis などのキャッシュサーバーをインストールします。
-
ワンタイムパスワードを生成したら、キャッシュに保存します。
<?php
$userId = 1; // ユーザーID$otp = generateOTP(); // ワンタイムパスワードを生成$timestamp = time(); // 現在時刻を取得
$memcached = new Memcached();$memcached->addServer('localhost', 11211);$memcached->set($userId . ':' . $otp, $timestamp, 30); // 30秒間キャッシュする
?>
- ワンタイムパスワードを検証する前に、キャッシュにレコードが存在するか確認します。
<?php
$userId = 1; // ユーザーID$otp = '123456'; // 入力されたワンタイムパスワード$timestamp = time(); // 現在時刻を取得
$memcached = new Memcached();$memcached->addServer('localhost', 11211);$cachedTimestamp = $memcached->get($userId . ':' . $otp);
if ($cachedTimestamp !== false && $cachedTimestamp >= $timestamp - 30) { // ワンタイムパスワードが有効 echo 'Valid OTP';
// キャッシュからレコードを削除 $memcached->delete($userId . ':' . $otp);} else { // ワンタイムパスワードが無効 echo 'Invalid OTP';}
?>
その他の対策
- ワンタイムパスワードの長さを十分に長くする (少なくとも 6 桁)
- ワンタイムパスワードの有効期限を短くする (30 秒など)
- ワンタイムパスワードを複数回入力できないようにする (例えば、入力画面に残り試行回数カウンターを表示する)
これらの対策を組み合わせることで、より安全な二段階認証システムを構築することができます。