SQLインジェクションとは?仕組みと対策|プレースホルダで防ぐ方法

SQLインジェクションは、もう何年も前から知られている攻撃手法です。それでも実際の被害報告が絶えないのは、「知っているつもり」で実装してしまうケースが多いからです。

この記事では、SQLインジェクションがなぜ起きるのかという仕組みの部分から、実務でどう対策すればよいのかまでを整理します。

関連

Webアプリのセキュリティ対策を一通り確認したい方は、 Webアプリの脆弱性・セキュリティ対策まとめ もあわせてご覧ください。

SQLインジェクションとは

SQLインジェクションとは、フォームやURLパラメータなどユーザーが入力できる箇所に、意図的な文字列を送り込むことで、アプリが組み立てるSQL文の構造そのものを書き換えてしまう攻撃です。

「ユーザー名」や「検索キーワード」といった一見無害な入力欄が、そのまま攻撃の入り口になり得ます。

なぜ起きるのか|文字列連結という原因

典型的な原因は、SQL文を文字列連結で組み立てていることです。次のようなコードを考えてみます。

SELECT * FROM users WHERE name = '入力値' AND password = '入力値'

一見普通のログイン処理に見えますが、ここに以下のような文字列を入力するとどうなるでしょうか。

' OR '1'='1' --

この文字列がそのまま埋め込まれると、SQL文は次のように変化します。

SELECT * FROM users WHERE name = '' OR '1'='1' -- ' AND password = '...'

'1'='1'は常に真になるため、WHERE句の条件が実質的に無効化されます。--以降はコメントとして扱われるため、パスワードのチェックごと無視されます。結果として、IDもパスワードも知らないまま、ログインが成立してしまいます。

これがSQLインジェクションの基本的な仕組みです。入力値が「データ」としてではなく、「SQL文の一部」として解釈されてしまうことが問題の本質です。

体験|SQL文がどう組み立てられるか見る

言葉で説明されてもピンとこないと思うので、実際に入力しながら確かめてみましょう。以下のデモは実際のデータベースには一切接続しません。入力した文字がSQL文の中でどう扱われるかを、その場で可視化するだけです。

体験デモ|SQL文がどう組み立てられるか見る

文字列連結プレースホルダを比較する

実際のデータベースには接続しません。ユーザー名検索の入力が、SQL文の中でどう扱われるかを確認できます。

実際に組み立てられるSQL文

上のボタンを押すと、実行結果がここに表示されます。

「対策なし」モードで攻撃文字列を試すと、WHERE句が壊れて全ユーザーの情報が漏洩してしまう様子が確認できたはずです。一方「対策あり」モードでは、同じ文字列を入力してもSQL文の構造自体は?のまま変わらず、入力値は単なるデータとして扱われるため、該当なしという結果になります。これが「値として渡す」ことの意味です。

対策の基本|プレースホルダ(パラメータ化クエリ)

最も基本的かつ効果的な対策は、SQL文の組み立て時にプレースホルダ(パラメータ化クエリ)を使うことです。

SELECT * FROM users WHERE name = ? AND password = ?

このように、SQL文の「構造」と「値」を分離して送ります。データベースドライバは?の部分に入る値を、あくまで「データ」として扱い、SQL文の一部として解釈することはありません。どれだけクォートや--を含む文字列を入力しても、SQL文の構造自体は変化しないため、攻撃が成立しなくなります。

ORMを使うという選択肢

実務では、SQL文を直接書かずにORM(Object-Relational Mapping)を使うケースも多くあります。

Django ORMやSQLAlchemyといったORMは、内部的にプレースホルダを使ってクエリを発行するため、通常の使い方をしている限り、SQLインジェクションのリスクを大きく下げられます。

フレームワークやORMの選び方については、 DBを柔軟に設計できるWebアプリ開発 でも詳しく解説しています。

ただし、ORMを使っていても「生SQLを文字列連結で組み立てて実行する」機能を使ってしまうと、対策は無効になります。ORMを導入すること自体がゴールではなく、値を必ずパラメータとして渡すという原則を守ることが重要です。

実務で意識したいポイント

最後の「権限を絞る」は、万が一プレースホルダの対策が漏れていた場合でも被害を最小化するための保険です。対策は1つに頼らず、重ねておくのが実務上の基本になります。

まとめ

SQLインジェクションは、入力値をSQL文に文字列連結で埋め込むことで発生します。対策の核心はプレースホルダ(パラメータ化クエリ)を使い、値を必ずデータとして渡すことです。

ORMを使う場合でも、この原則を意識しているかどうかで安全性は大きく変わります。まずは自分のアプリのDB操作部分が、文字列連結になっていないかを確認するところから始めてみてください。

顧問契約、開発、プロジェクトのご依頼を承ります。
内容、期間により金額が変動しますのでお気軽にお問い合わせください。

※ 案件によりお受けできない場合もあります。

お問い合わせはこちら →
戻る