SQLインジェクションの概念
データはあらゆる情報システムにおいて最も重要な要素の一つです。そのため、組織は顧客情報を取得するために、ウェブアプリで動作するデータベースを利用します。
このデータを適切に管理することが重要です。そこでSQLの出番となります。
Sequelとも呼ばれるSQLは、Structured Query Languageの略で、データベース内の情報を取得・管理するために広く使われているクエリ言語です。
以上が、実際の話題であるSQLインジェクションにつながります。
SQLインジェクション (SQLi)は1998年に初めて知られ、XKCD 327の「Little Bobby Drop Tables」によって語り継がれています。インターネット上のアプリ(特にウェブアプリ)に今なお深刻な脅威を与える一般的な攻撃手法です。OWASPによるウェブアプリの安定性に対するトップ10の課題には、決して見過ごせない注入攻撃が含まれています。これらの攻撃により、攻撃者は危険なSQLクエリを実行でき、そのリクエストはウェブアプリのデータベース内のテーブルに送られます。
SQLインジェクションの脆弱性は、ネットワーク上の攻撃者が対象アプリのセキュリティ対策を突破するために利用されることがあります。攻撃者は、権限を乗っ取り、ウェブサーバのアプリやサイトのページから、構造化されたデータベース内の全情報を収集する恐れがあります。
SQLインジェクションにより、攻撃者はデータベース内のレコードを追加、編集、削除できます。
SQLインジェクションは、SQL Server、MySQL、OracleなどのSQLデータベースを利用するウェブアプリやサイトに影響を及ぼす、データベースの脆弱性です。
SQLインジェクションにより、攻撃者は個人情報、特許、独自技術などの機密顧客データにアクセスできるようになります。
攻撃者はまず、SQLインジェクション攻撃を行うために、対象のウェブアプリやサイトで不適切な入力を見つける必要があります。ウェブアプリやサイトの脆弱性は、このような入力をそのままSQLクエリに利用してしまいます。
攻撃者は、入力する文字列を自由に作成できます。これを悪意あるペイロードと呼び、攻撃の主要な手段となります。攻撃者がこのデータを送信すると、データベース上で有害なSQLクエリが実行されます。
前述の通り、SQLはリレーショナルデータベースのデータ管理のために作られ、データの取得、変更、削除に用いられます。多くのサイトやウェブアプリは全データをSQLデータベースに保存しています。
稀に、SQLを利用してOS上のコマンドを実行することも可能です。そのため、深刻なSQLインジェクション攻撃は大きな影響を及ぼす可能性があります。
攻撃者はSQLインジェクションを利用して、他のデータベースユーザの重要な認証情報を取得することがあります。場合によっては、そのユーザを複製し、データベース管理者として全アクセス権を得る恐れもあります。
さらに、SQLはデータベースから情報を抽出する手段でもあります。SQLインジェクションの脆弱性があれば、攻撃者はデータベースサーバ内の全情報にアクセスできる可能性があります。
また、SQLを利用すれば、データベースの完全な操作が可能となり、新規データの登録も行えます。例えば、金融系ウェブアプリでは、攻撃者がSQLインジェクションにより口座残高の変更、資金移動、取引の取消を行う恐れがあります。
さらに、SQLはデータベースからレコードを削除するためにも用いられます。管理者がバックアップを持っていたとしても、データ削除によりデータベース復旧までアプリの利用が困難になる可能性があり、バックアップに最新データが含まれていない場合もあります。
一部のデータベースサーバでは、データベースサーバ経由でOSにアクセスできる場合があります。これが意図的か否かにかかわらず、攻撃者はSQLインジェクションを足がかりに、その先のファイアウォール内部への攻撃を試みる可能性があります。
日常英語における「クエリ」とは情報の要求を意味します。同様に、プログラミングでのクエリも、データベースから情報を取得する動作を指し、データの追加、削除、更新に便利です。
以下は、よく使われるSQLクエリの例です
1. AND|OR
ANDは複数の条件を一つのクエリにまとめ、全条件が成立した場合に結果を表示します。
例
SELECT * FROM Developers
WHERE Country='India' AND City='Delhi';
ORは同様に使われ、どちらか一方の条件を満たす行が出力されます.
2. ALTER TABLE
ALTER TABLEはテーブルに列を追加または削除するための文です。
例
ALTER TABLE Developers
ADD BirthDate date;
3. AS(エイリアス)
ASを用いることで、データベース内の名前を変更することなく、列やテーブルに分かりやすい別名を付けられます。これにより、元の名前が長かったり複雑な場合でも、クエリの記述が簡単になります。
例
SELECT ID as CustomerID, Name AS Customers
FROM Customers;
例
SELECT o.ID, c.Name
FROM Customers AS c, Customer_orders AS o
WHERE c.id = 2 AND c.ID = o.customer_id;
3. BETWEEN
BETWEEN演算子は、指定された範囲に合致する結果のみを抽出します。日付、数値、テキストなどで値を指定できます。
例
SELECT * FROM Orders
WHERE Price BETWEEN 10 AND 15;
4. CREATE DATABASE
新しいデータベースを作成する場合は、CREATE DATABASE文を使用します。管理者権限が必要です。
例
CREATE DATABASE testing DB;
5. CREATE TABLE
CREATE TABLE文は、データベースに新しいテーブルを作成します。
例
CREATE TABLE Suppliers (
SupplierID int,
FirstName varchar(255),
LastName varchar(255),
City varchar(255),
Country varchar(255)
)
6. CREATE INDEX
CREATE INDEXはテーブルの索引を作成し、データ検索を高速化します。索引自体はユーザに表示されません。
例
CREATE INDEX idx_lastname
ON Persons (LastName);
7. CREATE VIEW
CREATE VIEWは、特定のクエリに基づいた結果セットから、既存テーブルの部分的な表示を作成します。ビューは実テーブルと似ており、不要なフィールドを含まないため、より扱いやすくなります。
例
CREATE VIEW [Present List Products] AS
SELECT ID, Name
FROM Products
WHERE Discontinued = No;
8. DELETE
テーブルから特定の行を削除する場合は、DELETE FROM文を用います。
例
DELETE FROM Developers
WHERE Name='Antonio Indigo';
例
DELETE * FROM Developers;
9. GRANT
GRANTは、ユーザにデータベースへのアクセス権を与えるための文です。
例
GRANT SELECT, UPDATE ON YOUR_TABLE TO FIRST_USER, SECOND_USER;
10. REVOKE
REVOKEは、ユーザから権限を取り上げるための文です。
例
REVOKE SELECT, UPDATE ON YOUR_TABLE FROM FIRST_USER, SECOND_USER;
上記はSQLクエリの一部にすぎません。
SQLインジェクションには、主にIn-Band SQLi、Inferential SQLi、Out-of-Band SQLiの3種類があります。
In-Band SQLiは、最も一般的かつ直接的なSQL注入攻撃です。同一の通信路で攻撃の実行と結果の取得が行われます。
ErrorベースSQLiとUnionベースSQLiが、In-Band SQLiの2種類です。
Error ベースSQLi
ErrorベースSQL注入は、エラーメッセージからデータベースの構造に関する詳細情報を引き出す手法です。攻撃者はエラーメッセージを収集するだけで、必要な情報を得ることができます。ウェブアプリ開発時、エラーは重要ですが、ログに残すか対策を講じる必要があります。
Union ベースSQLi
このSQL注入は、UNION構文を使って複数のSELECT文の結果を一つに結合し、その結果をHTTPレスポンスの一部として送信します。
In-Band型とは異なり、Inferential SQLインジェクションは情報を引き出すのにより時間がかかりますが、他のSQL注入攻撃と同様に危険です。
Inferential SQLiでは、ウェブアプリを通じて直接情報が送られることはなく、攻撃者は結果を見ることができません(このため『盲目SQLインジェクション攻撃』とも呼ばれます)。それでも、攻撃者はペイロードを送り、アプリやデータベースサーバの反応を観察することで、データベースの構造を変更または制御できる可能性があります。
Inferential SQLインジェクションには、Blind-boolean-based SQLiとBlind-time sensitive SQLiの2種類があります。
Boolean-Based(内容ベース)Blind SQLi
BooleanベースSQLインジェクションは、クエリの結果がTRUEかFALSEかにより、アプリの反応が変わる仕組みを利用した攻撃手法です。
結果に応じてHTTPレスポンスのメッセージが変化するため、ペイロードが有効か偽かを判断できますが、データ自体は返されません。攻撃者が1文字ずつ情報を抽出する必要があり、特に大規模なデータベースではこの攻撃は非常に遅くなります。
Time-based Blind SQLi
TimeベースSQLインジェクションは、SQLクエリを用いてデータベースに一定時間の遅延を発生させ、その応答時間からクエリの結果がTRUEかFALSEかを判断する手法です。
結果により、HTTPレスポンスが即時または遅れて返され、ペイロードの有効性を確認できますが、データ自体は返されません。攻撃者が1文字ずつ情報を抽出するため、特に大規模なデータベースでは攻撃は非常に遅くなります。
Out-of-Band SQLインジェクションは、ウェブアプリのデータベースサーバで特権的な機能が有効な場合に使用される特殊な手法です。通常の通信路が使用できない場合に採用されます。
この手法は、サーバの反応が不安定な場合、Inferential時間ベース手法に代わる選択肢となります。
Out-of-Band SQLインジェクションは、ウェブアプリのデータベースサーバで有効な機能に依存するため、一般的ではありません。
サーバの応答が予測できない場合、Out-of-Band手法はInferential時間ベース手法の代替になり得ます。
Out-of-Band SQLi手法は、データベースサーバがHTTPやDNS経由で攻撃者に情報を送信する能力に依存します。Microsoft SQL ServerのXPディレクトリツリーリクエストは、攻撃者がDNS問い合わせを自ら管理するサーバへ送信する一例です。また、Oracle DatabaseのUTL_HTTPパッケージを利用すれば、SQLやPL/SQLから攻撃者管理のサーバへHTTPリクエストを送ることが可能です。
SQLインジェクションの例
以下は、直接的なSQLインジェクション攻撃の一例です。貴社が、顧客が自分のプロフィールを顧客IDで取得できるウェブアプリを作成したとします。顧客が入力した顧客IDは、アプリのフロントエンドからバックエンドのデータベースへ送られ、データベースがSQLクエリを実行、その結果がウェブアプリに返され、最終的に顧客に表示されます。
以下は、シンプルなSQLインジェクション攻撃の例です。貴社が、顧客が自分の顧客IDを入力してプロフィールを取得できるウェブアプリを構築したとします。顧客が入力したIDは、アプリのフロントエンドからバックエンドのデータベースに送られ、SQLクエリが実行され、その結果がウェブアプリに返され、最終的に顧客に表示されます。
続いて、バックエンドのデータベースクエリの例を示します:
SELECT *
FROM clients
WHERE customer_id = '1234567'
もし顧客がウェブフォームに入力するcustomer_idが以下のようであれば:
1234567; DELETE * clients WHERE '1' = '1'
すると、バックエンドのデータベースは以下のSQLを実行します:
SELECT *
FROM clients
WHERE customer_id = '1234567';
DELETE *
FROM clients
WHERE 'x' = 'x'
データベースは、セミコロンで区切ることで複数のSQL文を続けて実行します。入力の除去が不十分な場合、攻撃者はテーブル全体を削除できてしまいます。
上記の例は意図的に単純化されたものであり、SQLインジェクション攻撃の手法は他にも存在します。いずれも、ウェブアプリが入力の除去に失敗している点に起因しています。
続きは第2部に記載されます。
最新情報を購読