SQLインジェクションとは?攻撃の仕組み・被害例・対策を徹底解説
SQLインジェクションは、Webアプリケーションの脆弱性を悪用し、不正なSQL文を実行させる攻撃手法です。これにより、不正ログインやデータの改ざん・削除、個人情報の漏えいといった深刻な被害が発生する可能性があります。本記事では、SQLインジェクションの仕組み、具体的な被害例、防止策を徹底解説し、安全なシステム構築のための実践的な対策を紹介します。
SQLインジェクションとは
SQLインジェクション(SQL Injection)は、ユーザー入力を介して不正なSQL文を注入し、データベースを意図しない形で操作されてしまう攻撃手法です。
これにより、不正ログイン、データの改ざん・削除(DROP TABLEなど)、情報漏えいなど、企業の存続に関わる重大な被害が発生する恐れがあります。
例えば、ログイン画面のユーザー名入力欄に `admin’ OR ‘1’=’1` などの特殊な文字列を入力すると、システムが本来意図しないSQLクエリを実行し、認証をバイパスしてしまう可能性があります。
これは OR '1'='1'
の部分が常に「真」となり、本来必要な認証をバイパスしてしまうためです。
※プリペアドステートメント(パラメータ化クエリ)を使用することで、このような攻撃は防ぐことができます。
SQLインジェクションが起こる仕組み
なぜ文字列連結が問題なのか
Webアプリケーションがデータベースへアクセスする際、以下のように文字列を直接連結してSQLを生成していると危険です。
-- 【脆弱な例】
query = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";
ユーザーからの入力にシングルクォート '
や、SQL構文を破壊する文字が混ざっていると、本来意図しない形でクエリの構造を変化させてしまいます。
たとえば、' OR '1'='1
という文字列をユーザー名として連結すると、'1'='1'
は常に真となり、全ユーザー情報を取得される可能性があります。
図解イメージ(テキストベースの例)
- 想定していたクエリ:
SELECT * FROM users WHERE username = '正常な入力' AND password = '正常な入力'
- 悪意ある入力を連結:
SELECT * FROM users WHERE username = '' OR '1'='1' -- ' AND password = ''
OR '1'='1'
により条件式が常に真となり、全レコードが取得される。
文字列連結によって「データ」と「命令」の境界が曖昧になり、攻撃者の意図通りにクエリ構造が改変されることが、SQLインジェクションの本質的な問題です。
主な被害例
不正ログイン
- 管理者アカウントへの侵入
常に真(TRUE)となる条件を注入することで、正しいパスワードを入力しなくてもログインできてしまう。 - セッションハイジャック
セッションIDを奪われたり、不正に書き換えられたりする可能性もあります。
データの改ざん・削除
- UPDATE文での改ざん
例えば商品価格やポイント情報などを攻撃者が意図的に変更。 - DROP TABLEなど破壊的なコマンド
一部または全テーブルを削除され、システムそのものが停止する危険性。
情報漏えい
- 個人情報・顧客情報の流出
クレジットカード情報や住所・電話番号など、機密性の高いデータが閲覧・取得される可能性。 - 大規模な被害の事例
2015年の英国TalkTalk社のケースでは、15万件以上の顧客データが漏えい。企業の評判・信用が大きく損なわれ、多額の賠償や罰金を支払う事態に陥りました。
他にも…
Sony PlayStation Network(PSN):7,700万人の個人情報流出。Sonyは約1,500万ドルの罰金を支払うことに。
Heartland Payment Systems:1億3,400万件のカード情報流出。企業の信用失墜、カード会社からの多額の賠償請求。
SQLインジェクションの防止策
パラメータ化クエリ(プリペアドステートメント)の使用
なぜ安全か?
- 「データ(入力)」と「命令(SQL構文)」を明確に分離して扱える。
- パラメータ部分をSQLエンジンが適切に無害化(エスケープ)するため、攻撃者が構文を変化させにくい。
コード例(Java風)
String sql = "SELECT * FROM users WHERE username = ? AND password_hash = ?";
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1, username);
pstmt.setString(2, hashPassword(inputPassword)); // ハッシュ化したパスワードを比較
ResultSet rs = pstmt.executeQuery();
パスワードはハッシュ化して保存し、認証時は同じハッシュアルゴリズムで変換した値を比較します(例: bcrypt, Argon2)。
入力値のバリデーション
- ホワイトリスト方式(英数字や特定記号のみ受け付ける)で、想定外の文字を排除。
- 適切な文字数制限を行い、過剰に長い入力を防ぐ。
エスケープ処理(補助的対策)
- データベースごとに異なるエスケープ方法(
mysql_real_escape_string()
など)を利用して、シングルクォートなどを無害化。 - ただし、パラメータ化クエリの導入が最優先で、エスケープ処理はあくまで補助的。構文ミスや適用漏れがあると脆弱性を残す原因になります。
データベースの権限設定
- アプリケーション専用のDBユーザーを用意し、最低限の操作権限(SELECT, INSERTなど)に制限する。
- 万一クエリを改変されても、DROPなどの危険な操作ができないようにする。
脆弱性テストやスキャンの実施
- 定期的に脆弱性検査を行い、潜在的な問題を早期発見。
- 主なツール例:
- OWASP ZAP(オープンソースの脆弱性スキャナー)
- SQLMap(SQLインジェクション検出・攻撃テストに特化)
- Burp Suite(総合的なWebセキュリティテストツール)
補足トピック
ORM(Object-Relational Mapping)の活用
近年のWebフレームワークでは、ActiveRecordやHibernateなどのORMによってSQLを直接書かずに済むケースが増えています。ORMは内部的にパラメータ化クエリを用いるため、手動でSQLを組み立てるリスクが減少します。
ただし、ORMでもカスタムクエリを書かなければならない場面では、引き続きSQLインジェクションに注意が必要です。
NoSQLインジェクション(具体例)
SQL以外のデータベース(MongoDB、Firebaseなど)に対しても注入攻撃は存在します。
たとえばMongoDBでは、以下のようにユーザー入力をそのままfindクエリに渡すと危険です。
// 【脆弱なコード】ユーザーの入力をそのまま MongoDB の find に渡してしまう
db.users.find({ username: userInput, password: passInput });
もし攻撃者が次のようなJSONを入力として渡した場合:
{
"username": { "$ne": null },
"password": "password123"
}
"$ne": null
は「null以外ならすべて該当する」という意味になるため、結果としてすべてのアカウントをヒットさせる形になります。
NoSQLの場合も、SQLインジェクションと同様にデータとクエリ(命令)を分離し、パラメータを正しくバインド・検証する対策が重要です。
WAF(Webアプリケーションファイアウォール)の導入
WAF(Web Application Firewall)は、SQLインジェクションやXSS(クロスサイトスクリプティング)などの攻撃を検知・ブロックする仕組みです。
特に、Webサイト運営者やクラウド環境を利用している企業にとって、手軽に追加できる防御策として有効です。
WAFの導入方法
1. クラウド型WAF(簡単に導入可能)
- AWS WAF(Amazon Web Servicesを利用する場合)
- Cloudflare WAF(Webサイト向け、無料プランあり)
- Google Cloud Armor(Google Cloud環境向け)
2. オンプレミス型WAF(自社で管理・カスタマイズ可能)
- ModSecurity(オープンソース、Apache/Nginx/IISに導入可能)
- Imperva WAF(エンタープライズ向け、細かいカスタマイズが可能)
WAFのメリット
- SQLインジェクションの攻撃パターンを事前にブロック
- Webサイトの負荷を増やさず、セキュリティを強化できる
- 特にクラウド型WAFなら設定が簡単で、初心者でも導入しやすい
WAFの限界と注意点
WAFは万能ではありません。既知の攻撃パターンには強いものの、新しいSQLインジェクション手法には対応できない場合があります。
また、WAFだけではアプリケーション内部の脆弱性は解決できないため、以下の基本対策と組み合わせることが重要です。
- パラメータ化クエリ(プリペアドステートメント)の使用(SQLインジェクション防止の基本)
- 入力値のバリデーション(異常なデータの入力を防ぐ)
- 最小限のデータベース権限設定(不要な権限を持たせない)
WAFは「補助的な防御策」であり、アプリケーションコードの安全性を高めることが最優先!
まとめ
- SQLインジェクションとは、ユーザー入力を利用して意図しないSQL文を実行させる攻撃手法。
- 文字列連結によるSQL組み立てが最大のリスク。パラメータ化クエリの導入が必須。
- 被害例として、不正ログイン、データの改ざん・削除、情報漏えいなど多岐にわたり、被害規模は極めて大きい。
- 具体的な対策は下記の通り。
- パラメータ化クエリ(プリペアドステートメント)の利用
- 入力値のバリデーションとエスケープ処理
- DBユーザーの権限を最小限に抑える
- 定期的な脆弱性スキャン(OWASP ZAP, SQLMap, Burp Suite など)
- ORM活用・NoSQLインジェクション・WAFの導入など、補足的な対策や関連領域にも注意を払う。
SQLインジェクションは発見されてから長い歴史を持つ攻撃手法ですが、いまだに多くのシステムで深刻な被害をもたらしています。基本的な対策を怠らず、「データと命令を混ぜない」設計を常に意識することが重要です。