1. まず共通原則
SQLインジェクションは、PostgreSQL、MariaDB、MySQL、Oracle、SQL Server、SQLiteなど、SQLを使うDBMSで起こり得ます。
原因はDB製品そのものではなく、多くの場合、利用者入力をSQL文字列に連結してしまうことです。
OWASPも、SQLインジェクション対策の中心として、プリペアドステートメント/パラメータ化クエリを第一に挙げています。これはSQLの構造と利用者入力を分離する考え方です。
2. DBMS別の違いを理解する
全体比較
| DBMS | よく使われる環境 | SQLi確認で見るポイント | 防御の基本 |
|---|---|---|---|
| MariaDB / MySQL | WordPress、PHP、LAMP | URLパラメータ、検索、ログイン、プラグイン独自SQL | プレースホルダ、PDO/mysqli、$wpdb->prepare() |
| PostgreSQL | 業務システム、API、SaaS | 型変換、JSON、配列、関数、動的SQL | $1, $2 形式のバインド、Prepared Statement |
| Oracle Database | 大企業、基幹系、金融、ERP | PL/SQL、動的SQL、権限、ストアドプロシージャ | バインド変数、DBMS_ASSERT、権限分離 |
| SQL Server | Windows系業務システム、社内システム | 動的SQL、ストアドプロシージャ、ADO.NET | @param、sp_executesql、SqlParameter |
| SQLite | スマホアプリ、小規模CMS、組込み | ローカルDB、ファイル権限、アプリ内検索 | 名前付きパラメータ、ファイル権限 |
| 汎用ORM系 | Laravel、Django、Rails、Prisma等 | 生SQL、Raw Query、検索条件の組立 | ORM標準のパラメータ化機能を使う |
3. MariaDB / MySQL 系
3-1. 特徴
MariaDB / MySQLは、WordPressやPHP製Webシステムで非常によく使われます。
特に中小企業のWebサイトでは、
WordPress
独自PHPフォーム
予約システム
会員サイト
問い合わせ管理システム
などで使われているケースが多いです。
MariaDB公式ドキュメントでは、Prepared Statementsは繰り返しSQLの効率化だけでなく、SQLインジェクション脆弱性の防止にも関係すると説明されています。
MySQL公式ドキュメントでも、Prepared StatementsはSQLインジェクション攻撃に対する保護として説明されています。
3-2. SQLインジェクションが起きやすい場所
| 場所 | 例 |
|---|---|
| WordPressプラグイン | 独自テーブル検索、Ajax処理 |
| 検索フォーム | 商品検索、投稿検索、会員検索 |
| URLパラメータ | id、post_id、category、menu_id |
| ログインフォーム | メールアドレス、ユーザー名 |
| 予約フォーム | メニューID、日時、人数 |
| 管理画面 | 一覧検索、CSV出力、絞り込み |
WordPressの場合、公式の wpdb クラスにはSQLインジェクション対策の注意が明記されており、メソッドによってエスケープされるもの・されないものがあるため、必ずドキュメント確認が必要です。
3-3. MariaDB / MySQLで見るべきポイント
| 確認項目 | 内容 |
|---|---|
| 文字列連結SQL | PHPでSQLを文字列結合していないか |
| PDO / mysqli | プリペアドステートメントを使っているか |
| WordPress | $wpdb->prepare() を正しく使っているか |
| DBユーザー権限 | Webアプリ用DBユーザーに不要な権限がないか |
| エラー表示 | SQLエラーが画面に出ていないか |
| 複数文実行 | ドライバ設定で不用意に複数SQL文を許可していないか |
| ファイル系権限 | 不要なFILE権限などがないか |
| ログ | 不審なクエリやDBエラーが残っていないか |
MariaDB / MySQL系では、PHPやWordPressとの組み合わせが多いため、フォーム、検索、URLパラメータ、プラグイン独自SQLが確認ポイントになります。
特にWordPressでは、本体よりもプラグインやテーマの独自実装でSQLインジェクションが起きることがあります。
対策は、PDO、mysqli、WordPressの
$wpdb->prepare()などを正しく使い、SQL文と利用者入力を分離することです。
4. PostgreSQL
4-1. 特徴
PostgreSQLは、業務システム、SaaS、APIサーバー、分析系システムなどでよく使われます。
堅牢なDBMSですが、アプリケーション側でSQLを文字列連結していれば、SQLインジェクションは起こり得ます。
PostgreSQL公式ドキュメントでは、PREPARE によりPrepared Statementを作成し、EXECUTE で実行できることが説明されています。
4-2. PostgreSQLで注意する場所
| 場所 | 例 |
|---|---|
| APIの検索条件 | JSON API、GraphQL、REST API |
| 管理画面の検索 | ユーザー検索、注文検索、ログ検索 |
| 動的SQL | PL/pgSQL内でSQL文字列を組み立てる処理 |
| JSON/JSONB検索 | JSON内の値検索 |
| 配列検索 | IN 条件や配列パラメータ |
| 型変換 | 数値・UUID・日付などの変換処理 |
4-3. PostgreSQLで見るべきポイント
| 確認項目 | 内容 |
|---|---|
$1, $2 バインド | ドライバ側でプレースホルダを使っているか |
| 型の扱い | UUID、数値、日付を文字列のまま扱っていないか |
| 動的SQL | PL/pgSQLで危険な文字列連結がないか |
| 関数権限 | SECURITY DEFINER関数の権限が強すぎないか |
search_path | 意図しない関数・テーブル参照のリスクがないか |
| DBロール | アプリ用ロールの権限が最小化されているか |
| エラー表示 | PostgreSQLの詳細エラーが画面に出ていないか |
4-4. PostgreSQLの防御イメージ
PostgreSQLでは、アプリ側のドライバでパラメータ化する場合、概念としては以下のような形になります。
SQLの構造:SELECT ... WHERE id = $1
渡す値:利用者入力
ポイントは、利用者入力をSQL文字列に混ぜないことです。
PostgreSQLは堅牢なDBですが、SQLインジェクションはDB製品の弱さではなく、アプリケーション側のSQLの作り方で発生します。
PostgreSQLでは、数値、UUID、JSON、配列、関数などを扱う場面が多いため、入力値の型とバインド処理を確認することが重要です。
特に、PL/pgSQL内の動的SQLや、強い権限を持つ関数には注意が必要です。
5. Oracle Database
5-1. 特徴
Oracle Databaseは、基幹系、大企業、金融、自治体、ERPなどで使われることが多いDBMSです。
Oracle環境では、単純なWebフォームだけでなく、PL/SQL、ストアドプロシージャ、パッケージ、権限設計まで含めて確認する必要があります。
Oracle公式ドキュメントでも、動的SQLやPL/SQLブロックに対するSQLインジェクション、Statement Injectionのリスクが説明されています。
5-2. Oracleで注意する場所
| 場所 | 例 |
|---|---|
| PL/SQL | EXECUTE IMMEDIATE などの動的SQL |
| ストアドプロシージャ | 文字列でSQLを組み立てている処理 |
| パッケージ | 共通検索処理、権限付き処理 |
| レポート出力 | 条件指定、並び替え、集計 |
| 基幹連携 | 外部システムから渡される条件 |
| 管理画面 | ユーザー検索、帳票検索 |
5-3. Oracleで見るべきポイント
| 確認項目 | 内容 |
|---|---|
| バインド変数 | :param 形式で値を分離しているか |
| 動的SQL | EXECUTE IMMEDIATE で文字列連結していないか |
DBMS_ASSERT | オブジェクト名など、バインドできない値を検証しているか |
| 権限 | DEFINER権限で強すぎる処理がないか |
| エラー表示 | ORAエラーが画面やAPIに出ていないか |
| 監査ログ | 不審なSQLや権限エラーが記録されるか |
Oracleには DBMS_ASSERT パッケージがあり、入力値の性質を検証するためのインターフェースとして公式ドキュメントに説明されています。
Oracle環境では、Webフォームだけでなく、PL/SQLやストアドプロシージャ内の動的SQLが重要な確認対象になります。
Oracleではバインド変数を使うことが基本ですが、テーブル名やカラム名など、値としてバインドできない部分を動的に組み立てる場合は、許可リストや
DBMS_ASSERTなどで検証する必要があります。また、基幹系ではDB権限が強いことが多いため、SQLインジェクションが起きた場合の影響範囲も大きくなります。
6. SQL Server
6-1. 特徴
SQL Serverは、Windows Server、IIS、ASP.NET、社内業務システム、基幹系で多く使われます。
SQL Server環境では、動的SQL、ストアドプロシージャ、ADO.NET、権限設定が重要です。
Microsoft公式ドキュメントでは、SQLインジェクションはユーザー入力がSQLコマンドに連結されて実行されることで発生すると説明されています。
6-2. SQL Serverで注意する場所
| 場所 | 例 |
|---|---|
| ASP.NETアプリ | 検索フォーム、管理画面 |
| ストアドプロシージャ | 動的SQLを組み立てる処理 |
| レポート機能 | WHERE句、ORDER BY句の動的生成 |
| 社内システム | 社員検索、顧客検索、CSV出力 |
| API | パラメータをSQLへ渡す処理 |
6-3. SQL Serverで見るべきポイント
| 確認項目 | 内容 |
|---|---|
SqlParameter | ADO.NETでパラメータ化しているか |
sp_executesql | 動的SQLでもパラメータ化しているか |
| 文字列連結 | SQL文を + で組み立てていないか |
| ストアドプロシージャ | 内部で危険な動的SQLを使っていないか |
| DB権限 | Webアプリの接続ユーザーが強すぎないか |
| エラー表示 | SQL Serverエラーが画面に出ていないか |
Microsoft公式ドキュメントでは、sp_executesql はパラメータを含むTransact-SQLを実行できる仕組みとして説明されており、ランタイムでコンパイルされるSQLは悪用リスクがあるため、パラメータ化が必要と注意されています。
SQL Serverでは、ストアドプロシージャを使っているから安全、とは限りません。
ストアドプロシージャの内部でSQL文字列を連結していれば、SQLインジェクションの可能性があります。
ADO.NETの
SqlParameterや、動的SQLであればsp_executesqlによるパラメータ化を確認することが重要です。
7. SQLite
7-1. 特徴
SQLiteは、サーバー型DBではなく、ファイルベースの軽量DBです。
スマホアプリ、デスクトップアプリ、小規模ツール、組込みシステム、一部CMSなどで使われます。
SQLite公式ドキュメントでは、SQLパラメータとして ?、:name、@name、$name などを使い、sqlite3_bind_*() 系の関数で値をバインドできると説明されています。
7-2. SQLiteで注意する場所
| 場所 | 例 |
|---|---|
| アプリ内検索 | メモ、履歴、顧客検索 |
| ローカル管理ツール | 台帳、CSV取込、簡易DB |
| スマホアプリ | ユーザーデータ、設定情報 |
| Electron系アプリ | ローカルDB検索 |
| 小規模Webアプリ | ファイルDBとして利用 |
7-3. SQLiteで見るべきポイント
| 確認項目 | 内容 |
|---|---|
| バインド処理 | ? や名前付きパラメータを使っているか |
| DBファイル権限 | DBファイルが外部公開されていないか |
| ファイル配置 | Web公開ディレクトリ配下にDBを置いていないか |
| ローカルアプリ | 入力値でSQLを文字列連結していないか |
| バックアップ | DBファイルが平文で漏れないか |
SQLiteは小規模で便利なDBですが、SQLを使う以上、SQLインジェクションの考え方は同じです。
サーバー型DBではないため、SQLインジェクションに加えて、DBファイルそのものの保存場所やアクセス権限も重要になります。
Web公開ディレクトリ配下にSQLiteファイルを置くような設計は避けるべきです。
8. ORM・フレームワーク利用時の注意
Laravel、Django、Ruby on Rails、Spring、Entity Framework、PrismaなどのORMを使っている場合も、SQLインジェクションの確認は必要です。
ORMを正しく使っている限り、SQLインジェクションのリスクは大きく下がります。
しかし、以下のようなケースではリスクがあります。
| 危険なケース | 内容 |
|---|---|
| Raw SQL | 生SQLを直接書いている |
| 動的ORDER BY | カラム名や並び順を文字列で組み立てている |
| 動的WHERE | 条件式を文字列で連結している |
| LIKE検索 | ワイルドカードやエスケープの扱いが雑 |
| IN句 | 配列を文字列連結している |
| 管理画面の検索 | 高権限データを扱う |
| APIフィルタ | 任意条件をそのままSQLへ変換している |
MicrosoftのEntity Framework Core公式ドキュメントでも、ユーザー提供値をSQLに組み込む場合はSQLインジェクションに注意が必要で、安全なメソッドとRaw系メソッドの扱いを区別するよう説明されています。
9. DBMS別:ペネトレーションテスト確認項目
9-1. 共通確認
| 確認項目 | 内容 |
|---|---|
| 対象DBMS | MariaDB、PostgreSQL、Oracle、SQL Server等を確認 |
| 接続ユーザー | アプリがどのDBユーザーで接続しているか |
| DB権限 | SELECT、INSERT、UPDATE、DELETE、DDL権限の範囲 |
| エラー表示 | DBエラーが画面やAPIに出ないか |
| ログ | DBエラー、不審クエリ、WAFログ |
| バックアップ | 診断前にDBバックアップがあるか |
| ステージング | 本番と近い構成の検証環境があるか |
| コード | SQL文字列連結がないか |
| フレームワーク | ORMやDBライブラリを正しく使っているか |
9-2. DBMS別の重点確認
| DBMS | 重点確認 |
|---|---|
| MariaDB / MySQL | PHP、WordPress、PDO、mysqli、$wpdb->prepare()、プラグイン独自SQL |
| PostgreSQL | $1 形式のバインド、型、JSONB、PL/pgSQL、関数権限、DBロール |
| Oracle | バインド変数、PL/SQL、EXECUTE IMMEDIATE、DBMS_ASSERT、強い権限 |
| SQL Server | SqlParameter、sp_executesql、ストアドプロシージャ、Windows認証、DB権限 |
| SQLite | バインド、DBファイル権限、配置場所、ローカルアプリの入力処理 |
10. DBMS別:安全な修正方針
| DBMS | 修正方針 |
|---|---|
| MariaDB / MySQL | PDO/mysqliのPrepared Statement、WordPressなら $wpdb->prepare()、DBユーザー権限最小化 |
| PostgreSQL | ドライバのパラメータバインド、PL/pgSQLの動的SQL見直し、ロール分離 |
| Oracle | バインド変数、DBMS_ASSERT、PL/SQL内の動的SQL見直し、権限分離 |
| SQL Server | SqlParameter、sp_executesql、ストアドプロシージャ内の文字列連結廃止 |
| SQLite | sqlite3_bind_*()、DBファイル非公開、アプリ権限の制御 |
| ORM | Raw SQL削減、Raw利用時のパラメータ化、許可リスト方式 |
11. 重要ポイント
ポイント1
DB製品が違っても、原因はほぼ同じ
SQLインジェクションの原因は、多くの場合、利用者入力をSQL文字列に混ぜていることです。
ポイント2
DBMSごとに「見え方」が違う
MariaDB / MySQL、PostgreSQL、Oracle、SQL Serverでは、エラー表示、型の扱い、動的SQL、権限設計が異なります。
そのため、診断時はDBMSごとの特徴を理解して確認します。
ポイント3
ストアドプロシージャでも安全とは限らない
ストアドプロシージャを使っていても、内部でSQLを文字列連結していれば危険です。
これはOracle、SQL Server、PostgreSQLの関数でも同じです。
ポイント4
WAFだけでは根本解決ではない
WAFは補助防御です。
根本対策は、
SQL文と利用者入力を分離すること
DB権限を最小化すること
エラーを外部に出さないこと
ログを監視すること
です。
12. 講義用まとめ文
SQLインジェクションは、MariaDB、MySQL、PostgreSQL、Oracle、SQL Server、SQLiteなど、SQLを使う多くのDBMSで発生し得る脆弱性です。
DBMSによって文法やエラー表示、バインド変数の書き方、権限設計は異なります。
しかし、根本原因は共通しています。それは、利用者入力をSQL文に直接混ぜてしまうことです。
そのため、対策の基本は、DBMSごとの文法を理解しながら、プリペアドステートメント、バインド変数、パラメータ化クエリを使うことです。
また、SQLインジェクションが起きた場合の被害を抑えるため、DBユーザーの権限を最小化し、エラー表示を抑制し、ログ監視とバックアップを整備することも重要です。
13. 講義用の締め言葉
SQLインジェクション対策で重要なのは、
「MySQLだから危ない」「PostgreSQLだから安全」という考え方ではありません。どのDBMSでも、利用者入力をSQLに直接混ぜれば危険です。
DBMSごとの違いを理解したうえで、
SQLの構造と利用者入力を分離すること、
DB権限を最小化すること、
本番でエラーを見せないこと、
修正後に再診断すること
が重要です。
