講義資料 SQLインジェクションをDBMS別に理解する

1. まず共通原則

SQLインジェクションは、PostgreSQL、MariaDB、MySQL、Oracle、SQL Server、SQLiteなど、SQLを使うDBMSで起こり得ます。

原因はDB製品そのものではなく、多くの場合、利用者入力をSQL文字列に連結してしまうことです。

OWASPも、SQLインジェクション対策の中心として、プリペアドステートメント/パラメータ化クエリを第一に挙げています。これはSQLの構造と利用者入力を分離する考え方です。


2. DBMS別の違いを理解する

全体比較

DBMSよく使われる環境SQLi確認で見るポイント防御の基本
MariaDB / MySQLWordPress、PHP、LAMPURLパラメータ、検索、ログイン、プラグイン独自SQLプレースホルダ、PDO/mysqli、
$wpdb->prepare()
PostgreSQL業務システム、API、SaaS型変換、JSON、配列、関数、動的SQL$1, $2 形式のバインド、Prepared Statement
Oracle Database大企業、基幹系、金融、ERPPL/SQL、動的SQL、権限、ストアドプロシージャバインド変数、DBMS_ASSERT、権限分離
SQL ServerWindows系業務システム、社内システム動的SQL、ストアドプロシージャ、ADO.NET@paramsp_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パラメータidpost_idcategorymenu_id
ログインフォームメールアドレス、ユーザー名
予約フォームメニューID、日時、人数
管理画面一覧検索、CSV出力、絞り込み

WordPressの場合、公式の wpdb クラスにはSQLインジェクション対策の注意が明記されており、メソッドによってエスケープされるもの・されないものがあるため、必ずドキュメント確認が必要です。


3-3. MariaDB / MySQLで見るべきポイント

確認項目内容
文字列連結SQLPHPで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
管理画面の検索ユーザー検索、注文検索、ログ検索
動的SQLPL/pgSQL内でSQL文字列を組み立てる処理
JSON/JSONB検索JSON内の値検索
配列検索IN 条件や配列パラメータ
型変換数値・UUID・日付などの変換処理

4-3. PostgreSQLで見るべきポイント

確認項目内容
$1, $2 バインドドライバ側でプレースホルダを使っているか
型の扱いUUID、数値、日付を文字列のまま扱っていないか
動的SQLPL/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/SQLEXECUTE IMMEDIATE などの動的SQL
ストアドプロシージャ文字列でSQLを組み立てている処理
パッケージ共通検索処理、権限付き処理
レポート出力条件指定、並び替え、集計
基幹連携外部システムから渡される条件
管理画面ユーザー検索、帳票検索

5-3. Oracleで見るべきポイント

確認項目内容
バインド変数:param 形式で値を分離しているか
動的SQLEXECUTE 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で見るべきポイント

確認項目内容
SqlParameterADO.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. 共通確認

確認項目内容
対象DBMSMariaDB、PostgreSQL、Oracle、SQL Server等を確認
接続ユーザーアプリがどのDBユーザーで接続しているか
DB権限SELECT、INSERT、UPDATE、DELETE、DDL権限の範囲
エラー表示DBエラーが画面やAPIに出ないか
ログDBエラー、不審クエリ、WAFログ
バックアップ診断前にDBバックアップがあるか
ステージング本番と近い構成の検証環境があるか
コードSQL文字列連結がないか
フレームワークORMやDBライブラリを正しく使っているか

9-2. DBMS別の重点確認

DBMS重点確認
MariaDB / MySQLPHP、WordPress、PDO、mysqli、$wpdb->prepare()、プラグイン独自SQL
PostgreSQL$1 形式のバインド、型、JSONB、PL/pgSQL、関数権限、DBロール
Oracleバインド変数、PL/SQL、EXECUTE IMMEDIATEDBMS_ASSERT、強い権限
SQL ServerSqlParametersp_executesql、ストアドプロシージャ、Windows認証、DB権限
SQLiteバインド、DBファイル権限、配置場所、ローカルアプリの入力処理

10. DBMS別:安全な修正方針

DBMS修正方針
MariaDB / MySQLPDO/mysqliのPrepared Statement、WordPressなら $wpdb->prepare()、DBユーザー権限最小化
PostgreSQLドライバのパラメータバインド、PL/pgSQLの動的SQL見直し、ロール分離
Oracleバインド変数、DBMS_ASSERT、PL/SQL内の動的SQL見直し、権限分離
SQL ServerSqlParametersp_executesql、ストアドプロシージャ内の文字列連結廃止
SQLitesqlite3_bind_*()、DBファイル非公開、アプリ権限の制御
ORMRaw 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権限を最小化すること
本番でエラーを見せないこと
修正後に再診断すること
が重要です。

HOMEへ戻る