油断できないSQLインジェクション。その種類とWebアプリにおける対策
SQL インジェクション(SQL Injection、略称: SQLi) は、バックエンドにおけるデータベース操作に悪意のある SQL クエリを意図的に注入して、データベース内のデータに不正にアクセスできてしまう脆弱性および攻撃手法です。
データベースには、企業の機密情報や顧客の個人情報などが保存されているため、攻撃者はこの機密情報を狙って取得を試みようとします。
SQL インジェクションは、攻撃が成功すると被害は Web アプリケーション内に留まらず、情報漏えいという形でビジネスに悪い影響を与えます。
ユーザーリストを不正に表示できたり、データベースのテーブル全体の削除できたり、場合によっては攻撃者がデータベースの管理者権限を取得できたりする可能性もあります。
SQL インジェクションによって顧客の個人情報(電話番号、住所、パスワード、クレジットカード情報など)が漏えいした場合、企業としても顧客の信頼を失ってしまいます。
本記事では、SQL インジェクションの概要・脆弱性の種類についてご紹介し、Web 開発者としてできる対策方法について解説していきます。
どのくらい発生しているのか
SQL インジェクションはどのくらい発生しているのでしょうか。
以前クロスサイトスクリプティング(XSS)とは?でもご紹介したように、情報処理推進機構(IPA)が四半期ごとにとりまとめている「ソフトウェア等の脆弱性関連情報に関する届出状況」から2019 年第 4 四半期(10 月~12 月)の資料を見ていきましょう。
ウェブサイトの脆弱性の種類別の届出状況(IPA の資料より引用)
「SQL インジェクション」は、クロスサイトスクリプティング、DNS 情報の設定不備に続き発生しており、過去 2 年間の届け出内訳を見ても件数は少ないものの、恒常的に発生していることが伺えます。
SQL インジェクションは対策が進んでいるとはいえ、いまだに多くの Web サイトや Web サービスで発生しえる脆弱性といえるでしょう。
どうして SQL インジェクションは発生するのか
SQL インジェクションについてご紹介する前に、まずは SQL(Structured Query Language)について簡単にご紹介しましょう。
SQL クエリについて
SQL は、データベースから必要なデータを読み書きするための標準化された言語です。
クエリと呼ばれる命令文・コマンドを通して、レコードの取得、更新、削除ができます。クエリのことを SQL 文、SQL 構文とも呼ばれます。
SQL インジェクションの例
例として、あるユーザーの情報を取得するために、http://www.example.com/?userid=20という URL にアクセスすると、データベースに対して以下のクエリが発行されるとしましょう。
SQL インジェクションを実行しようとする攻撃者は、SQL クエリを含めた文字列を入れてアクセスすることで、クエリが変化することを期待して意図しないデータを取り出そうと試みます。以下のような URL になります。
この URL にアクセスすると、SQL クエリに利用する値として 20 or 1=1 を Web アプリケーション側で受け取ることになります。アプリケーション側で実装されたコードが、入力する値に対してバリデーション(検証)処理と後述するプレースホルダーの利用がされていない場合、以下のようなクエリが生成されます。
上記のようなクエリが生成されると 1=1 というステートメントは常に true となってしまい、データベース内のすべてのユーザー情報を返してしまうことになるのです。
そのため、正しい意図したクエリになるように修正が必要です。
SQL インジェクションの種類・攻撃手法
SQL インジェクション脆弱性の種類および攻撃手法として、いくつかの種類があります。
代表的なものとして「インバンド SQL インジェクション」「ブラインド SQL インジェクション」について紹介します。
インバンド SQL インジェクション(In-Band SQLi, Classic SQLi)
インバンド SQL インジェクションは、SQL インジェクション攻撃の中で最も一般的で簡単できるものです。
いずれも Web アプリケーションからのレスポンスを収集して分析していくことになります。
エラーベース SQL インジェクション(Error-Based SQLi)
攻撃者がデータベースに対してエラーメッセージを生成させるアクションを実行します。
攻撃者は、これらのエラーメッセージを見てデータベース構造を調査できることになり、別の攻撃方法を考えるきっかけを与えることになります。
UNION インジェクション(Union-Based SQLi)
UNION インジェクションは、複数の SELECT ステートメントの結果を 1 つの結果に結合し、HTTP レスポンスの一部に結果が含まれて返ってくるインバンド SQL インジェクションです。
テーブルを結合させることができるため、アプリケーションのテーブルだけでなくシステムが元々持っているテーブルを読み出すことも可能になります。
ブラインド SQL インジェクション(Inferential SQLi, Blind SQLi)
ブラインド SQL インジェクションは、攻撃者がデータを Web サーバーに送信し、Web サーバーのレスポンスと動作を観察・分析することにより、攻撃先の理解を深める攻撃方法です。
Web サーバーからのレスポンスから直接データを盗み出すものではなく、不正な SQL とページのレスポンスの違いを見て、データベースの管理に関わる情報(実行しているユーザーの情報やテーブル名など)を盗み出すものになります。
データベースからの結果やデータが攻撃者に転送されることはないため、ブラインド SQL インジェクションと呼ばれます。
Web サーバーのレスポンスや挙動に依存するため、悪用するのに時間がかかる傾向にありますが、他の種類の SQL インジェクションと同じくらいリスクになりえます。
どういった対策をすれば良いのか
それでは、Web アプリケーションの開発者にとって、どのような対策を行えば良いでしょうか。
Web アプリケーションにおいて SQL インジェクションが発生するのは、SQL のクエリ(構文)が意図しないクエリになってしまうことが原因です。
構文の意味が変わらないようアプリケーションコードの修正を行うことがまず第 1 の対策方法といえるでしょう。以下に対策方法をご紹介します。
SQL クエリをプリペアドステートメント/プレースホルダで組み立てる
昨今の Web アプリケーション開発においては、DB アクセスライブラリや O/R マッパーを利用してクエリを発行することが一般的になってきていると思います。
DB アクセスライブラリや O/R マッパーには、プリペアドステートメント/プレースホルダと呼ばれるクエリの一部と変数をバインドさせる機構が備わっており、意図したクエリになるように処理を行ってくれます。
実際、多くの O/R マッパーでは、先述したプレースホルダーなどの安全な SQL 発行を行う構文と、それを基本的に利用するようにドキュメントが整備されている傾向にあります。
そのため、開発者によって安全ではない書き方をしてしまうといったミスを防げる利点があります。是非活用するようにしましょう。
すでにプリペアドステートメント / プレースホルダを活用されている方は、アプリケーションコード内で使っていないところがないかどうか、今一度確認されることをお勧めします。
ユーザーがリクエストした入力値を検証し、エスケープ処理を行う
ユーザーから受け取った文字列をバリデーション(検証)し、意図した SQL クエリになるようにエスケープ処理を行うようにしましょう。
たとえば一覧ページの絞り込みフィルターのように URL のクエリパラメーターと連動するような箇所、ログインフォームなどユーザーの個人情報を格納したテーブルにアクセスするような箇所は注意が必要です。
PHP + MySQL 構成の一例にはなりますが mysqli_real_escape_string や PDO::quote 関数を用いることでエスケープ処理が可能です。
DB アクセスライブラリ、O/R マッパーの導入を検討する
エスケープ処理を行う方法もありますが、安全な SQL を発行するという観点で前項でご紹介した「プリペアドステートメント / プレースホルダで組み立てる」アプローチも検討してください。
データベースのエラーメッセージをレスポンスボディに含めない
API からデータベースにクエリを投げてエラーとなった場合、SQL のエラーが API のレスポンスボディまで返すような実装になっている場合、攻撃者はここから SQL エラーメッセージの特徴を見てデータベースの種類やバージョン、利用している文字セット等を推察できてしまいます。
今一度、エラーハンドリング機構に問題がないか、確認しましょう。
ライブラリやツールを最新版にアップデートする
データベースアクセスライブラリや O/R マッパーライブラリ、またデータベースにアクセスできる管理ツールにおいても、SQL インジェクションの脆弱性が発見されるケースがあります。
つい先日も、MySQL 管理ツール「phpMyAdmin」において、SQL インジェクションの脆弱性が発見され、修正されたバージョンが提供されています。
(詳しくは NVD による CVE-2020-5504, JVN による JVNDB-2020-01438 をご参照ください)
ライブラリやツールに脆弱性が発見されたら対応できるようにウォッチすることが重要です。定期的に最新版にアップデートするようにしましょう。
脆弱性診断 / DAST を検討する
Web セキュリティの観点では「Webセキュリティはどこから手をつければよいのか?」でもご紹介したように、脆弱性診断サービスを利用することも検討してください。
また、Web アプリケーションファイアウォール(WAF)を導入することで SQL インジェクションを引き起こすような、怪しいクエリやリクエストを検知・ブロックすることで、SQL インジェクションの発生を軽減することも可能です。
さいごに
SQL インジェクションはクロスサイトスクリプティング同様、Web 開発者も運営者も注意を払うべき脆弱性であり、また適切な対策を行えば防ぐことができる脆弱性です。
ユーザーが入力できる文字列をチェックし、正しいクエリが作られることを意識することが、SQL インジェクション対策における意識付けであり、解消へ向けての第一歩となります。
Web サービスに携わる開発者として、セキュア開発を意識しながら開発を進めていくことが大切です。
また Web サイトの運営者としても、日ごろからセキュリティについて注視し、セキュリティ対策を強化するよう努めていきましょう。
稼働中の Web サイト・Web アプリケーションに対して、SQL インジェクションの検証・対策を実施するのは大変な労力がかかります。
脆弱性が見つかっても開発やビジネスの優先度から対策が後回しになったり、放置になるケースもあるのではないでしょうか。
SQL インジェクション攻撃が成功した場合、個人情報の漏えいに直結する可能性が高く、ご利用のユーザーや顧客に被害の影響が大きくなります。
企業リスクにも直結しますので、継続的にリソースを確保して検証および対策を実施していきましょう。
最後になりますが、Web アプリケーションで用いられるフレームワーク・ライブラリに潜む SQL インジェクションの脆弱性については、yamory を用いることで検出が可能です。
ぜひ一度お試しいただければ幸いです。