PHPで安全なフォーム処理を実装する方法【バリデーション・エスケープ・CSRF・SQLインジェクション】

Webフォームはユーザーとの重要な接点ですが、不正入力や攻撃のリスクも抱えています。特にPHPでは、適切な対策を講じないとXSSやCSRF、SQLインジェクションなどの脆弱性を招く恐れがあります。本記事では、PHPで安全にフォーム処理を行うための基本「バリデーション」「エスケープ」「CSRF対策」「SQLインジェクション対策」の実装方法を具体例付きで解説します。

バリデーション:入力の正しさを確認する

バリデーションは、ユーザーからの入力が正しいかどうかを検証する処理です。不正な入力がそのまま処理されると、アプリケーションの動作に予期せぬ影響を与えることがあります。

サンプルコード:POSTデータの検証

$name = $_POST['name'] ?? '';
$email = $_POST['email'] ?? '';
$url = $_POST['url'] ?? '';
$age = $_POST['age'] ?? '';
$ip = $_POST['ip'] ?? '';
$errors = [];

if ($name === '') {
    $errors[] = '名前は必須です。';
}

if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $errors[] = 'メールアドレスの形式が正しくありません。';
}

if ($url && !filter_var($url, FILTER_VALIDATE_URL)) {
    $errors[] = 'URLの形式が正しくありません。';
}

if ($age && !filter_var($age, FILTER_VALIDATE_INT, ["options" => ["min_range" => 1, "max_range" => 120]])) {
    $errors[] = '年齢は1〜120の整数で入力してください。';
}

if ($ip && !filter_var($ip, FILTER_VALIDATE_IP)) {
    $errors[] = 'IPアドレスの形式が正しくありません。';
}

主なバリデーション関数

検証内容関数・手法
必須入力empty(), isset()
メール形式filter_var($email, FILTER_VALIDATE_EMAIL)
URL形式filter_var($url, FILTER_VALIDATE_URL)
整数チェックfilter_var($value, FILTER_VALIDATE_INT)
範囲付き整数FILTER_VALIDATE_INT + min_range, max_range オプション
IPアドレスfilter_var($ip, FILTER_VALIDATE_IP)
数値かどうかis_numeric()
文字列の長さ制限strlen()

エスケープ:表示時に無害化する

入力内容をそのままHTML出力すると、クロスサイトスクリプティング(XSS)の危険があります。PHPではhtmlspecialchars()を使って、HTMLに変換される特殊文字を無効化できます。

サンプルコード:エスケープして表示

$name = htmlspecialchars($name, ENT_QUOTES, 'UTF-8');
$email = htmlspecialchars($email, ENT_QUOTES, 'UTF-8');

echo "<p>名前:{$name}</p>";
echo "<p>メール:{$email}</p>";

注意点

  • フォームのvalue属性にもhtmlspecialchars()を使う
  • DB保存時ではなく「画面に出すとき」にエスケープする

htmlspecialchars()filter_var()の違い

項目htmlspecialchars()filter_var()
目的HTMLのエスケープ(無害化)入力値の検証・正当性の確認
主な用途XSS対策(表示時)バリデーション(受信時)
使用タイミング表示直前入力直後
htmlspecialchars($str)filter_var($email, FILTER_VALIDATE_EMAIL)
  • htmlspecialchars() は出力時の無害化を目的とし、特にHTML内で表示する際に使用します。
  • filter_var() は受け取ったデータが想定通りかを確認するための関数で、入力チェック(バリデーション)に使います。

この2つは補完関係にあり、filter_varで検証し、htmlspecialcharsで表示を安全にするという順序が基本です。


CSRF対策:正当なフォーム送信を保証する

CSRF(クロスサイトリクエストフォージェリ)は、ユーザーが意図しない操作を第三者に実行させる攻撃です。PHPではトークンを使った対策が一般的です。

サンプルコード:トークン生成と検証

フォーム表示時(トークン発行)

session_start();
if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
<form method="POST" action="form.php">
    <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token'], ENT_QUOTES, 'UTF-8') ?>">
    <!-- 他のフォーム項目 -->
    <input type="submit" value="送信">
</form>

送信時の検証

session_start();
if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
    die('不正なアクセスです。');
}

SQLインジェクション対策:プリペアドステートメントの利用

SQLインジェクションとは、SQL文に悪意ある入力を混入させてデータベースを不正に操作する攻撃です。PDOやMySQLiでプリペアドステートメントを使うことで、この脅威を防ぐことができます。

サンプルコード:PDOによる安全なINSERT処理

try {
    $pdo = new PDO('mysql:host=localhost;dbname=sample_db;charset=utf8', 'user', 'password');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $stmt = $pdo->prepare('INSERT INTO users (name, email) VALUES (:name, :email)');
    $stmt->bindParam(':name', $name);
    $stmt->bindParam(':email', $email);
    $stmt->execute();

    echo "登録が完了しました。";
} catch (PDOException $e) {
    echo "エラー: " . $e->getMessage();
}

注意点

  • query()に変数を直接渡さない
  • prepare() + bindParam() / execute() を必ず使用する
  • データベースのエラーメッセージは公開しない

まとめ:安全なフォーム処理でWebアプリを守る

フォームの安全性は、バリデーション・エスケープ・CSRF対策・SQLインジェクション対策の4本柱で成り立っています。以下のポイントをおさえることで、PHPフォームのセキュリティを大幅に向上させることができます。

  • 入力は信用せず、厳格にバリデーション
  • 画面表示には必ずエスケープ処理
  • トークンを用いたCSRF対策を徹底
  • DBアクセスには必ずプリペアドステートメントを使用

セキュアなフォーム実装は、ユーザー信頼の第一歩です。今回紹介したコードをベースに、実案件でも安全なフォーム処理を実現してみてください。

Contact

ウェブサイトの制作や運用に関わる
お悩みやご相談
お気軽にお問い合わせ下さい

ウェブサイトと一口に言っても、企業サイトやECサイト、ブログ、SNSなど、その“カタチ”は目的に応じてさまざまであり、構築方法や使用する技術も大きく異なります。株式会社コナックスでは、お客様のご要望やブランドの個性を丁寧に汲み取り、最適なウェブサイトの“カタチ”をご提案いたします。

デザイン、ユーザビリティ、SEO対策はもちろん、コンテンツ制作やマーケティング戦略に至るまで、あらゆるフェーズでお客様のビジネスに寄り添い、成果につながるウェブサイトづくりをサポートいたします。私たちは、ウェブサイトの公開をゴールではなくスタートと捉え、お客様のビジネスの成功に向けて共に伴走してまいります。