カテゴリ: PHP 更新日: 2026/01/21

PHPのSQLインジェクション対策を完全解説!初心者でも安全にデータベースを扱う方法

PHP の SQL インジェクション対策(PDO, mysqli)
PHP の SQL インジェクション対策(PDO, mysqli)

先生と生徒の会話形式で理解しよう

生徒

「PHPでデータベースに保存する処理を作っているんですが、SQLインジェクションって危ないと聞きました。どうやって防げばいいんですか?」

先生

「SQLインジェクションは、フォームなどに入力された文字を悪用して不正なSQLを実行されてしまう攻撃のことです。PHPでは、PDOやmysqliを正しく使うことで簡単に対策できますよ。」

生徒

「PDOって聞いたことはありますけど、どう書けば安全になるんですか?」

先生

「では、まずSQLインジェクションがどんな攻撃かを理解して、次にPDOとmysqliを使った安全な書き方を見ていきましょう。」

-

1. SQLインジェクションとは?初心者でもわかる危険性の解説

1. SQLインジェクションとは?初心者でもわかる危険性の解説
1. SQLインジェクションとは?初心者でもわかる危険性の解説

SQLインジェクションとは、ユーザーが入力する文字の中に「特別な命令」を混ぜて、データベースに不正な操作をさせてしまう攻撃です。例えば、ログイン画面で本来はIDとパスワードだけを入力させる部分に、悪意のあるSQL文を紛れ込ませることで、データの書き換えや削除が行われてしまうことがあります。

たとえるなら、注文書を書く欄に「配送先:倉庫→そのまま全部捨てろ」と追加で書かれてしまって、そのまま実行してしまうようなものです。普通はそんな指示は無視すべきですが、対策をしていないとPHPはそのまま命令を実行してしまいます。

2. なぜSQLインジェクションが起きるのか?

2. なぜSQLインジェクションが起きるのか?
2. なぜSQLインジェクションが起きるのか?

原因は「文字列をそのままSQL文にくっつけてしまうこと」です。PHPでありがちな失敗例として、下記のようなコードがあります。


$user = $_POST['user'];
$sql = "SELECT * FROM users WHERE name = '$user'";
$stmt = $pdo->query($sql);

このコードは一見正しく見えますが、ユーザーが次のように入力したらどうでしょう?


' OR '1'='1

SQL文は下記のようになり、全ユーザーの情報が表示されてしまいます。


SELECT * FROM users WHERE name = '' OR '1'='1'

これがSQLインジェクションの典型的な例です。このような危険を防ぐためには、入力された値を「そのままSQLにつなげない」ことが重要です。

3. PDOを使った安全なSQLインジェクション対策

3. PDOを使った安全なSQLインジェクション対策
3. PDOを使った安全なSQLインジェクション対策

もっとも一般的で安全な方法は「プリペアドステートメント」を使うことです。プリペアドステートメントとは、SQL文の中に「?」などのプレースホルダー(後で値を入れる場所)を用意して、入力値を自動で安全に処理してくれる仕組みのことです。

PDOを使った安全なコードは下記のようになります。


$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');

$user = $_POST['user'];

$stmt = $pdo->prepare("SELECT * FROM users WHERE name = :name");
$stmt->bindParam(':name', $user, PDO::PARAM_STR);

$stmt->execute();
$result = $stmt->fetchAll();

ポイントは、値を prepare()bindParam() に渡すことで、mysql側が自動で危険な文字をエスケープ(安全に変換)してくれる点です。これにより、不正なSQL文が実行されることを防げます。

4. mysqliでのSQLインジェクション対策

4. mysqliでのSQLインジェクション対策
4. mysqliでのSQLインジェクション対策

PHPではPDOだけでなく、mysqli を使ったデータベース接続でもSQLインジェクション対策ができます。難しそうに見えますが、基本はPDOと同じ「プリペアドステートメント」を使うだけです。


$mysqli = new mysqli("localhost", "root", "", "test");

$user = $_POST['user'];

$stmt = $mysqli->prepare("SELECT * FROM users WHERE name = ?");
$stmt->bind_param("s", $user);

$stmt->execute();
$result = $stmt->get_result();

「s」は文字列(string)の意味で、値の型を指定します。mysqliでも、prepare → bind → execute の流れで安全にSQLを実行できます。

-

5. SQLインジェクション対策として絶対にやってはいけないこと

5. SQLインジェクション対策として絶対にやってはいけないこと
5. SQLインジェクション対策として絶対にやってはいけないこと

初心者の方が特にやってしまいがちなNG例も紹介します。これらは危険なので避けましょう。

  • ユーザー入力を直接SQLに連結する
  • addslashes() でエスケープすれば大丈夫だと思い込む
  • Magic Quotes(古いPHPの機能)に頼る

現代のPHPでは、プリペアドステートメントを使うことがもっとも安全で、最も推奨される方法です。

6. フォーム入力をバリデーションして安全性をさらに高める

6. フォーム入力をバリデーションして安全性をさらに高める
6. フォーム入力をバリデーションして安全性をさらに高める

SQLインジェクション対策には、プリペアドステートメントが絶対ですが、さらに安全性を高めるためには「バリデーション」が重要です。バリデーションとは、入力値に対して「正しい形式かどうか」を確認する処理です。

例えば、ログインフォームで「ユーザー名は20文字以内」「ひらがなは禁止」などのルールを作り、それを守らない入力をはじくことで、攻撃の入り口を狭めることができます。

コメント
コメント投稿は、ログインしてください

まだ口コミはありません。

カテゴリの一覧へ
新着記事
New1
PHP
PHPのhiddenフィールドとは?初心者でもわかる使い方とセキュリティ対策をやさしく解説!
New2
Python
Pythonのデコレータ(@decorator)とは?関数を拡張する仕組みを解説
New3
Python
Pythonで祝日判定する方法を完全解説!初心者でもわかるholidaysモジュール入門
New4
Python
Pythonのタプルの要素を変更できない理由とその回避策を初心者向けに解説
-
人気記事
No.1
Java&Spring記事人気No1
Python
Pythonで文字列が数値か判定する方法!isdigit()・isnumeric()の違い
No.2
Java&Spring記事人気No2
PHP
PHPのCookieのSecure, HttpOnly, SameSite設定を初心者向けに解説
No.3
Java&Spring記事人気No3
Python
PythonでExcelファイル(.xlsx)を操作する方法を徹底解説!初心者でもできるopenpyxl・pandasの使い方
No.4
Java&Spring記事人気No4
PHP
PHP のコンストラクタ(__construct)とは?使い方を解説
No.5
Java&Spring記事人気No5
Python
Pythonの変数宣言の方法とは?型ヒント(type hints)の使い方を初心者向けに解説!
No.6
Java&Spring記事人気No6
Python
Pythonのインストール&環境構築!Windows・Mac・Linuxでの手順を初心者向けに解説
No.7
Java&Spring記事人気No7
PHP
PHPの配列をソートする方法!sort, rsort, asort, ksortの使い方を丁寧に解説します!
No.8
Java&Spring記事人気No8
Python
Pythonの書き方を基本から解説!はじめてのPythonプログラム
-
-