フッターコンテンツにスキップ
Iron Academy Logo
C#データベース統合

C#でSQLインジェクションを防ぐには?

Tim Corey
34分33秒

SQLインジェクションとは、コードインジェクションの手法の一つで、攻撃者がユーザー入力を通じて悪意のあるSQLコードをデータベースサーバーに送信することを可能にするものです。 ティム・コーリーのビデオ"What Is SQL Injection And How Do I Prevent It in C#?"では、SQLインジェクションの脆弱性が実際のコードにどのように現れるかを正確に示し、SQLインジェクション攻撃の成功例(ユニオンベースや破壊的攻撃を含む)をいくつか紹介し、C#で適用できる実践的なSQLインジェクション防止テクニックを解説しています。 この記事は、Timのウォークスルーに従っているので、彼が示す正確な問題と修正を見ることができます。

デモ アプリとその理由

Tim は、ローカルの InjectableDB (People テーブルと Secrets テーブル) に関連付けられた小さな WPF デモ アプリから始めます。 このアプリのウェブフォームのような検索ボックスは、ユーザー入力(姓)を受け取り、ID、姓、名を返すSQLクエリを構築します。 Corey と入力すると Tim Corey が表示されます。動作するウェブ・アプリケーションは、文字列の連結や動的 SQL を介して、ユーザが提供した入力が直接 SQL 文に挿入された場合、SQL インジェクションの脆弱性を持つ可能性があります。

安全でないコード - 文字列の連結と動的 SQL

ティムは、多くの開発者が使用する安全でないパターンを正確に示しています:

var sql = $"SELECT * FROM People WHERE LastName = '{searchText}'";
var results = connection.Query<Person>(sql);
var sql = $"SELECT * FROM People WHERE LastName = '{searchText}'";
var results = connection.Query<Person>(sql);

このオリジナルのクエリは、文字列の連結を使用してSQL文を作成します。 Timは警告します:SQLクエリに直接ユーザー入力を注入するコードを見かけたら、やめてください - これはSQLインジェクションの脆弱性です。 攻撃者は、SQLコマンドの構造を変更したり、悪意のあるSQLステートメントを追加実行したりする悪意のある入力を作成することができます。

攻撃者はどのように悪用するか - UNION と DROP

SQLインジェクション攻撃がどのように機能するかを示すために、ティムはSQL Serverでクエリを再現し、UNION ALLと末尾の文字を隠すためのSQLコメント(--)を使用してインジェクションを作成します。 ティムが示す悪意のあるペイロードの例

  • 他のテーブルを読み込むためのユニオンベースのSQLインジェクション:

    UNION ALL SELECT ID, Username AS FirstName, Password AS LastName FROM Secrets;

    これは、Secretsの結果を元のSELECTの結果セットに混ぜてしまい、ユーザー名やパスワードのような機密データを公開してしまいます。

  • テーブルを削除する破壊的インジェクション:

    DROP TABLE DemoTable;

    これは、最初のステートメントをセミコロンで終了し、破壊コマンドを追加することによって、2番目のSQLステートメント(DROP TABLE)を実行します。 悪意のあるSQLによってデータベースが変更されました。

攻撃者は、前もってテーブル名やカラム名を知っている必要はありません。データベースサーバーからテーブル名やカラム名を列挙したり、ブラインドテクニックやタイミングベースのテクニックを試して動作を発見したりするだけです。

修正 1 - パラメータ化されたクエリ

ティムの第一の防御策は、ユーザーデータでSQL文字列を構築するのをやめることです。 動的SQLをパラメータ化されたクエリに置き換える:

string sql = "SELECT * FROM People WHERE LastName = @LastName";
var results = connection.Query<Person>(sql, new { LastName = searchText });
string sql = "SELECT * FROM People WHERE LastName = @LastName";
var results = connection.Query<Person>(sql, new { LastName = searchText });

ティムは、パラメータ化(プリペアド・ステートメント・スタイルの使用法)とは、データベースがユーザーから提供された入力を厳密にデータとして扱うことを意味し、悪意のあるSQLは単なる文字列値となり、SQL構造を変更することはできないと説明する。 これは、ユニオンベースのペイロードや付加された.NET Frameworkを含む、多くの一般的なSQLインジェクション攻撃を防ぎます; DROP TABLEコマンド。

彼はまた、パラメータ化と最小限の入力検証を組み合わせることを推奨している。アポストロフィのような正当な文字を許可する一方で、姓にありそうもない文字(セミコロンや--コメントマーカーなど)をサニタイズまたはブロックするのだ(O'Reilly)。 パラメータ化されたクエリ+入力クレンジングは、SQLインジェクション攻撃に対する実質的な防御となります。

修正 2 - ストアドプロシージャ

Timは次に、2つのストアドプロシージャを示します。SQLをプロシージャ内で連結して実行する安全でないストアドプロシージャと、パラメータを直接使用する安全なストアドプロシージャです。

  • 安全でないストアドプロシージャは、パラメータから@sql文字列を構築し、それを実行します。

  • 安全なストアドプロシージャは、SELECT ... WHERE LastName = @LastName で、パラメータ - safe で実行します。

ストアドプロシージャは、その中に動的SQLを構築している場合、自動的には治りません。 しかし、ストアドプロシージャを適切に使用すれば(動的SQLを使用しない)、SQL文を一元化し、クエリのパラメータ化や監査を容易にすることができます。 ストアドプロシージャは、アプリのSQLインジェクション対策を簡素化するのにも役立ちます。

どんなデータも信用してはいけません - データベースのデータでさえも

ティムは、しばしば見落とされがちな重要なポイントとして、自分のSQLデータベースから取得したデータを盲目的に信用してはいけないと指摘する。 攻撃者は、悪意のあるペイロードをカラムに仕込むことがあります("時限爆弾")。 ティムは次のように主張しています:悪意のある入力が後でインジェクションの経路にならないように、ウェブフォーム、ファイルアップロード、または独自のデータベースからのデータであろうと、常にパラメータを使用し、すべてのステップでデータをサニタイズすること。

ボーナスヒント - 最小特権とデータベース特権の制限

コードの修正だけでなく、Tim は防御的な設定を推奨しています。 彼のデモでは、統合されたセキュリティを経由して管理者アカウントを使用しています。 その代わり、最小権限の原則を使用してください:

  • アプリに必要な権限だけを持つデータベースアカウントを作成します。

  • ストアドプロシージャを使用する場合は、そのアカウントに、特定のストアドプロシージャに対する EXECUTE 権限のみを与え、それ以外の権限を与えないでください。

  • アプリケーションアカウントには、DROP TABLE、すべてのテーブルの一覧表示、他のデータベースの読み取りを許可する広範な管理者権限を与えないでください。

これにより、SQLインジェクション攻撃が成功した場合の影響を軽減します。たとえインジェクションが可能であっても、攻撃者はアカウントが許可している以上のことはできません。

ティムはまた、Entity Frameworkがこれを複雑にしていると指摘する:EFは、しばしば昇格した権限(移行、スキーマの変更)を必要とします。 本番環境でEFを使用する場合は、その許可とデプロイを慎重に計画してください。

リキャップ - 停止、パラメータ化、サニタイズ、制限

ティムは、ビデオの最後に、C# アプリケーションでの SQL インジェクションを防ぐための明確なチェックリストを紹介しています:

1.文字列を連結したSQL文や、ユーザー入力を含む動的SQLを構築するのはやめてください。

2.ユーザーデータが常にデータとして扱われるように、パラメータ化されたクエリ/プリペアドステートメントパターンを使用してください。

3.適切な場合、入力をサニタイズします(ブロックセミコロン、SQLコメント、予期しない文字)。

4.クエリロジックを一元化するために、安全なストアドプロシージャ(内部に動的SQLを含まない)を優先してください。

5.データベースアカウントに最小権限を適用する - アプリのデータベースユーザーができることを制限します。

6.コード(特にSQLを動的にビルドする場所)をレビューし、SQLインジェクションの欠陥がないかテストします。

Timの最後の警告:ユーザー入力のずさんな取り扱い、動的SQL、過剰なデータベース権限は、漏洩した機密データ、破壊されたテーブル、長期間にわたって検出されなかった流出など、深刻な侵害につながる可能性があります。 SQLインジェクション対策は、セキュリティの中核的な要件であり、オプションではありません。

Hero Worlddot related to C#でSQLインジェクションを防ぐには?
Hero Affiliate related to C#でSQLインジェクションを防ぐには?

好きなことを共有することで収入を増やす

.NET、C#、Java、Python、またはNode.jsを使用する開発者向けのコンテンツを作成しますか?あなたの専門知識を副収入に変えましょう!

アイアンサポートチーム

私たちは週5日、24時間オンラインで対応しています。
チャット
メール
電話してね