データ アクセスのセキュリティ保護
更新 : 2007 年 11 月
ASP.NET Web アプリケーションのほとんどは、データ アクセスを必要とします。多くのアプリケーションはデータベースやファイルに格納されているデータを収集しますが、格納されているデータの多くは、ユーザーから取得した情報を基にしています。元のデータが信頼できないソースから取得される可能性がある、情報は永続的な形式で格納される、さらに、承認されていないユーザーがデータ ソースに直接アクセスできないようにする必要がある、などの理由から、データ アクセスに関するセキュリティ上の問題には十分注意する必要があります。このトピックでは、ASP.NET Web アプリケーションにおける、データ アクセスのセキュリティを向上するために推奨される手順について説明します。
コーディングと構成の推奨される手順を使用すると、アプリケーションのセキュリティを向上できますが、Microsoft Windows やインターネット インフォメーション サービス (IIS: Internet Information Services) の最新のセキュリティ更新プログラムと共に Microsoft SQL Server やその他のデータ ソース ソフトウェアのセキュリティ更新プログラムを使用して、Web サーバーを常に最新の状態に維持することも大切です。
安全なコードの記述およびアプリケーションのセキュリティ保護に関する推奨される手順の詳細については、『Writing Secure Code』(Michael Howard および David LeBlanc の共著)、または Microsoft Patterns and Practices Web サイトで提供されているガイダンスを参照してください。
データ ソースへのアクセスのセキュリティ保護
以下のセクションで、データ アクセスに対するさまざまなセキュリティ保護について説明します。
接続文字列
データベースに接続するには、接続文字列が必要です。接続文字列には重要情報が含まれることがあるので、次のガイダンスに従う必要があります。
接続文字列をページに格納しないでください。たとえば、SqlDataSource コントロールやその他のデータ ソース コントロールの宣言プロパティとして接続文字列を設定しないでください。代わりに、接続文字列はサイトの Web.config ファイルに格納してください。例については、「方法 : データ ソース コントロールを使用するときに接続文字列をセキュリティ保護する」を参照してください。
接続文字列をプレーンテキストとして格納しないでください。データベース サーバーへの接続の安全を確保するには、保護された構成を使用して構成ファイルで接続文字列情報を暗号化することをお勧めします。詳細については、「保護された構成を使用した構成情報の暗号化」を参照してください。
統合セキュリティを使用した SQL Server への接続
可能な場合には、明示的なユーザー名とパスワードを使用する代わりに統合セキュリティを使用して、SQL Server のインスタンスに接続します。これにより、接続文字列の安全性が損なわれたり、ユーザー ID とパスワードが公開されたりする可能性を回避できます。
ASP.NET を実行するプロセス (アプリケーション プールなど) の ID は、必ず、既定のプロセス アカウントまたは制限されたユーザー アカウントにすることをお勧めします。詳細については、「ASP.NET の偽装」を参照してください。
各 Web サイトがそれぞれ異なる SQL Server データベースに接続する場合、統合セキュリティは実用に適さないことがあります。たとえば、Web ホスト サイトでは、通常、顧客ごとに異なる SQL Server データベースが割り当てられますが、すべてのユーザーが匿名のユーザーとして Web サーバーを使用します。このような場合は、明示的な資格情報を使用して、SQL Server のインスタンスに接続する必要があります。資格情報は、「接続文字列」の説明に従って安全な方法で格納してください。
SQL Server データベースへのアクセス許可
アプリケーションで使用する SQL Server データベースに接続するためのユーザー ID には、最小限の特権を割り当てることをお勧めします。
SQL 操作の制限
データ バインド コントロールでは、データ テーブル内のレコードの選択、挿入、削除、更新など、さまざまなデータ操作をサポートできます。しかし、データ コントロールは、ページやアプリケーションで必要な最小限の機能を実行するように設定することをお勧めします。たとえば、コントロールによって削除を実行できないようにする場合は、データ ソース コントロールに削除クエリを含めないように、またコントロールで削除を有効にしないようにします。
SQL Server Express Edition
プロセスが SQL Server Express Edition データベース (.mdf ファイル) に接続する場合、そのプロセスには管理者特権が必要になります。このため、一般に SQL Server Express Edition データベースは実際に運用する Web サイトでは実行できません。ASP.NET プロセスは管理者特権を使用して実行されないだけでなく、実行してはならないからです。そのため、SQL Server Express Edition データベースは、次の場合にのみ使用します。
Web アプリケーションの開発中にテスト データベースとして使用します。アプリケーションを配置する準備が整った時点で、SQL Server Express Edition から実際の運用に使用する SQL Server にデータベースを移します。
偽装を使用できる Web サイトを実行し、偽装されたユーザーのアクセス許可を制御できる場合に使用します。実質的にこの方法は、アプリケーションが公開 Web サイトでなく、ローカル エリア ネットワークで実行される場合にしか実用的でありません。
.mdf ファイルをサイトの App_Data フォルダに格納します。このフォルダの内容は、HTTP 要求に対して直接返されないためです。また、サイトの Web.config ファイル内の次の要素を使用して、.mdf 拡張子を IIS 上の ASP.NET に、および ASP.NET 上の HttpForbiddenHandler ハンドラに割り当てる必要があります。
<httpHandlers> <add verb="*" path="*.mdf" type="System.Web.HttpForbiddenHandler" /> </httpHandlers>
ファイル名の拡張子を IIS 上の ASP.NET に割り当てる方法については、「方法 : HTTP ハンドラを登録する」を参照してください。
Microsoft Access データベース
Microsoft Access データベース (.mdb ファイル) には、SQL Server データベースほどのセキュリティ機能は用意されていません。したがって、Access データベースは、実際の運用で使用する Web サイトには推奨されません。ただし、.mdb ファイルを Web アプリケーションの一部として使用する場合は、次のガイドラインに従ってください。
.mdb ファイルをサイトの App_Data フォルダに格納します。このフォルダの内容は、HTTP 要求に対して直接返されないためです。また、サイトの Web.config ファイル内の次の要素を使用して、.mdb 拡張子を IIS 上の ASP.NET に、および ASP.NET 上の HttpForbiddenHandler ハンドラに割り当てる必要があります。
<httpHandlers> <add verb="*" path="*.mdb" type="System.Web.HttpForbiddenHandler" /> </httpHandlers>
ファイル名の拡張子を IIS 上の ASP.NET に割り当てる方法については、「方法 : HTTP ハンドラを登録する」を参照してください。
.mdb ファイルの読み取りまたは書き込みを行うユーザー アカウントに適切なアクセス許可を追加します。Web サイトが匿名アクセスをサポートする場合、このアカウントは一般にローカルの ASPNET ユーザー アカウントか、NETWORK SERVICE アカウントになります。Access では、ロックをサポートするために .ldb ファイルを作成する必要があるので、ユーザーには、.mdb ファイルを格納しているフォルダの書き込みアクセス許可が必要です。
データベースがパスワードによって保護されている場合は、データベースへの接続の確立に AccessDataSource コントロールを使用しないでください。これは、AccessDataSource コントロールでは、資格情報の受け渡しがサポートされていないためです。代わりに、SqlDataSource コントロールと ODBC プロバイダを使用して、接続文字列に含まれる資格情報を渡します。接続文字列は、このトピックの「接続文字列」の説明に従ってセキュリティで保護する必要があります。
XML ファイル
データを XML ファイルに格納する場合は、XML ファイルを Web サイトの App_Data フォルダに配置します。このフォルダの内容は、HTTP 要求に対して直接返されないためです。
悪意のあるユーザー入力に対する防御
アプリケーションがユーザーの入力を受け入れる場合は、アプリケーションを破壊する可能性がある悪質な内容が入力に含まれていないことを確認する必要があります。悪意のあるユーザー入力によって、次のような攻撃が開始される可能性があります。
スクリプトの注入 スクリプト注入攻撃は、実行可能なスクリプトを別のユーザーに実行させることを目的に、そのスクリプトをアプリケーションに送信しようとする攻撃です。一般的なスクリプト注入攻撃では、スクリプトをデータベースに格納するページにスクリプトを送信し、データを表示する別のユーザーが気付かずにコードを実行するようにします。
SQL の注入 SQL 注入攻撃は、アプリケーションに組み込まれたコマンドの代わりに実行される SQL コマンド、またはそのようなコマンドと合わせて実行される SQL コマンドを作成して、データベースを破壊し、さらにデータベースを実行するコンピュータを破壊しようとする攻撃です。
一般的なガイドライン
すべてのユーザー入力に対し、以下のガイドラインに従って対処します。
できるだけ検証コントロールを使用して、ユーザー入力を受け入れ可能な値に制限します。
サーバー コードを実行する前に、IsValid プロパティの値が true であることを必ず確認します。値が false の場合、1 つ以上の検証コントロールが検証チェックに失敗していることを意味します。
クライアント側の検証を回避したユーザーからデータを保護するため、ブラウザでクライアント側の検証が行われている場合でも、必ずサーバー側の検証を実行します。特に CustomValidator コントロールの場合は、クライアント側検証ロジックだけでなく、必ず冗長サーバー検証を使用してください。
アプリケーションのビジネス レイヤでユーザー入力を必ず再検証します。安全なデータを提供する呼び出しプロセスに依存しないでください。たとえば、ObjectDataSource コントロールを使用する場合は、データの更新を実行するオブジェクトに冗長の検証とエンコーディングを追加します。
スクリプト注入
スクリプト注入攻撃を回避するには、以下のガイドラインに従います。
HtmlEncode メソッドを使用してユーザー入力をエンコードします。このメソッドは、HTML をテキスト表現に転換し (たとえば、<b> は <b> になります)、マークアップがブラウザで実行されないようにします。
パラメータ オブジェクトを使用してユーザー入力をクエリに渡すときは、データ ソース コントロールのクエリ前のイベント用のハンドラを追加し、クエリ前イベントでエンコーディングを実行します。たとえば、SqlDataSource コントロールの Inserting イベントを処理する場合は、クエリを実行する前にそのイベントでパラメータ値をエンコーディングします。
GridView コントロールをバインド フィールドで使用する場合は、BoundField オブジェクトの HtmlEncode プロパティに true を設定します。これにより、GridView コントロールは、行が編集モードのときにユーザー入力をエンコーディングします。
編集モードに設定できるコントロールでは、テンプレートを使用することをお勧めします。たとえば、GridView、DetailsView、FormView、DataList、Login の各コントロールは、編集可能なテキスト ボックスを表示できます。ただし、GridView コントロール (上の項目を参照) 以外の各コントロールは、ユーザー入力の検証と HTML エンコーディングを自動的に実行しません。このため、これらのコントロールにはテンプレートを作成し、作成したテンプレートに TextBox などの入力コントロールと検証コントロールを追加することをお勧めします。さらに、コントロールの値を抽出するときは、値をエンコードする必要があります。
SQL 注入
SQL 注入攻撃を回避するには、以下のガイドラインに従います。
文字列を連結して SQL コマンドを作成しないでください。特にユーザー入力を含む文字列は絶対に避けてください。代わりに、パラメータ化されたクエリやストアド プロシージャを使用してください。
パラメータ化されたクエリを作成する場合は、パラメータ オブジェクトを使用してパラメータの値を設定します。詳細については、「SqlDataSource コントロールにおけるパラメータの使用」および「データ ソース コントロールとパラメータの使用」を参照してください。
ビューステート データの暗号化
GridView コントロールなどのデータ バインド コントロールでは、機密情報と見なされる情報を保持しなければならないことがあります。たとえば、GridView コントロールは、DataKeys プロパティのキーの一覧を、この情報が表示されていない場合でも保持できます。このコントロールは、ラウンド トリップ間で情報をビュー ステートに格納します。
ビューステート情報はエンコードされ、ページの内容と共に格納されます。これらの情報は、デコードされ、必要のないソースにまで公開される可能性があります。ビューステートに機密情報を格納する必要がある場合は、ページがビューステート データを暗号化するように設定できます。ビューステート データを暗号化するには、ページの ViewStateEncryptionMode プロパティに true を設定します。
キャッシュ
クライアントの偽装が有効で、データ ソースからの結果がクライアント ID に基づいて取得される場合は、Cache オブジェクトに機密情報を格納しないことをお勧めします。キャッシュを有効にすると、特定のユーザーのキャッシュされたデータをすべてのユーザーが参照できるようになるため、機密情報が不適切なソースに公開される可能性があります。クライアントの偽装は、identity 構成要素の impersonate 属性が true に設定され、アプリケーションの匿名 ID が Web サーバーで無効になっている場合に有効になります。