HTTPリファラー、POSTメソッドの確認
フォーム送信時に、特定のページからのリクエストかどうか、またPOSTメソッドで送信されているかを確認することで、不正なアクセスを防ぐことができます。ここでは、HTTPリファラーチェックとPOSTメソッドの確認をコードに追加する方法を紹介します。
register.htmlはregister.phpに変更してください。
// HTTPリファラーチェック
if (empty($_SERVER['HTTP_REFERER']) || strpos($_SERVER['HTTP_REFERER'], 'register.php') === false) {
http_response_code(403);
die("不正なアクセスです。");
}PHP解説
- $_SERVER[‘HTTP_REFERER’] を確認し、リファラーが register.php を含んでいるかを確認します。
- strpos() を使って register.php がURL内に含まれているかを判定します。
- リファラーが空の場合や条件を満たさない場合、不正なアクセスと判断し処理を中断します。
// POSTメソッド確認
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(403);
die("不正なアクセスです。");
}PHP解説
- $_SERVER[‘REQUEST_METHOD’] を使って、リクエストが POST であることを確認します。
- POST以外のリクエストが来た場合(例えばGETリクエスト)、処理を中断し、不正アクセスとみなします。
<?php
// HTTPリファラーチェック
if (empty($_SERVER['HTTP_REFERER']) || strpos($_SERVER['HTTP_REFERER'], 'register.php') === false) {
http_response_code(403);
die("不正なアクセスです。");
}
// POSTメソッド確認
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(403);
die("不正なアクセスです。");
}
// データベース接続情報
$host = 'localhost';
$dbname = 'member_system';
$charset = 'utf8';
$username = 'root';
$password = 'pass';PHPCSRF対策
CSRF(クロスサイトリクエストフォージェリ)攻撃を防ぐために、フォーム送信時に CSRFトークン を導入することが効果的です。トークンを使うことで、正規のリクエストであることを確認し、不正アクセスを防止します。ここではCSRFトークンを生成し、検証する仕組みを紹介します。
フォームにトークンを埋め込む(register.php)
ファイルをhtmlからphpに変更してください。
<?php
session_start();
// CSRFトークンを生成し、セッションに保存
$token = bin2hex(random_bytes(32));
$_SESSION['csrf_token'] = $token;
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>会員登録システム</title>
</head>
<body>
<form action="insert.php" method="post">
<div>
<label>
ユーザー名:
<input type="text" name="name">
</label>
</div>
<div>
<label>
メールアドレス:
<input type="text" name="mail">
</label>
</div>
<div>
<label>
パスワード:
<input type="password" name="pass">
</label>
</div>
<!-- CSRFトークンを埋め込む -->
<input type="hidden" name="csrf_token" value="<?php echo $token; ?>">
<input type="submit" value="新規登録">
</form>
</body>
</html>register.phpまた、index.htmlのリンク先もregister.phpに書き換えてください。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>会員登録システム</title>
</head>
<body>
<h1>会員登録システム</h1>
<a href="register.php">新規登録</a>
</body>
</html>index.htmlポイント
- トークンの生成
- random_bytes() でランダムなトークンを生成し、セッションに保存します。
- トークンの埋め込み
- フォームの hidden フィールドでトークンを送信。
サーバー側でトークンを検証(insert.php)
コードの先頭に追加して下さい。この仕組みによって、CSRF攻撃を防ぎ、正規のフォームからの送信のみを許可することができます。
<?php
session_start(); // セッションを開始
// CSRFトークンの検証
if (empty($_POST['csrf_token']) || $_POST['csrf_token'] !== ($_SESSION['csrf_token'] ?? '')) {
http_response_code(403);
die("不正なアクセスです。");
}
// トークンを使い捨てにする(再利用防止)
unset($_SESSION['csrf_token']);
// HTTPリファラーチェック
if (empty($_SERVER['HTTP_REFERER']) || strpos($_SERVER['HTTP_REFERER'], 'register.php') === false) {
die("不正なアクセスです。<br><a href='register.php'>戻る</a>");
}
// POSTメソッド確認
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
die("不正なリクエストです。<br><a href='register.php'>戻る</a>");
}PHPポイント
- トークンの検証
- サーバー側で送信されたトークンとセッションのトークンが一致するかを確認。
- トークンの使い捨て
- トークンを検証後に削除し、再利用を防ぎます。
トランザクション
トランザクションとは、データベース操作中のエラーによる不整合を防ぐ仕組みです。トランザクションは一連の処理をひとまとまりとして扱い、成功時に確定(コミット)、失敗時に元に戻す(ロールバック)を実行します。例えば、複数のデータ挿入や更新が途中で失敗しても、ロールバックにより変更を無効化でき、データの整合性を保てます。これにより、システムの信頼性と安全性が向上します。
try {
$dsn = "mysql:host=$host;dbname=$dbname;charset=$charset";
$pdo = new PDO($dsn, $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
// トランザクションを開始
$pdo->beginTransaction();
$checkSql = "SELECT COUNT(*) FROM users WHERE mail = ?";
$checkStmt = $pdo->prepare($checkSql);
$checkStmt->execute([$mail]);
$count = $checkStmt->fetchColumn();
if ($count > 0) {
// 重複があればロールバックして終了
$pdo->rollBack();
die("このメールアドレスはすでに登録されています。<br><a href='register.html'>戻る</a>");
}
$sql = "INSERT INTO users (name, mail, pass) VALUES (?, ?, ?)";
$stmt = $pdo->prepare($sql);
$stmt->execute([$name, $mail, $pass]);
// トランザクションをコミット
$pdo->commit();
echo "登録が完了しました!";
echo '<br><a href="index.html">トップに戻る</a>';
} catch (PDOException $e) {
// エラー発生時はロールバック
if (isset($pdo) && $pdo instanceof PDO && $pdo->inTransaction()) {
$pdo->rollBack();
}
echo "エラーが発生しました: " . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8');
}
?>PHPコードが長くなったので、トランザクション挿入部分のみのコードになります。
ポイント
- トランザクションの開始: beginTransaction() を呼び出して、処理の一連の開始を明示します。
- 成功時のコミット: データベース操作がすべて正常に完了した場合に、commit() を呼び出して変更を確定します。
- 失敗時のロールバック: 途中でエラーが発生した場合に、rollBack() を呼び出して、データを元の状態に戻します。
これらの改良を行うことで、フォームの安全性とユーザーの利便性が大幅に向上します。特にCSRFトークンの導入は、セキュリティの観点で欠かせない要素です。これらを組み込むことで、より実用的な会員登録フォームが完成します。



コメント