【セキュリティ入門】SQLインジェクションとは?Webサイトを破壊する魔法の呪文
公開日: 2025年9月23日
あなたがWebアプリケーションを開発し、ユーザーの情報をデータベースに保存するようになると、必ず向き合わなければならない、非常に重要なテーマがあります。それが「セキュリティ」です。
数あるサイバー攻撃の中でも、特に古くから存在し、そして今なお最も強力な攻撃手法の一つとして知られているのが、「SQLインジェクション (SQL Injection)」です。
「名前は聞いたことあるけど、具体的に何がどう危険なのかはよく分からない…」という人も多いかもしれません。
今日は、このSQLインジェクションの恐ろしい仕組みと、なぜそれが「Webサイトを破壊する魔法の呪文」とまで呼ばれるのかを、簡単なログインフォームを例に解説していきます。
普通のログイン処理
まず、一般的なログインフォームの裏側で動いている、単純なSQL文を見てみましょう。 ユーザーが入力した「ユーザー名」と「パスワード」が、データベースに保存されている情報と一致するかどうかを確認する処理です。
-- ユーザーが入力した username と password を変数に入れる
username = "Taro"
password = "pass123"
-- データベースに問い合わせるSQL文を組み立てる
sql = "SELECT * FROM users WHERE name = '" + username + "' AND password = '" + password + "'"
-- 完成したSQL文:
-- SELECT * FROM users WHERE name = 'Taro' AND password = '' OR '1'='1'
このSQL文は、usersテーブルから、nameがTaroであり、かつ(AND)、passwordがpass123であるユーザーを探します。 データが見つかればログイン成功、見つからなければ失敗。非常にシンプルですね。
悪意のある攻撃者は、どうやって攻撃するのか?
ここからが本題です。 もし、このログインフォームに、悪意のある攻撃者がやってきたらどうなるでしょう? 彼らは、パスワードを知りません。しかし、SQLの文法を知っています。
攻撃者は、パスワード入力欄に、以下のような**「魔法の呪文」**を入力します。
OR '1'='1'
一見、意味不明な文字列ですよね。しかし、これが先ほどのプログラムによってSQL文に注入(インジェクション)されると、恐ろしいことが起こります。
username = "Taro"
password = "' OR '1'='1" -- 攻撃者が入力したパスワード
-- データベースに問い合わせるSQL文を組み立てる
sql = "SELECT * FROM users WHERE name = '" + username + "' AND password = '" + password + "'"
-- ★★★ 完成した、恐ろしいSQL文 ★★★
-- SELECT * FROM users WHERE name = 'Taro' AND password = OR '1'='1'
「魔法の呪文」が意味するもの
完成したSQL文を、コンピュータがどのように解釈するか見てみましょう。 WHERE句の条件は、以下のようになっています。
「nameがTaroであり、かつ、passwordが(空文字)である」
または (OR)
「'1'と'1'が等しい」
'1'と'1'は、もちろん常に等しいですよね。つまり、この'1'='1'という条件は、常にTRUE(真)になります。
OR条件は、どちらか片方がTRUEであれば、条件全体がTRUEになります。 その結果、passwordが全く違っていても、'1'='1'が`TRUE`であるため、WHERE句全体の条件が満たされてしまい、攻撃者はパスワードを知らないまま、Taroとしてログインに成功してしまうのです。
さらに恐ろしいことに、攻撃者はデータベースのすべての情報を抜き取ったり(UNION SELECT攻撃)、最悪の場合、テーブルをすべて削除する(DROP TABLE)ことさえ可能になります。
どうすれば防げるのか?:「プレースホルダ」を使おう
では、どうすればこの恐ろしい攻撃を防げるのでしょうか? 答えは、「ユーザーからの入力を、絶対にSQL文として直接組み立てない」ことです。
そのための最も標準的な防御策が、「プレースホルダ(Prepared Statements)」を使う方法です。
-- Python (Flask-SQLAlchemy) での安全な書き方
username = "Taro"
password = "' OR '1'='1" # 攻撃者の入力
-- SQL文の「テンプレート」を用意する
sql = "SELECT * FROM users WHERE name = :name AND password = :password"
-- テンプレートの「穴(:name, :password)」に、後から値を「安全なデータとして」当てはめる
result = db.session.execute(sql, {name: username, password: password})
この方法を使えば、たとえユーザーが OR '1'='1'のような魔法の呪文を入力しても、それは決してSQLの文法の一部としては解釈されず、単なる「 OR '1'='1'という文字列のパスワード」として扱われます。 その結果、データベースは「そんな変わったパスワードのユーザーはいませんね」と正しく判断し、攻撃は失敗に終わります。
まとめ
SQLインジェクションは、非常に古くからある攻撃ですが、今でも多くのWebサイトがこの脆弱性を抱えています。
あなたが将来、データベースを扱うアプリケーションを作る際は、必ず「ユーザーからの入力は、常に『汚れている』可能性がある危険なものだ」という意識を持ち、プレースホルダを使って、安全にSQLを扱う習慣を身につけてください。 それが、あなた自身と、あなたの大切なユーザーを守るための、第一歩です。
プログラミング学習に必須ツール!
記事で紹介したコードがよく分からなかったり、ご自身のコードについてもっと知りたい場合は、AIコード解説ツールが便利です。コードを貼り付けるだけで、AIが日本語で分かりやすく解説します。
AIコード解説ツールを使ってみる →