企業のWebサービスを脅かすサイバー攻撃の中でも特に注意すべき手法の一つが「SQLインジェクション」です。SQLインジェクションとはWebアプリケーションの脆弱性を悪用して、データベースに不正なプログラムを注入(インジェクション)し、不正に操作をするサイバー攻撃です。近年、SQLインジェクション攻撃による被害は増加傾向にあります。
この記事では、SQLインジェクションの基本概念から仕組み、具体的な対策方法まで詳しく解説します。Webサイトやアプリケーションを運営する企業の担当者がセキュリティリスクを理解し、適切な防御策を立てるための参考にしてください。

ページコンテンツ
SQLインジェクションとは?
SQLインジェクションとは、Webアプリケーションの脆弱性を悪用して、不正なSQL文を送り込み、データベースを不正に操作する攻撃手法です。SQLはデータベースを操作するための標準的な言語で、多くのWebサイトやアプリケーションで使用されています。
この攻撃が成功すると、攻撃者は以下のような悪意ある操作が可能になります。
- データベースに保存された個人情報や機密情報の不正閲覧・窃取
- データベース内のデータの改ざんや消去
- 認証プロセスの回避(パスワードなしでのログイン)
- Webサイトの改ざん
- システム管理者権限の取得
SQLインジェクションは、IPAの「ソフトウェア等の脆弱性関連情報」の報告においても、クロスサイトスクリプティング(XSS)に次いで2番目に届け出が多い攻撃手法です。SQLインジェクションは依然として深刻な脅威であることを示しています。また、脆弱性に関する被害事例として最も多いのは、全体の57%を占める「本物サイト上への偽情報の表示」です。
SQLインジェクションの影響やクロスサイトスクリプティングとの違い
SQLインジェクション攻撃は企業に深刻な影響をもたらします。
某アウトレット運営会社では、2017年から2018年にかけて複数回のSQLインジェクション攻撃により、約27万件のメールマガジン会員情報が漏えいしました。
また、2020年には事務用品を扱うECサイトで最大12万件の顧客情報(一部クレジットカード情報を含む)が流出する被害が発生しました。
さらに2022年、国内の大手リサーチ会社がSQLインジェクション攻撃を受け、約10万件の個人情報が流出し、サービスを数日間停止する事態に陥っています。
このような被害は、賠償金の支払い、企業信頼の低下、サービス停止による売上損失、システム復旧コスト、さらには行政処分などの二次的な損害にもつながります。
SQLインジェクションとクロスサイトスクリプティング(XSS)はどちらもWebアプリケーションの脆弱性を突く攻撃ですが、異なっているのは以下の点です。
- SQLインジェクションはデータベースを、XSSはユーザーのブラウザを標的とする
- SQLインジェクションはサーバー側で、XSSはクライアント側で実行
- SQLインジェクションはデータベース内の情報漏えいや改ざん、XSSはCookie窃取やセッションハイジャックなどが主な被害内容
両者ともWebサイトのセキュリティを脅かす深刻な脆弱性であり、それぞれに適した対策が必要です。
SQL インジェクションの仕組み
SQLインジェクションがどのように機能するのか、その基本的なメカニズムを解説します。
通常、Webアプリケーションがデータベースと連携する際の処理の流れは以下の通りです。
- ユーザーがWebフォームなどから情報(IDやパスワードなど)を入力
- Webアプリケーションがその入力値を基にSQL文を生成
- 生成されたSQL文がデータベースに送信され実行される
- データベースから結果が返され、Webアプリケーションを通じてユーザーに表示される
例:SELECT * FROM users WHERE id = ‘taro’;
SQLインジェクション攻撃では、攻撃者が入力フィールドに特殊な文字や構文を含む悪意ある入力を行います。
- 攻撃者が脆弱性のあるWebアプリケーションを見つける
- 入力フィールドに不正なSQL構文(例:’ OR ‘1’=’1)を入力
- Webアプリケーションはこの入力をそのままSQL文に組み込む
- 結果として以下のようなSQL文が生成される。
例:SELECT * FROM users WHERE id = ‘taro’ OR ‘1’=’1′;
この例では、OR ‘1’=’1’という条件が追加されています。’1’=’1’は常に真となるため、この条件は「idが’taro’に一致するか、または1=1が真である(常に真)」という意味です。結果として、WHERE句の条件は常に真となり、usersテーブルの全てのレコードが返されてしまいます。
これはごく単純な例ですが、実際の攻撃ではさらに複雑な構文が使用され、データベース内の情報の窃取、改ざん、削除などが行われます。データベースの種類によっては、OSコマンドの実行やファイルシステムへのアクセスを許してしまう可能性もあります。
SQLインジェクションの対策方法
SQLインジェクションを防ぐためには、以下の対策を総合的に実施することが重要です。
プレースホルダの利用
プレースホルダとは、SQL文の中で値が変動する部分を、事前に定義した記号で置き換える仕組みです。
プレースホルダ(パラメータ化クエリ)は、SQLインジェクション対策として最も効果的な方法の一つです。プレースホルダを使用すると、SQL文の構造とデータ(ユーザー入力など)を明確に分離できます。
プレースホルダでは、SQL文の中で変動する値の部分を一時的に疑問符(?)やコロン(:name)などの記号で置き換えます。そして、実行時にデータベースエンジンがこれらの記号を実際の値で置換します。
この方法では、入力データがSQLコードとして解釈されることはなく、純粋なデータとして処理されるため、SQLインジェクションを防止できます。
例:
// 安全なSQL(プレースホルダ使用)
$sql = “SELECT * FROM users WHERE mail = :mail AND pass = :pass”;
$stmt = $pdo->prepare($sql);
$stmt->bindParam(‘:mail’, $mail);
$stmt->bindParam(‘:pass’, $pass);
$stmt->execute();
プレースホルダには主に「静的プレースホルダ」と「動的プレースホルダ」の2種類です。静的プレースホルダはデータベース側で変換処理が行われるため、より安全性が高いとされています。一方、動的プレースホルダはアプリケーション側で変換処理が行われるため、ライブラリの脆弱性に影響を受ける可能性があります。
エスケープ処理の実施
エスケープ処理とは、SQLにおいて特別な意味を持つ文字(シングルクォート「’」、ダブルクォート「”」、バックスラッシュ「\」など)を無効化する処理です。これにより、不正なSQL文が実行されるのを防ぎます。
例えば、MySQLでのエスケープ処理は以下の通りです。
- シングルクォート(‘) → ‘
- ダブルクォート(“) → “
- バックスラッシュ() → \
- NULLバイト → \0
各プログラミング言語やデータベースには、エスケープ処理を行うための関数やメソッドが用意されています。例えば、PHPのmysqli_real_escape_string()やPDO::quote()などです。
ただし、エスケープ処理だけではSQLインジェクションを完全に防げない場合があるため、可能な限りプレースホルダと併用することが推奨されています。
入力値検証の実施
ユーザーからの入力に対して、適切な検証を行うのも重要な対策です。例えば、数値のみを受け付ける項目では文字列を拒否したり、特殊な記号を使用できないようにしたりすることが挙げられます。
具体的な方法としては以下の通りです。
- 入力可能な文字の種類を制限する(英数字のみ、数字のみなど)
- 入力の長さに制限を設ける
- 想定外の形式の入力を拒否する(例:電話番号フィールドにアルファベットがある場合)
- 正規表現を使用してパターンマッチングを行う
ただし、入力値検証だけではSQLインジェクションを完全に防げないため、プレースホルダやエスケープ処理と組み合わせて使用することが重要です。
Webアプリケーションファイアウォール(WAF)の導入
Web Application Firewall(WAF)は、Webアプリケーションへの不正なアクセスや攻撃を検知・遮断するセキュリティ対策ツールです。WAFはSQLインジェクションだけでなく、クロスサイトスクリプティング(XSS)やクロスサイトリクエストフォージェリ(CSRF)など、さまざまな攻撃からWebアプリケーションを保護します。
WAFは通信の内容をチェックし、SQLインジェクションに使われる不正なSQL文パターンを検知すると、その通信を遮断します。WAFはアプリケーション層(OSI参照モデルの第7層)で動作するため、一般的なファイアウォールよりも高度な保護機能を提供するものです。
WAFには主にハードウェア型、ソフトウェア型、クラウド型の3種類があり、企業のニーズや予算に応じて選択できます。
Webアプリケーションの最新状態の維持
Webアプリケーションやそのフレームワーク、ライブラリを常に最新の状態に保つことも重要な対策です。開発元から提供されるアップデートには、セキュリティ脆弱性の修正が含まれている場合が多いからです。
特に、WordPressやJoomlaなどのCMSを使用している場合は、本体だけでなく、プラグインやテーマも含めて定期的にアップデートを行ってください。
また、JPCERTコーディネーションセンターとIPA(独立行政法人情報処理推進機構)が共同で運営するJVN iPedia(脆弱性対策情報データベース)などを定期的にチェックし、最新の脆弱性情報を入手するのも効果的です。
データベースサーバーのログ監視
データベースサーバーのログを定期的に監視すると、SQLインジェクション攻撃の兆候を早期に発見できます。ログにはSQL文の実行履歴が記録されているため、不審なSQLクエリが実行されていないか確認が可能です。
ログ監視のポイントは以下の通りです。
- 通常とは異なるパターンのSQLクエリ
- 短時間に大量のクエリが実行されている
- 権限昇格を試みるようなクエリ
- データベース構造情報を取得しようとするクエリ
自動ログ監視ツールを導入すると、24時間体制での監視が可能になり、攻撃の早期発見・対応が期待できます。
脆弱性診断の実施
定期的に自社のWebアプリケーションに対して脆弱性診断を実施することも重要です。脆弱性診断では、セキュリティの専門家が擬似的な攻撃を行い、Webアプリケーションの脆弱性を洗い出します。
脆弱性診断には主に以下の種類があります:
- 静的解析ーソースコードを解析して潜在的な脆弱性を発見する
- 動的解析ー実際にWebアプリケーションを動作させながら脆弱性を発見する
- ペネトレーションテストー専門家が実際の攻撃者のように振る舞い、システムの脆弱性を探る
これらの診断を定期的に実施することで、新たに発見された脆弱性に対して迅速に対応できます。
エラー表示の抑制
SQLインジェクション攻撃の初期段階では、攻撃者はデータベース構造を把握するためにエラーメッセージを利用する場合があります。詳細なエラーメッセージによってデータベースの種類やテーブル構造などの情報が漏えいする可能性があります。
そのため、本番環境ではデータベースエラーの詳細を直接ユーザーに表示せず、一般的なエラーメッセージに置き換えることが重要です。エラーの詳細はログに記録し、開発者やシステム管理者のみが確認できるようにしてください。
SQL文の代替案の検討
場合によっては、SQLを直接使用する代わりに、ORマッパーなどの高水準のデータベースアクセス手法を使用することも検討しなければなりません。ORマッパーは、オブジェクト指向プログラミングとリレーショナルデータベースの橋渡しをする技術で、SQLインジェクションのリスクを減らせます。
代表的なORマッパーは以下の通りです。
- Java: Hibernate
- PHP: Doctrine
- Python: SQLAlchemy
- Ruby: ActiveRecord
- .NET: Entity Framework
これらのフレームワークは内部でSQLインジェクション対策を実装しているため、開発者が直接SQLを扱う機会が減り、セキュリティリスクも低減します。
SQLインジェクション対策の例
実際のコード例を通じて、SQLインジェクション対策の実装方法を見ていきます。
プレースホルダの利用
異なるプログラミング言語でのプレースホルダ実装例を紹介します。
PHP(PDO):
// 危険なコード(SQLインジェクションの脆弱性あり)
$sql = “SELECT * FROM users WHERE mail='” . $mail . “‘ AND pass='” . $pass . “‘;”;
$result = $pdo->query($sql);
// 安全なコード(プレースホルダ使用)
$sql = “SELECT * FROM users WHERE mail = :mail AND pass = :pass”;
$stmt = $pdo->prepare($sql);
$stmt->bindParam(‘:mail’, $mail);
$stmt->bindParam(‘:pass’, $pass);
$stmt->execute();
$result = $stmt->fetchAll();
Java(JDBC):
// 危険なコード
String sql = “SELECT * FROM users WHERE username = ‘” + username + “‘ AND password = ‘” + password + “‘”;
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(sql);
// 安全なコード(プレースホルダ使用)
String sql = “SELECT * FROM users WHERE username = ? AND password = ?”;
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1, username);
pstmt.setString(2, password);
ResultSet rs = pstmt.executeQuery();
Python(SQLite3):
# 危険なコード
cursor.execute(“SELECT * FROM users WHERE username = ‘” + username + “‘ AND password = ‘” + password + “‘”)
# 安全なコード(プレースホルダ使用)
cursor.execute(“SELECT * FROM users WHERE username = ? AND password = ?”, (username, password))
エスケープ処理
エスケープ処理の実装例も見ていきます。
PHP(mysqli):
// mysqli_real_escape_stringを使用したエスケープ処理
$mail = mysqli_real_escape_string($conn, $mail);
$pass = mysqli_real_escape_string($conn, $pass);
$sql = “SELECT * FROM users WHERE mail=’$mail’ AND pass=’$pass'”;
$result = mysqli_query($conn, $sql);
Java:
// Apache CommonsのStringEscapeUtilsを使用
import org.apache.commons.lang3.StringEscapeUtils;
String safeUsername = StringEscapeUtils.escapeSql(username);
String sql = “SELECT * FROM users WHERE username = ‘” + safeUsername + “‘”;
SQLインジェクション対策:エスケープ処理
エスケープ処理は、データベースやプログラミング言語によって異なる場合があります。
一般的なデータベースでエスケープすべき主な文字は以下の通りです。
文字 |
内容 |
シングルクォート(‘) |
文字列の区切りに使用され、SQLインジェクションで最も悪用される |
ダブルクォート(“) |
一部のデータベースでは文字列区切りに使用される |
バックスラッシュ(\) |
エスケープ文字自体 |
セミコロン(;) |
SQL文の区切りに使用される |
ハイフン(-)と連続するハイフン(–) |
コメント開始を意味する |
スラッシュとアスタリスク(/*) |
複数行コメントの開始を意味する |
NULLバイト |
特定の言語では文字列終端として扱われる |
データベース製品によってエスケープ方法が異なる場合があります。
MySQL:
- シングルクォート(‘) → \’
- ダブルクォート(“) → \”
- バックスラッシュ(\) → \\
- NULLバイト → \0
- 改行(\n) → \\n
- キャリッジリターン(\r) → \\r
- コントロールZ(\Z) → \\Z
PostgreSQL:
- シングルクォート(‘) → ”(シングルクォートを2つ)
Oracle:
- シングルクォート(‘) → ”(シングルクォートを2つ)
エスケープ処理を行う際の注意点は以下の通りです。
- データベース固有のエスケープルールを正確に適用する
- 文字エンコーディングの違いに注意する
- 可能な限りプレースホルダと併用する
- エスケープ処理を忘れずに全ての外部入力に適用する
エスケープ処理は確実に実施しないと、一部のSQLインジェクション攻撃に対して脆弱性が残る可能性があります。
SQLインジェクション対策の注意点
SQLインジェクション対策を実施する際の注意点について説明します。
エスケープ処理の漏れ
SQLインジェクション対策として最も多い失敗は、一部の入力データに対してエスケープ処理を忘れてしまうことです。特に以下のようなケースで見落とされがちです。
- 検索条件の一部(WHERE句のLIKE演算子など)
- ORDER BY句などでのソート条件
- テーブル名やカラム名を動的に変更する場合
- バッチ処理などでのSQL生成
すべての外部入力値を例外なくエスケープ処理することが重要です。また、可能な限りテーブル名やカラム名を動的に変更するような処理は避けなければなりません。
不適切な入力値検証
入力値検証(バリデーション)を実施する際、以下のようなアプローチが推奨されます。
- ホワイトリスト方式(許可された文字のみ受け入れる)
- サーバーサイドでの必ずバリデーションを実施
- データ型に応じた適切な検証(数値は整数型として処理するなど)
適切な対策レベルの選定
セキュリティ対策は重要ですが、過剰な実装は開発効率や運用コストに影響を与える可能性があります。以下の対応が効果的です。
- リスクに応じた適切な対策レベルの選定
- 既存のフレームワークやライブラリの活用
- 開発チーム全体でのセキュリティ知識の共有
また、複数の対策を組み合わせる「多層防御」の考え方が重要です。プレースホルダの使用を基本としつつ、WAFの導入や定期的な脆弱性診断を組み合わせることで、より堅牢なセキュリティ体制を構築できます。
SQLインジェクション対策でWebサイトの安全性を高めよう
SQLインジェクションは古くから知られている攻撃手法ですが、今日でもWebサイトの脆弱性を狙った攻撃は増加しています。個人情報や機密情報の漏えい、Webサイトの改ざんなど、SQLインジェクションによる被害は企業の信頼を大きく損なう可能性があります。
SQLインジェクション対策は一度実施して終わりではなく、継続的に見直し、改善していくことが重要です。新たな脆弱性や攻撃手法が日々発見されるため、常に最新の情報をキャッチアップし、適切な対応を取らなければなりません。
Webサイトやアプリケーションのセキュリティは、企業の信頼性に直結する重要な要素です。SQLインジェクション対策を徹底し、ユーザーの大切な情報を守ってください。
専門的な知識や人材が不足している場合は、セキュリティ専門企業による診断サービスやコンサルティングの利用をおすすめします。
当社では、さまざまなニーズに対応できる幅広いセキュリティソリューションを取り扱っており、専門的な知識を有するスタッフがお客様の課題に合わせた最適なソリューションをご提案します。お気軽にお問い合わせください。