1. SQL インジェクション攻撃とは何ですか?
いわゆる SQL インジェクション攻撃とは、攻撃者が Web フォームの入力フィールドまたはページ リクエストのクエリ文字列に SQL コマンドを挿入し、サーバーをだまして悪意のある SQL コマンドを実行させることを意味します。一部のフォームでは、ユーザー入力が動的 SQL コマンドを構築する (または影響を与える) ために直接使用されたり、ストアド プロシージャの入力パラメーターとして使用されたりする場合、そのようなフォームは SQL インジェクション攻撃に対して特に脆弱です。一般的な SQL インジェクション攻撃プロセスは次のとおりです
。 ⑴ ASP.NET Web アプリケーションにはログイン ページがあり、ユーザーがアプリケーションにアクセスする権利があるかどうかを制御します。ユーザーは名前とパスワードを入力する必要があります。
⑵ ログイン ページに入力された内容は、動的 SQL コマンドの構築に直接使用されるか、ストアド プロシージャのパラメータとして直接使用されます。次に、クエリを構築する ASP.NET アプリケーションの例を示します。
System.Text.StringBuilder query = new System.Text.StringBuilder(
"SELECT * from ユーザー WHERE ログイン = '")
.Append(txtLogin.Text).Append("' AND パスワード='")
.Append(txtPassword.Text).Append("");
⑶ 攻撃者は、ユーザー名とパスワードの入力ボックスに「' または '1'='1」などを入力します。
⑷ ユーザーが入力したコンテンツがサーバーに送信された後、サーバーは上記の ASP.NET コードを実行してユーザーにクエリを実行する SQL コマンドを作成します。ただし、攻撃者が入力したコンテンツは非常に特殊であるため、最終的な SQL コマンドが作成されます。 SELECT * from Users WHERE ログイン = '' または '1'='1' AND パスワード = '' または '1'='1' となります。
⑸ サーバーはクエリまたはストアド プロセスを実行して、ユーザーが入力した ID 情報とサーバーに保存されている ID 情報を比較します。
⑹ SQL コマンドは実際にはインジェクション攻撃によって変更されており、ユーザーの ID を真に認証できないため、システムは攻撃者を誤って承認します。
攻撃者は、アプリケーションがフォームに入力されたコンテンツを本人確認クエリに直接使用することを知っている場合、特別な SQL 文字列を入力してクエリを改ざんし、元の機能を変更し、システムをだましてアクセス許可を付与しようとします。
システム環境に応じて、攻撃者が引き起こす可能性のある被害も異なります。これは主に、データベースにアクセスするためのアプリケーションのセキュリティ権限によって決まります。ユーザーのアカウントに管理者またはその他の比較的高度な権限がある場合、攻撃者は、データの追加、削除、更新、さらにはテーブルの直接削除など、データベース テーブルに対してさまざまな操作を実行する可能性があります。
2. どうやって防ぐのか?
幸いなことに、SQL インジェクション攻撃による ASP.NET アプリケーションの侵入を防ぐことは特に難しいことではありません。フォーム入力コンテンツを使用して SQL コマンドを作成する前に、すべての入力コンテンツをフィルターするだけです。入力のフィルタリングはさまざまな方法で実行できます。
⑴ SQL クエリが動的に構築される状況では、次の手法を使用できます。
まず、単一引用符を置き換えます。つまり、攻撃者が SQL コマンドの意味を変更できないように、すべての単一単一引用符を 2 つの単一引用符に変更します。前の例をもう一度見てみると、「SELECT * from Users WHERE login = ''' or ''1''=''1' AND passwd = ''' or ''1''=''1'」は明らかに取得されます。同じ「SELECT * from Users WHERE login = '' または '1'='1' AND パスワード = '' または '1'='1'」でも結果は異なります。
2 番目: ユーザー入力コンテンツ内のすべてのハイフンを削除して、攻撃者が「SELECT * from Users WHERE login = 'mas' -- AND passwd =''」などのクエリを作成できないようにします。そのようなクエリのサフィックスの半分がコメント化されているためです。攻撃者は正当なユーザー ログイン名を知るだけで、アクセスを成功させるためにユーザーのパスワードを知る必要はありません。
3 番目: クエリの実行に使用されるデータベース アカウントの権限を制限します。別のユーザー アカウントを使用して、クエリ、挿入、更新、および削除の操作を実行します。異なるアカウントで実行できる操作を分離することで、元々 SELECT コマンドの実行に使用されていた場所が INSERT、UPDATE、または DELETE コマンドの実行に使用されるのを防ぎます。
⑵ ストアド プロシージャを使用してすべてのクエリを実行します。 SQL パラメータの受け渡し方法により、攻撃者が一重引用符やハイフンを使用して攻撃を実行することを防ぎます。さらに、特定のストアド プロシージャの実行のみを許可するようにデータベースのアクセス許可を制限することもできるため、インジェクション攻撃が発生しにくくなるように、すべてのユーザー入力が呼び出されたストアド プロシージャのセキュリティ コンテキストに準拠する必要があります。
⑶ フォームまたはクエリ文字列の入力長を制限します。ユーザーのログイン名が最大 10 文字しかない場合は、フォームに 10 文字を超える文字を入力しないでください。これにより、攻撃者が SQL コマンドに有害なコードを挿入することが大幅に困難になります。
⑷ ユーザー入力の合法性をチェックし、入力内容に合法的なデータのみが含まれていることを確認します。データ検査はクライアント側とサーバー側の両方で実行する必要があります。サーバー側の検証は、クライアント側の検証メカニズムの脆弱なセキュリティを補うために実行されます。
クライアント側では、攻撃者が Web ページのソース コードを取得し、合法性を検証するスクリプトを変更し (またはスクリプトを直接削除し)、変更されたフォームを通じて違法なコンテンツをサーバーに送信することが完全に可能です。したがって、検証操作が実際に実行されたことを確認する唯一の方法は、サーバー側でも検証を実行することです。検証用のクライアント側スクリプトを自動的に生成できる RegularExpressionValidator など、多くの組み込み検証オブジェクトを使用できます。もちろん、サーバー側のメソッド呼び出しを挿入することもできます。既製の検証オブジェクトが見つからない場合は、CustomValidator を使用して自分で作成できます。
⑸ ユーザーのログイン名、パスワード等のデータを暗号化して保存します。ユーザーが入力したデータを暗号化し、データベースに保存されているデータと比較することは、ユーザーが入力したデータを「殺菌」することと同等であり、ユーザーが入力したデータはデータベースにとって特別な意味を持たなくなります。攻撃者が SQL コマンドを挿入するのを防ぎます。 System.Web.Security.FormsAuthentication クラスには HashPasswordForStoringInConfigFile があり、入力データのサニタイズに非常に適しています。
⑹ データを抽出したクエリで返されたレコード数を確認します。プログラムで返されるレコードが 1 つだけであるにもかかわらず、実際に返されるレコードが複数行である場合、エラーとして扱われます。