SQLインジェクションは、緩いコーディングの習慣を利用します。 これは、敵対的なユーザーが、収集しようとしたデータではなく、Webフォームの1つにコードを送信する攻撃です。 敵対的なコードは、予期しない方法でデータベースにクエリを実行するか、Webアプリケーションから抜け出し、クラウドサーバー上で直接操作を実行します。 疑いを持たないサイトに対してSQLインジェクション攻撃を開始するのは驚くほど簡単です。 このような攻撃から身を守ることは、初日からの最優先事項の1つです。

ステップ1-脆弱なコードを認識する方法を学ぶ

SQL攻撃は常に、2つの部分を含むユーザーが送信した文字列の形式を取ります。 最初の部分は、コードが実行しようとしているコマンドを安全に終了する方法の推測です。 2番目の部分は、攻撃者がVPSで実行したい敵対的なコードです。 コードの緩みを利用するように設計された、ユーザーが送信した文字列の例を次に示します。

x' AND user.email IS NULL; --

これは、あなたが自分で書いたもののように見えます-そしてそれがポイントです。 ユーザーは、コードがこの文字列を受け取り、次のようなSQLクエリで使用することを望んでいます。

SELECT email, passwd FROM user
WHERE email = 'x' AND user.email IS NULL; --';

これはあまり効果がないように見えるかもしれませんが、アプリケーションの応答方法によっては、攻撃者に関連するテーブル名を正しく推測したことを通知する可能性があります。 その後、ユーザー名やパスワードなど、より多くの情報を明らかにし始める可能性のあるさらなる攻撃があります。

理解すべき重要な詳細は、敵対的なコードがSQL引用符を閉じようとするか、他の方法でSQLクエリの制約から抜け出し、独自のデータを要求または挿入しようとすることです。

すべてのSQLインジェクション攻撃で終了引用符が必要なわけではありません。 コードが数値に対してクエリを実行する場合、そのデータを引用符で囲むことはありません。 これにより、次のタイプのインジェクションに対して脆弱になります。

2097 OR 1=1

攻撃者は、アプリケーションが次のようなことを行うことを望んでいます。

SELECT somedata FROM yourtable
WHERE userid = 2097 OR 1=1;

あなたのコードは、ユーザーIDが正しいユーザーのユーザーIDと一致した場合にのみ、上記のSQLクエリがデータを返すことを意図していました。 ただし、SQLインジェクションにより、クエリは常にデータを返します。

重要なのは、特定のSQLインジェクションの正確な動作ではありません。 これから取り除く最も重要なことは、すべてのSQLインジェクションに共通する特性です。つまり、クエリの一部を終了し、予期しない別の部分を開始する方法を推測する試みです。 これがすべてのSQLインジェクションの署名です。 そして、それは彼らと戦う方法です。

ステップ2-入力を見つける

コード内で、SQLインジェクション攻撃の可能性のあるすべてのエントリポイントを追跡するのに最適な場所は、HTMLフォームを探すことによってではなくです。 もちろん、その方法で大量のデータを取得することもできますが、URLや、AJAXインターフェイスの1つを介して、ユーザーがデータを入力する方法は他にもあります。

いいえ、調べるのに最適な場所は、脆弱性のポイント、つまりSQLクエリ自体です。 おそらく、すべてのクエリは同じ基本コマンドを使用して実行されます。あるいは、2つまたは3つの異なる可能なコマンドを使用して実行されます。 コードベースでそれらを検索するだけで、脆弱性のすべてのポイントを非常にすばやく見つけることができます。 たとえば、コードでPerlを使用している場合、すべてのクエリは次のような形式になる可能性があります。

$result = mysql_query($sql)

その場合、次のようなコマンドを使用して、コマンドラインからすべての脆弱性のポイントをすばやく見つけることができます。

$ grep -R mysql_query *

ステップ3-入力をサニタイズする

SQLインジェクション攻撃を防ぐために人々が使用するさまざまな手法がありますが、最前線の防御は、すべてのユーザー入力をサニタイズすることです。 ユーザーが希望する形式でデータを送信すると想定してはなりません。 実際、あなたは正反対のことを想定する必要があります-彼らはあなたのコードをバラバラにするためにちょうどいい文字列を提出したいと思っています。

入力をサニタイズするということは、ユーザーが送信したすべての文字列がテストされ、攻撃で使用されることのない安全な文字のみが含まれていることを確認することを意味します。

ユーザーが送信した文字列は、SQLサーバーによって次の2つの方法のいずれかで使用されます。

1. 数として、2097年のように

2. ユーザー名、パスワード、メールアドレスなどの文字列として

コードは常に、これら2つの形式のデータのいずれかを想定しています。 このチュートリアルの上部にある例では、最初の例では文字列が必要であり、2番目の例では数値が必要でした。 それは常にどちらか一方になります。

データをサニタイズする方法には、良い方法と悪い方法の2つもあります。 悪い方法は、注射の可能性をチェックすることです。 悪い理由は、可能な注入の数が非常に多く、攻撃者の創造性が非常に高いためです。 データをサニタイズする良い方法は、適切な入力がどのように見えるかを識別し、それらの制約に準拠していないものをすべて除外することです。

数値データは最も簡単にサニタイズできるので、最初にそれについて説明します。 数値の左側にはオプションのマイナス記号があり、その後にいくつかの数字が続き、場合によっては小数点が続きます。 他には何もありません。 Perlでは、次のように数値のユーザー入力をテストできます。

if($numericaluserinput !~ /^-?[0-9.]+$/) {
    # the user input is not a number
}

その障壁をこっそり通り抜ける敵対的な注射を想像するのは難しいです。

テキスト入力のサニタイズは、それを試みる方法が非常に多いため、より困難です。 攻撃者は、引用符と円記号を創造的な方法で使用する可能性があります。 実際、ユーザー入力で特定の文字をブラックリストに登録しようとすることは、重要なことを見逃しやすいため、嫌われています。

数値入力で行ったように、より良いアプローチは、ユーザー入力をホワイトリストに登録された文字のセットに制限することです。 たとえば、電子メールアドレスは、文字、数字、ダッシュ、アンダースコア、プラス記号、小数、および@記号に制限される場合があります。 Perlでは、次のように電子メールアドレスの入力をテストできます。

if($useremail ~= /^[0-9a-zA-Z\-_+.\@]$/) {
    # the user's email address is unacceptable
}

同様のホワイトリストは、ユーザー名、自宅の住所など、他の種類のユーザー入力についても見つけることができます。

ユーザーはホワイトリストに反対する可能性があります。 電子メールアドレスの仕様には、上記のテストに含まれていないさまざまな記号が含まれています。 もちろん、テストに追加のシンボルを自由に含めることができますが、そうする前に、SQLインジェクションで使用されていないことを確認するために、それぞれを調査する必要があります。 ユーザーの快適性とサイトのセキュリティのどちらかを選択する場合、サイトのセキュリティを常に最優先する必要があります。

ホワイトリストに登録された文字セットを使用して入力をサニタイズするのは簡単なので良いです。 ユーザーが送信できるデータの種類にいくつかの簡単な制約を課す場合、およびSQLクエリを定期的にチェックして、サニタイズされた入力のみを使用していることを確認する場合は、SQLインジェクションのリスクを実質的に排除できます。 。

ステップ4-危険な入力を受け入れる

何? しかし、リスクの高い入力を受け入れないことの重要性について話し合ったところです。

アプリケーションがユーザーにそのレベルの制限を課すことを許容できる場合は、非常に制限の厳しいホワイトリストが最適な方法であることは事実です。 ただし、場合によっては、ビジネスモデルがユーザー入力にいかなる種類の制約も課さないことが重要になることがあります。

この場合、アプリケーションで使用されるプログラミング言語には、敵対的なユーザー入力からコードを保護するためのライブラリが含まれている可能性があります。 たとえば、Perl DBIライブラリには、ユーザー入力が目的のクエリの特定の部分から抜け出さないようにするメソッドがあります。

my $sql = "INSERT INTO user (username, email) VALUES (?, ?)";
my $handle = $dbh->prepare( $sql );
$handle->execute( $untrustedusername, $untrustedemail);

上記の例では、「?」 文字はプレースホルダーとして使用されます。 Perl DBIライブラリは、それらをユーザーから収集された信頼できない変数に置き換えます。 ただし、そうすることで、DBIライブラリーは、これらの変数を、それらを予期するフィールドのみに関連するように明示的に制限します。

他の言語にも同様のライブラリがあり、ユーザーデータの使用を制限したり、データをエスケープしたりします。

この手法の利点は、ライブラリコードを管理している人々に信頼を置き、彼らがそれを維持し、バグやセキュリティホールから解放されることです。 この手法の欠点は、少し読みにくくなることです。そのため、SQLクエリの一部が、適切なライブラリ呼び出しを使用して自分自身を保護することを忘れる可能性が高くなります。

ステップ5-通過する攻撃を軽減する

ビジネスモデルによっては、最終的な防御線を実装することをお勧めします。これは、アプリケーション開発者から完全に独立したものです。 結局のところ、そのうちの1つがどこかで間違ったホワイトリストを使用したか、ユーザーデータを分離するための適切なライブラリ呼び出しを呼び出せなかった可能性があります。 サイト全体をSQLインジェクションに対して脆弱にするために必要なのは、コードの1つの穴だけです。

まず、攻撃者がインジェクション防御を破った場合、攻撃者はそのVPSに対する完全なルート権限を取得したと想定する必要があります。 あなたがそれのすべての世話と給餌をしているとしても、彼らは機械を所有しています。

それによるフォールアウトを軽減するには、VPS自体をネットワークの分離された部分内に構成して、そのシステムのrootユーザーがインフラストラクチャ内の他のシステムを表示したりアクセスしたりできないようにする必要があります。 この種の防御はDMZと呼ばれ、非常に優れており、このチュートリアルの範囲を超えています。

すでに侵入している敵対的なユーザーからクラウドサーバーを保護するために使用するメカニズムが何であれ、特定のアクティビティがVPSに記録されている場合にシステム管理者に通知されるように、何らかのアラートシステムを設定する必要があります。 これらのインジケーターは、アプリケーションコードが侵入されたこと、およびバグを見つけるためにコードベース全体を即座に確認する必要があることを示します。 これらのアラートがなければ、攻撃者はDMZに侵入するのに時間を費やす可能性があり、「アクセスできない」部分で、完全に異なるサーバーに分離されていると思われるすべてのクレジットカード番号を放棄するまで、何かが間違っているという手がかりが得られない可能性があります。ネットワークの。

ステップ6-セキュリティ専門家を雇う

セキュリティの専門家の助けを借りずにWebアプリケーションを実装している場合は、非常に危険な海域で泳ぐことになります。 何らかの理由でセキュリティの専門家を雇う準備がまだできていない場合は、ユーザー入力で許可されている文字をホワイトリストに登録するための非常に厳格なアプローチを検討する必要があります。 ホワイトリストの実装とレビューは比較的簡単であり、十分に厳格なシステムはかなり侵入できないはずです。 あなたがあなたのビジネスを構築し、あなたが必要とする雇用をする準備をしている間、あなたのユーザーに制約されたキャラクターセットのわずかな不便を経験させてください。 セキュリティの問題を理解している人がいれば、SQLインジェクション、クロスサイトスクリプティング攻撃、および最新のWebを悩ませている他の多くの危険なセキュリティ問題から保護する準備が整います。