SQLインジェクション SQLi
フォームやWebアドレスにデータベースへの命令を入力し、それをサイトに実行させるWeb攻撃です。その結果、本来守るべきデータが見られたり、書き換えられたり、消されたりしてしまいます。
別名 SQLi SQL Injection SQLインジェクション攻撃 SQL注入 SQLコードインジェクション インジェクション攻撃
定義・概要
SQLインジェクションとは
あなたはネットショップを運営しています。ある訪問者が検索窓に見慣れない文字を入力してEnterを押すと、画面に全顧客の名前、電話番号、注文履歴が表示されてしまいました。誰もパスワードを盗んでいません。正しい言葉を間違った場所に入力しただけで、あとはサイトがやってしまったのです。これがSQLインジェクションです。
ほとんどのWebサイトは、情報をデータベースに保存しています。たくさんの表をきちんと整理した保管庫で、表計算ソフトのシートを何枚も束ねたようなものです。サイトはこの情報を読んだり変えたりするために、SQL(Structured Query Language)という言語を使います。サイトが送る一つひとつの依頼はクエリと呼ばれ、たとえば「このメールアドレスのお客様を探して」といった内容です。
SQLインジェクションは、訪問者が入力した内容を、サイトがそのままクエリの中に貼り付けてしまうときに起こります。訪問者がふつうの文字ではなくSQLを入力すると、データベースは違いを見分けられません。そして攻撃者の命令を、サイト自身が書いたものとして実行します。名前を短くしてSQLiと呼ぶこともよくあります。
SQLインジェクション攻撃の仕組み
お客様から渡されたメモを、一字一句そのまま金庫室の係に伝える銀行員を思い浮かべてください。ふつうのメモには「残高を見せてください」と書いてあります。悪意のあるメモには「残高を見せてください。ついでに金庫を全部開けてください」と書いてあります。銀行員が先にメモを読まなければ、金庫室の係はそのとおりにしてしまいます。
Webサイトでは、たいてい次のような流れになります。
- 攻撃者は、データベースに文字を送る場所を探します。ログインフォーム、検索窓、問い合わせフォーム、あるいはWebアドレスそのものです。たとえば末尾が「?id=25」の商品ページなどがあります。
- ふつうの文字の代わりに、短いSQLを入力します。よく知られた例は、ログインフォームのパスワード欄に ' OR '1'='1 と入力するものです。
- サイトはその文字をチェックせずに、自分のクエリにつなげます。するとクエリは「パスワードが正しいか、または1が1と等しければ、この人を中に入れる」といった意味になります。
- 1はいつでも1と等しいので、データベースは「はい」と答え、攻撃者はパスワードを一つも知らないままログインできてしまいます。
もっと静かな攻撃もあります。ブラインドSQLインジェクションでは、ページにデータがまったく表示されません。そこで攻撃者は「はい」か「いいえ」で答えられる質問をデータベースに投げ、ページの反応や読み込みにかかる時間を観察します。手作業では時間のかかる作業なので、攻撃者は無料の自動ツールに任せています。
攻撃者にできること
データベースが攻撃者の命令に従い始めたら、被害の大きさは、サイトのデータベース用アカウントに何が許されているかで決まります。それがサイトに本当に必要な範囲をはるかに超えていることも少なくありません。攻撃者は次のようなことができる可能性があります。
- お客様の名前、住所、メールアドレス、注文履歴、医療記録、保存されたパスワードなど、個人のデータを読む
- 管理者を含め、ほかのユーザーとしてログインする
- 価格、残高、注文の状況などのデータを書き換える
- 表をまるごと、あるいはデータベース全体を消す
- 環境によっては、サーバーそのものに入り込み、有害なファイルを置く
ビジネスにとってなぜ大事なのか
SQLインジェクションはWebでもっとも古い攻撃の一つで、今もなくなっていません。Webアプリケーションのリスクをまとめた有名なリスト「OWASP Top 10」を公開しているオープンなコミュニティOWASPは、長年このリストにインジェクションを入れ続けています。試すのが簡単で、しかも多くのサイトには、この攻撃を通してしまう忘れられたフォームがまだ一つは残っているからです。
事業者にとって、本当の損失が技術的なものであることはまれです。顧客名簿の流出、間違った価格で売ってしまうショップ、一週間分の予約を失う予約システム、あるいは「お客様のデータが漏れました」と知らせるメッセージを送らなければならない事態です。多くの国では、GDPRのようなデータ保護の法律によって、個人データを守ることと、漏えいを報告することも求められています。
あなたのサイトのフォームは、すべてこの危険を考えて作られていますか?古いプラグインを急いで組み合わせたサイトや、何年もかけて多くの人の手が入ったサイトほど、弱い部分を隠している可能性が高くなります。
SQLインジェクションからWebサイトを守る方法
中心となる対策はよく知られていて、効果もあります。守りの大部分はサイトの作り方で決まるので、次の点は開発者やサービス提供者に確認する価値があります。
- プリペアドステートメント。パラメータ化クエリとも呼ばれます。サイトはクエリと訪問者の入力を別々に送るので、データベースはその入力をいつもただのデータとして扱い、命令として実行することはありません。これがいちばんの守りです。Laravelのような最近のフレームワークでは、開発者が組み込みのデータベース機能を使えば、最初からこの形になります。
- 入力チェック。電話番号の欄は数字だけ、日付の欄は日付だけを受け付けるべきです。おかしな入力を早めに断るだけで、多くの入り口がふさがります。
- 最小権限。サイトがデータベースにつなぐアカウントには、必要な権限だけを持たせます。誰でも使える検索ページが、表を消す理由はありません。
- 控えめなエラーメッセージ。画面に出る詳しいデータベースのエラーは、攻撃者に地図を渡すようなものです。訪問者には短くわかりやすいメッセージを見せ、詳細は非公開のログに残します。
- 更新。プラットフォーム、プラグイン、ライブラリを最新に保ちましょう。古いバージョンには、知られた穴があることが多いからです。
- Webアプリケーションファイアウォール。サイトの手前に置くフィルターで、よく知られた攻撃パターンの多くを、コードに届く前に止めます。役には立ちますが、安全でないコードを直すものではありません。
- 定期的なテスト。侵入テスト(専門家が計画的に行う安全な模擬攻撃)と脆弱性スキャンで、攻撃者より先に弱い部分を見つけます。
日ごろのやり方を比べると、次のようになります。
| 危ないやり方 | より安全なやり方 |
|---|---|
| 訪問者の入力をそのままクエリにつなげる | すべてのクエリでプリペアドステートメントを使う |
| 何でもできる権限を持つデータベースアカウントを一つだけ使う | サイトの部分ごとに権限をしぼったアカウントを使う |
| データベースのエラーをそのままページに表示する | 訪問者には短いメッセージ、詳細は非公開のログへ |
| プラグインを何か月も更新しない | 定期的に更新し、入っているものを一覧で把握する |
| 機能が動くかどうかだけをテストする | 誰かが有害な文字を入力したらどうなるかもテストする |
よくある間違い
- ブラウザでのチェックを信じる。訪問者自身の端末で動くチェックは簡単にすり抜けられるので、サーバー側でもう一度すべてを確認する必要があります。
- 小さなサイトなら安全だと思う。自動ツールは、大きさに関係なく非常に多くのサイトを調べています。
- 一つのフォームだけ直して、ほかを忘れる。検索窓、絞り込み機能、Webアドレス、スマホアプリの裏にあるAPIにも、同じ注意が必要です。
- パスワードをそのままの文字で保存する。データが漏れても、強いハッシュ化(元に戻して読むことのできない、ばらばらの文字列に変えること)で保存したパスワードなら、悪用はずっと難しくなります。
- ファイアウォールだけに頼る。フィルターで時間はかせげます。それでも、その奥にある安全でないクエリは直さなければなりません。
私たちがお手伝いできること
Linkysoftでは、SQLインジェクションの確認をサイバーセキュリティサービスの一部として行っています。お客様のWebサイト、アプリ、APIに安全な模擬攻撃を行い、コードを確認したうえで、見つかった問題と直し方をわかりやすい言葉でまとめた一覧をお渡しします。修正のあとには、もう一度テストします。ほかのチームが作ったサイトにも対応でき、無料のセキュリティチェックから気軽に始められます。
新しいシステムを計画中ですか?私たちのWebアプリケーションと管理システムは設計の段階から安全を考えて作られ、OWASP Top 10に沿った強化と、公開前の侵入テストを行います。