「泥棒に合鍵を渡すな!」SQLインジェクションの正体と、今日からできる鉄壁の守り方
こんにちは。現場で泥臭いインシデント対応に明け暮れるセキュリティエンジニアです。
今日は、Webアプリケーションにおける「最大の鬼門」と言われるSQLインジェクションについてお話しします。名前を聞くだけで難しそうに感じるかもしれませんが、実は私たちの日常生活にある「鍵」の仕組みに例えると、驚くほどシンプルに理解できるんです。
一緒に、システムを泥棒から守るための第一歩を踏み出してみましょう!
—
1. SQLインジェクションとは?「合鍵で家を乗っ取られる」ということ
まず、Webアプリケーションがデータベースと会話する仕組みを「家」に例えてみます。
あなたがWebサイトでログインするとき、IDとパスワードを入力しますよね。システムは裏側で、データベースという「金庫」に対してこう言っています。
「このIDとパスワードを持っている人を探して、中身(個人情報)を見せてあげて!」
これが正常な状態です。しかし、SQLインジェクションは、ここに「偽造された合鍵」を紛れ込ませる手口なんです。
攻撃者は何を狙っているのか?
攻撃者は入力欄に、普通のIDではなく、データベースを混乱させるための「命令文(SQLコマンド)」を書き込みます。
例えば、`’ OR ‘1’=’1` という文字列をID欄に入力されたとします。すると、データベースはこう解釈してしまいます。
「IDが一致するか、もしくは『1=1(常に正しい)』ならば、全員のデータを出しなさい!」
本来なら「特定の人のデータ」しか見られないはずが、この一行で「全員のデータ」が丸裸にされてしまう。これがSQLインジェクションの恐ろしさです。
—
2. なぜ「動的SQL」は危険なのか?
多くの初心者がやってしまいがちなのが、プログラムの中で「文字列をくっつけてSQLを作る」というやり方です。これを動的SQL生成と呼びます。
危険なコード例:文字列を直接くっつけている
user_input = “admin’ –” # 攻撃者が入力した怪しい文字列
query = “SELECT FROM users WHERE username = ‘” + user_input + “‘”
完成するクエリ:SELECT FROM users WHERE username = ‘admin’ –‘
後ろのパスワードチェックがコメントアウトされ、無効化されてしまう!
これは、「誰が書いたか確認せずに、渡されたメモをそのまま金庫の開錠命令として実行する」のと同じです。怪しいメモが混ざっていれば、金庫は簡単に開いてしまいますよね。
—
3. 最強の盾「プリペアドステートメント」という考え方
ここで登場するのが、セキュリティの救世主「プリペアドステートメント(バインド変数)」です。
これは、家で例えるなら「あらかじめ型が決まった鍵穴」を用意しておくようなものです。
仕組みはこうです:
1. 「先にSQLの『形』だけをデータベースに送る」
2. 「後からデータ(IDやパスワード)を流し込む」
こうすると、データベースは後から入ってきたデータに対して「これは命令文ではなく、ただの『名前』という文字列データだね」と判断します。たとえそこに `OR 1=1` という怪しい命令が書かれていても、データベースはそれを「そういう名前のユーザーがいるか?」と探すだけで、命令として実行することはありません。
安全なコードの書き方(Pythonの例)
import sqlite3
データベースに接続
conn = sqlite3.connect(‘example.db’)
cursor = conn.cursor()
1. まずSQLの『型』だけを定義する(? がプレースホルダー)
sql = “SELECT FROM users WHERE username = ?”
2. ユーザーからの入力値は『データ』として渡す
user_input = “admin’ –”
cursor.execute(sql, (user_input,))
これなら、データベースは ‘admin’ — という名前のユーザーを探すだけ!
命令として悪用されることは決してありません。
—
4. 今日からできる防犯対策まとめ
最後に、現場で戦うエンジニアとしてこれだけは守ってほしい「鉄則」をまとめました。
- 文字列連結でSQLを作らない: `+` や `f-string` でSQLを組み立てるのは、泥棒に合鍵を渡すのと同じです。
- プリペアドステートメントを徹底する: どんなに簡単なクエリでも、例外を作らずにバインド変数を使ってください。
- 権限を最小限にする: もし万が一侵入されても被害が広がらないよう、Webアプリケーションが使うデータベースのユーザーには、必要最低限の権限(読み取りだけ、など)しか与えないようにしましょう。
—
セキュリティ対策は、一度やって終わりではありません。でも、こうして「仕組み」を理解して少しずつ対策を積み重ねることで、あなたの書くコードは驚くほど強固になります。
まずは、今書いているコードのSQL生成部分を覗いてみてください。「文字列を連結してないかな?」とチェックする。その一歩が、あなたとユーザーを守る一番の近道ですよ!
何か分からないことがあれば、いつでも相談してくださいね。一緒に頑張りましょう!

コメント