SQLインジェクション(SQLi)は、現代のWebアプリケーションが直面する最も深刻なセキュリティ脅威の1つです。悪意のあるユーザーは、データベースに悪意のあるコードを注入し、機密情報へのアクセス、データの変更や削除、さらにはシステム全体の制御まで可能になります。そのため、SQLi攻撃の仕組みと防止方法に関する知識と認識は、現代のWebアプリケーションを安全に保つうえで不可欠です。
SQLインジェクション攻撃とは?
SQLインジェクション攻撃とは、アプリケーションの脆弱性を悪用する悪意のあるコード注入です。攻撃が成功すると、サイバー犯罪者は次のことを実行できる可能性があります。
- 機密データへのアクセス
- データベース上で管理者タスクを実行
- データベース情報の改変
- システムからファイルを復元
場合によっては、攻撃者が基盤となるデータベースのオペレーティングシステムにコマンドを発行できることさえあります。データベース管理者はこうした脅威を認識し、アプリケーションを攻撃から守るための予防的な対策を講じなければなりません。
SQLi攻撃の仕組みとは?
SQLi攻撃は、アプリケーションの構造化照会言語(SQL)クエリに悪意のあるコードを注入することで実行されます。WebサイトやWebアプリケーションが、サーバーで処理する前にユーザー入力を適切に検証しない場合、こうした攻撃が可能になります。攻撃者はアプリケーションの特定の脆弱性を悪用し、データベースの保護された部分へのアクセスや既存データの変更を行えます。
SQLi攻撃の影響
SQLi攻撃が成功すると、規模を問わず組織に深刻な影響を及ぼす可能性があります。攻撃者は認証情報を盗み、クレジットカード番号、社会保障番号、その他の個人データなど、顧客の機密情報を含むデータベースにアクセスできる場合があります。また、既存データを変更または削除してサービスを妨害したり、金銭的利益を得るために記録を改ざんしたりすることも可能です。さらに攻撃者は、ネットワーク内でのラテラルムーブメントを行う、より大規模な攻撃キャンペーンの一環として、こうした攻撃を利用できます。
SQLi緩和策に関する専門家の6つのヒント
Open Web Application Security Project(OWASP)のSQLインジェクション防止チートシートには、SQLiに関する最良のヒントがまとめられています。同団体が示す第1・第2の防御策――プリペアドステートメントやストアドプロシージャの利用、許可リストによる入力検証の実施など――を以下に紹介します。
第1の主要防御策:プリペアドステートメントの利用(パラメーター化クエリ)
変数バインディング(パラメーター化クエリとも呼ばれます)を用いたプリペアドステートメントは、SQLインジェクションを緩和するための第一線の防御策とすべきです。このコーディング方式では、開発者が最初にSQLコード全体を定義し、後から各パラメーターをクエリに渡せます。これにより、どのようなユーザー入力が使われても、データベースはコードとデータを区別できます。
プリペアドステートメントの利点は、攻撃者が悪意のあるSQLコマンドを挿入しても、クエリの意図を変更できないことです。さらに、こうしたクエリは記述構造がより単純なため、動的クエリよりも開発者にとって書きやすくなります。
第2の主要防御策:適切に構成されたストアドプロシージャの利用
ストアドプロシージャとは、データベースに保存され、そこで実行されるSQLコードの断片です。これにより、アプリケーション層にSQLコードを埋め込む必要性が減ります。ストアドプロシージャはユーザー入力を受け付けるよう設定することもでき、アプリケーション内でユーザー入力を検証する負担を軽減できます。
SQLiのリスクを緩和する際には、適切に構成されたストアドプロシージャを利用することが重要です。すべてのストアドプロシージャが悪用を免れるわけではありませんが、SQL文を自動的にパラメーター化する標準的なストアドプロシージャのプログラミング構造を利用すれば、潜在的な攻撃からの保護に大きな効果を発揮します。
プリペアドステートメントとストアドプロシージャを利用すれば、最終的には同じ結果――悪意のあるSQLi攻撃からの防御に成功すること――につながります。ただし、開発者が適切な構成と実行を確保する対策を講じることが前提です。
第3の主要防御策:許可リストによる入力検証
テーブル名や列名、昇順(ASC)・降順(DESC)などの並べ替え順序の指定といった、バインド変数の使用を想定していないSQLクエリの要素は数多くあります。このような場合は、許可リストと照合して入力を検証するのが最善の方法です。
ユーザーパラメーターの値を使ってテーブル名や列名を決定する場合は、クエリ内に未検証のユーザー入力がないことを確認するため、これらのパラメーターを想定される値または有効な値と照合する必要があります。
許可リストによる入力検証は、悪意のある入力によるセキュリティ侵害の防止に大きく役立ちます。ただし可能であれば、コード全体を書き直すことも検討すべきです。こうした問題は、コーディング設計の不備を示す症状である可能性があるためです。
第4の主要防御策:ユーザー提供の入力をすべてエスケープ
ユーザー提供の入力をすべてエスケープする方法は、上記3つの防御策を実施できない場合の最終手段として使うべき技術です。クエリに入れる前にユーザー入力をエスケープする方法は効果的ですが、実装がデータベース固有になることが多く、あらゆる状況であらゆる種類のSQLインジェクションから保護できる保証はないため、慎重に適用する必要があります。ユーザー入力のエスケープは通常、入力検証の実装が費用対効果に合わないレガシーコードに推奨されます。
追加の防御策5:最小権限の徹底
データ環境の安全性を確保するため、管理者は各データベースアカウントに割り当てる権限を最小限に抑えなければなりません。アプリケーションユーザーにデータベース管理者(DBA)アクセスや管理者相当の権限を与えるのは便利かもしれませんが、この慣行はネットワークに弱点を生む可能性が高くなります。
すべてのアクセス権が適切かつ安全であることを確保するには、既存の権限を制限しようとするのではなく、基本から始めて必要なアクセス権を見極めることが推奨されます。必要な場合でも、各アカウントには特定のテーブルへの読み取りアクセスだけを付与すべきです。これにより、攻撃を受けた場合にデータが不必要にさらされるのを防げます。
テーブル全体へのアクセスを付与するのではなく、アカウントが特定の一部だけを必要とする場合は、アクセス範囲を制限するビューを作成し、そのビューに対する権限を付与する方が適切です。データの安全性を確保するため、可能な限り「作成」や「削除」の機能を持つアカウントにはアクセス権を付与しないことが推奨されます。
安全なデータベースを確保するため、IT部門はストアドプロシージャの利用を義務付け、アプリケーションアカウントがクエリを直接実行できないよう制限するポリシーを策定すべきです。さらに、こうした制限付きアカウントは必要なストアドプロシージャだけを実行できるようにし、データベース内のテーブルへのアクセス権は一切付与すべきではありません。
SQLiでは、攻撃者が認証済みのパラメーター値を操作し、本来ならアクセスできない情報に侵入できるようになります。ただし、その情報へのアクセス自体はアプリケーションに許可されている可能性があります。そのため、アプリケーションに付与する権限を減らせば、未承認のアクセス試行のリスクを大幅に低減できます。
追加の防御策6:第2の防御策として許可リストによる入力検証を実施
許可リストによる入力検証を実施すると、攻撃の拡大を防ぎ、SQLデータベースを日常的に利用する環境にさらなるセキュリティ層を提供できます。第2の防御策として実装する場合は、許可されていない入力がSQLクエリに渡される前に、その注入を検出して防止できるようにする必要があります。
入力検証は、ワークフローに有効なデータだけが入るようにし、データベースに不正な形式のデータが残ることによる誤動作の可能性を最小限に抑えるうえで重要です。この種の防御は、外部ソースからデータを受け取ったら、できるだけ早く実施するのが望ましいでしょう。さらなる正確性を確保するため、構文レベルと意味レベルの両方を評価すべきです。
SQLインジェクションの例
SQLi攻撃がどのように発生するかを理解するには、例を確認するとよいでしょう。次のシナリオを考えてみます。
攻撃者が、オンラインストアで使用されているデータベースへの不正アクセスを試みています。攻撃者は悪意のある入力を作成し、保護されていないSQLクエリに注入します。これにより、データベースに保存された機密情報を抽出し、自由に変更できるようになります。
たとえば、SQLクエリが次のようになっているとします。
SELECT * FROM users WHERE username = ‘$username’ AND password = ‘$password.’
攻撃者は、次のような悪意のある入力を作成します。
Username: 1′ or ‘1’ = ‘1
Password: 1′ or ‘1’ = ‘1
この変更されたSQLクエリは、次のようになります。
SELECT * FROM Users WHERE Username=’1′ OR ‘1’ = ‘1’ AND Password=’1′ OR ‘1’ = ‘1’
ハッカーは認証プロセスにOR条件を効果的に注入しました。さらに、その条件‘1’ = ‘1’は常に真であるため、このSQLクエリでは必ず認証プロセスが回避されます。
この変更されたSQLクエリは「Users」テーブルのすべてのレコードを返します。有効なユーザー名とパスワードが入力されたかどうかは関係ありません。これは、攻撃者が機密情報への不正アクセスを得るために使える、最も一般的な手法の1つです。
「;」のような文字を使って既存のクエリの末尾に別のクエリを追加したり、「–」を使ってコメントアウトし、既存のクエリの一部を切り離したりすれば、ハッカーはテーブル全体を削除したり、そこに含まれるデータを変更したりできる可能性があります。さらに基盤となるオペレーティングシステムにコマンドを発行し、マシンを乗っ取ってネットワークの他の部分を攻撃するための足掛かりとして利用することさえ可能です。
SQLインジェクション攻撃の目的とは?
SQLi攻撃には、データの機密性と完全性の侵害、データの窃取、そして最終的にはネットワーク全体の侵害という4つの主な目的があります。
- データの機密性を侵害する:攻撃者はSQLi攻撃を利用して、クレジットカード情報やパスワードなど、データベースに保存された機密データにアクセスできます。
- データの完全性を侵害する:ハッカーは、データベースに保存されたデータを承認なく操作または削除できます。これにより機密情報が盗まれたり、データベースの完全性に依存するシステムに対して分散型サービス拒否(DDoS)攻撃が行われたりする可能性があります。
- データを盗む:データの窃取は、SQLi攻撃の最も一般的な目的の1つです。攻撃者はこの種の攻撃を利用して、データベースからログイン認証情報やその他の機密情報を盗めます。
- ネットワーク全体を侵害する:SQLi攻撃により、ハッカーは乗っ取ったデータベースを足掛かりとしてネットワークの他の部分にアクセスできます。その後、攻撃者はネットワークに接続された他のシステムやネットワークに対して、さらなる攻撃を仕掛けることが可能になります。
結論:SQLインジェクション攻撃からネットワークを守る
SQLインジェクションは、最も一般的なWebアプリケーションのセキュリティ脅威の1つであり、対策を講じなければ深刻な結果を招く可能性があります。こうした攻撃から身を守るため、組織はセキュリティ戦略全体の一環として、入力検証とパラメーター化クエリを実装すべきです。
さらに、すべてのデータベースが適切に構成され、最新のパッチで定期的に更新されていることを確認することが不可欠です。効果的なSQLi緩和戦略を実施すれば、組織が攻撃によって侵害されるリスクを大幅に低減できます。
組織を守る最善の方法は、堅牢な次世代ファイアウォールを導入することです。ネットワークセキュリティについて専門家の支援が必要なら、エンタープライズネットワークセキュリティの優れた企業に相談しましょう。