ログインフォーム、検索窓、お問い合わせ欄。アプリには「ユーザーから文字を受け取る場所」がいくつもあります。この入力を受け取る箇所にこそ、古くから知られていて、しかも被害が大きい穴が潜んでいます。それがSQLインジェクションです。

以前の記事個人開発で見るべきセキュリティ・非機能要件では、個人開発でも見ておきたい穴の1つとして名前だけ挙げました。この記事では、そのSQLインジェクションだけを取り出して、どういう仕組みで起きるのか、放っておくと何が起きるのか、そしてどう防ぐのかを、順を追ってやさしく見ていきます。

前提:データベースは「命令文」で動いている

多くのアプリは、ユーザーの情報や投稿を「データベース」という保管庫にしまっています。そのデータベースを操作するとき、内部では SQL という命令文が使われます。たとえば「メールアドレスがこの人の会員情報を取り出して」といった依頼を、決まった書き方の文章にして送っているイメージです。データベースそのものについてはデータベースとはで解説しています。

大事なのは、データベースは送られてきた命令文を「そのまま忠実に実行する」ということです。ここに、これから話す落とし穴の入り口があります。

結論:SQLインジェクションは「命令文を書き換えられる」攻撃

SQLインジェクションとは、入力欄に紛れ込ませた文字列によって、本来のデータベースへの命令を書き換えてしまう攻撃のことです。日本語では「SQL注入」とも言います。

利用者が打ち込んだ文字が、そのまま命令文の一部として解釈されてしまうと、攻撃者は入力欄を通じて、開発者が意図していない命令をデータベースに実行させられます。名前を入れる欄に、名前ではなく「命令の断片」を仕込む、という発想です。

なぜ起こるのか:入力を命令文に「そのまま混ぜる」から

原因はシンプルです。ユーザーが入力した文字を、命令文の中にそのまま貼り付けてつなげてしまうことにあります。

たとえばログイン画面を考えます。プログラムは、入力されたIDとパスワードを命令文に組み込み、データベースに「このIDとパスワードが一致する人はいますか」と尋ねます。このとき、入力された文字を検査せずに命令文へ差し込んでいると、パスワード欄に「もし〜なら、という条件を常に成立させる一言」を混ぜられることがあります。

すると命令文の意味が、本来の「IDとパスワードが一致する人」から「どんな場合でも一致とみなす」に化けてしまいます。パスワードを知らなくても、ログインが通ってしまうわけです。攻撃者は、命令文の文法をうまく利用して、条件そのものをすり替えているのです。

ムチオ
ムチオ
えっと…入力欄って、ただ文字を打つ場所じゃないの?なんでそれが命令になっちゃうの?
ルミナ
ルミナ
プログラムが、打ち込まれた文字を「値」ではなく「命令文の続き」としてつないでしまうからです。手紙の宛名欄に、宛名のふりをして指示を書き込まれ、それをそのまま実行してしまう、と考えると近いですよ。
ムチオ
ムチオ
こわいよ…名前を入れるだけの欄が、そんなことになるなんて思わなかった。

何が危ないのか:抜かれる・書き換えられる・消される

この穴を突かれると、被害はログインの突破だけにとどまりません。

  • 情報を抜き取られる:全ユーザーのメールアドレスやパスワード、購入履歴といった、本来見えないはずのデータをまとめて引き出されることがあります。個人情報の漏洩に直結します。
  • データを書き換えられる:料金や権限、残高といった値をこっそり変更されるおそれがあります。
  • データを丸ごと削除される:保管庫の中身をまとめて消されてしまうと、サービスそのものが立ち行かなくなります。

小さな入力欄1つの油断が、サービス全体の信頼を揺るがす重大な事故につながりうる。ここがSQLインジェクションの怖さです。

基本の防ぎ方:入力を「命令」でなく「ただの値」として扱う

対策の考え方は一貫しています。ユーザーの入力を、命令文の一部ではなく「ただのデータ」として扱うことです。代表的な方法を挙げます。

  1. プレースホルダ(プリペアドステートメント)を使う。これがいちばんの基本です。命令文の骨組みを先に用意し、入力する値は後から「ここに入る値です」と別枠で渡す仕組みです。値は最初から「命令ではなくデータ」として扱われるので、中に命令の断片が混ざっていても、そのまま実行されることはありません。
  2. 入力を検証する。メールアドレス欄には文字数や形式のルールを設けるなど、想定外の入力をあらかじめはじきます。プレースホルダと組み合わせる補強策です。
  3. 最小権限にする。アプリがデータベースを触るときの権限を、必要な範囲だけに絞っておきます。万一穴があっても、たとえば「削除はできない」状態にしておけば、被害を小さく抑えられます。
ムチオ
ムチオ
なんか難しそう…自分でその仕組みを全部つくらないといけないの?
ルミナ
ルミナ
いいえ、多くの開発ツール(フレームワークやORMと呼ばれるもの)には、プレースホルダの仕組みが最初から備わっています。それらを正しい使い方で使えば、SQLインジェクションは防ぎやすくなります。自分でゼロから守りを組む必要はありません。

AI開発での注意:生成されたコードが「値」を安全に扱っているか

AIにコードを書いてもらう場面でも、この観点は欠かせません。AIはデータベースにアクセスする部分もすらすら書いてくれますが、その書き方が入力を安全に扱っているとは限りません。

確認したいのは、生成されたコードが、ユーザー入力を命令文にそのままつなげていないか、プレースホルダのような仕組みを使っているか、という点です。動いたとしても、値の扱いが甘ければ穴は残ります。とくにAIにデータベースを直接触らせるときは注意が必要で、その手前で確認したいことはAIにデータベースを触らせる前に確認すべきことにまとめています。

次の一歩

まとめ

  • SQLインジェクションは、入力欄に混ぜた文字列で、データベースへの命令を書き換えてしまう攻撃。
  • 原因は、ユーザーの入力を命令文にそのままつなげてしまうこと。
  • 被害は、情報の抜き取り・データの書き換え・削除まで及び、重大な事故につながりうる。
  • 防ぎ方の基本は、入力を「命令」でなく「ただの値」として扱うプレースホルダ。入力検証と最小権限で補強する。

セキュリティの穴は、名前を知っていても「自分のコードのどこに当てはまるか」まで結びつかないと、なかなか防ぎきれません。独学でつまずきやすいのは、知識そのものよりも「何を、どの順番で学ぶか」です。守りの基礎も、あなたの目標から逆算した学ぶ順番の一部として、1対1で一緒に整理できます。