接続文字列とその他の構成情報を保護する (C#)

作成者: Scott Mitchell

PDF のダウンロード

ASP.NET アプリケーションは通常、構成情報を Web.config ファイルに保存します。 この情報の一部は機密情報であり、保護する必要があります。 既定では、このファイルは Web サイトの訪問者には提供されませんが、管理者またはハッカーが Web サーバーのファイル システムにアクセスしてファイルの内容を表示する可能性があります。 このチュートリアルでは、ASP.NET 2.0 で Web.config ファイルのセクションを暗号化することによって機密情報を保護する方法について説明します。

はじめに

ASP.NET アプリケーションの構成情報は、通常、 Web.config という名前の XML ファイルに保存されます。 これらのチュートリアルの過程で、Web.config を数回更新しました。 たとえば、最初のチュートリアルで型指定されたデータセット Northwind を作成すると、接続文字列情報が Web.config<connectionStrings> セクションに自動的に追加されました。 その後、マスター ページとサイト ナビゲーションのチュートリアルで、Web.config を手動で更新し、プロジェクト内のすべての ASP.NET ページで DataWebControls テーマを使用する必要があることを示す <pages> 要素を追加しました。

Web.config には接続文字列などの機密データが含まれている可能性があるため、Web.config の内容を安全に保ち、許可されていない閲覧者から隠すことが重要です。 既定では、拡張子 .config が付いたファイルに対するすべての HTTP 要求は ASP.NET エンジンによって処理され、図 1 に示す "この種類のページは提供されません" というメッセージが返されます。 つまり、訪問者はブラウザーのアドレス バーに http://www.YourServer.com/Web.config と入力するだけでは、Web.config ファイルの内容を表示できません。

Web.config にブラウザーからアクセスすると

図 1: ブラウザーから Web.config にアクセスすると、"この種類のページは提供されません" というメッセージが返される (クリックするとフルサイズの画像が表示されます)

しかし、攻撃者が Web.config ファイルの内容を表示できるようにする別の悪用を見つけることができた場合はどうでしょうか。 攻撃者はこの情報を使って何ができるでしょうか。また、Web.config 内の機密情報をさらに保護するためにどのような手順を実行できるでしょうか。 幸いなことに、Web.config のほとんどのセクションには機密情報は含まれていません。 ASP.NET ページで使用される既定のテーマの名前を攻撃者が知っている場合、どのような被害を及ぼす可能性があるでしょうか。

ただし、Web.config の特定のセクションには、接続文字列、ユーザー名、パスワード、サーバー名、暗号化キーなどの機密情報が含まれている場合があります。 この情報は通常、次の Web.config セクションにあります。

  • <appSettings>
  • <connectionStrings>
  • <identity>
  • <sessionState>

このチュートリアルでは、このような機密性の高い構成情報を保護するための手法について説明します。 後述しますが、.NET Framework バージョン 2.0 には、選択した構成セクションをプログラムで簡単に暗号化および暗号化解除できる保護された構成システムが含まれています。

Note

このチュートリアルの最後に、ASP.NET アプリケーションからデータベースに接続するための Microsoft の推奨事項について説明します。 接続文字列の暗号化に加えて、安全な方法でデータベースに接続することで、システムを強化することもできます。

手順 1: ASP.NET 2.0 の保護された構成オプションを探索する

ASP.NET 2.0 には、構成情報を暗号化および暗号化解除するための保護された構成システムが含まれています。 これには、構成情報をプログラムで暗号化または暗号化解除するために使用できる .NET Framework のメソッドが含まれます。 保護された構成システムでは、プロバイダー モデルを使用します。これにより、開発者は、使用する暗号化実装を選択できます。

.NET Framework には、次の 2 つの保護された構成プロバイダーが付属しています。

保護された構成システムはプロバイダー設計パターンを実装しているため、独自の保護された構成プロバイダーを作成し、それをアプリケーションにプラグインできます。 このプロセスの詳細については、「保護された構成プロバイダーの実装」を参照してください。

RSA および DPAPI プロバイダーは暗号化および暗号化解除ルーチンにキーを使用し、これらのキーはマシンレベルまたはユーザーレベルで保存できます。 マシンレベルのキーは、Web アプリケーションが独自の専用サーバー上で実行されるシナリオや、暗号化された情報を共有する必要がある複数のアプリケーションがサーバー上に存在するシナリオに最適です。 ユーザーレベルのキーは、同じサーバー上の他のアプリケーションがアプリケーションの保護された構成セクションを暗号化解除できないようにする必要がある共有ホスティング環境では、より安全なオプションです。

このチュートリアルの例では、DPAPI プロバイダーとマシンレベルのキーを使用します。 具体的には、Web.config<connectionStrings> セクションの暗号化について説明しますが、保護された構成システムを使用して、ほとんどすべての Web.config セクションを暗号化できます。 ユーザーレベル キーの使用または RSA プロバイダーの使用の詳細については、このチュートリアルの最後にある「もっと読む」セクションのリソースを参照してください。

Note

RSAProtectedConfigurationProvider および DPAPIProtectedConfigurationProvider プロバイダーは、それぞれ RsaProtectedConfigurationProvider および DataProtectionConfigurationProvider というプロバイダー名で machine.config ファイルに登録されます。 構成情報を暗号化または暗号化解除する場合、実際の型名 (RSAProtectedConfigurationProvider および DPAPIProtectedConfigurationProvider) ではなく、適切なプロバイダー名 (RsaProtectedConfigurationProvider または DataProtectionConfigurationProvider) を指定する必要があります。 machine.config ファイルは、$WINDOWS$\Microsoft.NET\Framework\version\CONFIG フォルダーにあります。

手順 2: プログラムにより構成セクションを暗号化および暗号化解除する

数行のコードで、指定されたプロバイダーを使用して特定の構成セクションを暗号化または暗号化解除できます。 後述しますが、コードでは、適切な構成セクションをプログラムで参照し、その ProtectSection または UnprotectSection メソッドを呼び出してから、Save メソッドを呼び出して変更内容を保存するだけです。 さらに、.NET Framework には、構成情報を暗号化および暗号化解除できる便利なコマンド ライン ユーティリティが含まれています。 手順 3 で、このコマンド ライン ユーティリティについて説明します。

構成情報をプログラムで保護する方法を説明するために、Web.config<connectionStrings> セクションを暗号化および暗号化解除するためのボタンを含む ASP.NET ページを作成します。

まず、AdvancedDAL フォルダーの EncryptingConfigSections.aspx ページを開きます。 ツールボックスから TextBox コントロールをデザイナーにドラッグし、ID プロパティを WebConfigContents に、TextMode プロパティを MultiLine に、Width および Rows プロパティをそれぞれ 95% と 15 に設定します。 この TextBox コントロールには、Web.config の内容が暗号化されているかどうかをすぐに確認できるように内容が表示されます。 もちろん、実際のアプリケーションでは、Web.config の内容を表示する必要はありません。

テキスト ボックスの下に、EncryptConnStringsDecryptConnStrings という名前の 2 つの Button コントロールを追加します。 Text プロパティを "接続文字列の暗号化" および "接続文字列の暗号化解除" に設定します。

この時点で、画面は図 2 のようになります。

EncryptingConfigSections.aspx ページが開いている Visual Studio を示すスクリーンショット。新しい TextBox コントロール 1 つと Button コントロール 2 つがあります。

図 2: ページに TextBox および 2 つの Button Web コントロールを追加する (クリックするとフルサイズの画像が表示されます)

次に、ページが最初に読み込まれたときに Web.config の内容を読み込んで WebConfigContents テキスト ボックスに表示するコードを記述する必要があります。 ページの分離コード クラスに次のコードを追加します。 このコードは、DisplayWebConfig という名前のメソッドを追加し、Page.IsPostBackfalse の場合に Page_Load イベント ハンドラーからそれを呼び出します。

protected void Page_Load(object sender, EventArgs e)
{
    // On the first page visit, call DisplayWebConfig method
    if (!Page.IsPostBack)
        DisplayWebConfig();
}
private void DisplayWebConfig()
{
    // Reads in the contents of Web.config and displays them in the TextBox
    StreamReader webConfigStream = 
        File.OpenText(Path.Combine(Request.PhysicalApplicationPath, "Web.config"));
    string configContents = webConfigStream.ReadToEnd();
    webConfigStream.Close();
    WebConfigContents.Text = configContents;
}

DisplayWebConfig メソッドは、File クラスを使用してアプリケーションの Web.config ファイルを開き、StreamReader クラスを使用してその内容を文字列に読み取り、Path クラスを使用して Web.config ファイルへの物理パスを生成します。 これら 3 つのクラスはすべて System.IO 名前空間にあります。 したがって、分離コード クラスの先頭に using System.IO ステートメントを追加するか、またはこれらのクラス名の前に System.IO. を付ける必要があります。

次に、2 つの Button コントロールの Click イベントのイベント ハンドラーを追加し、DPAPI プロバイダーでマシンレベルのキーを使用して <connectionStrings> セクションを暗号化および暗号化解除するために必要なコードを追加する必要があります。 デザイナーから、各ボタンをダブルクリックして、分離コード クラスに Click イベント ハンドラーを追加し、次のコードを追加します。

protected void EncryptConnStrings_Click(object sender, EventArgs e)
{
    // Get configuration information about Web.config
    Configuration config = 
        WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
    // Let's work with the <connectionStrings> section
    ConfigurationSection connectionStrings = config.GetSection("connectionStrings");
    if (connectionStrings != null)
        // Only encrypt the section if it is not already protected
        if (!connectionStrings.SectionInformation.IsProtected)
        {
            // Encrypt the <connectionStrings> section using the 
            // DataProtectionConfigurationProvider provider
            connectionStrings.SectionInformation.ProtectSection(
                "DataProtectionConfigurationProvider");
            config.Save();
            
            // Refresh the Web.config display
            DisplayWebConfig();
        }
}
protected void DecryptConnStrings_Click(object sender, EventArgs e)
{
    // Get configuration information about Web.config
    Configuration config = 
        WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
    // Let's work with the <connectionStrings> section
    ConfigurationSection connectionStrings = 
        config.GetSection("connectionStrings");
    if (connectionStrings != null)
        // Only decrypt the section if it is protected
        if (connectionStrings.SectionInformation.IsProtected)
        {
            // Decrypt the <connectionStrings> section
            connectionStrings.SectionInformation.UnprotectSection();
            config.Save();
            // Refresh the Web.config display
            DisplayWebConfig();
        }
}

2 つのイベント ハンドラーで使用されるコードはほぼ同じです。 どちらも、WebConfigurationManager クラスOpenWebConfiguration メソッドを介して、現在のアプリケーションの Web.config ファイルに関する情報を取得することから始まります。 このメソッドは、指定された仮想パスの Web 構成ファイルを返します。 次に、Configuration クラスGetSection(sectionName) メソッドを介して Web.config ファイルの <connectionStrings> セクションにアクセスし、ConfigurationSection オブジェクトを返します。

ConfigurationSection オブジェクトには、構成セクションに関する追加情報と機能を提供する SectionInformation プロパティが含まれています。 上記のコードで示されているように、SectionInformation プロパティの IsProtected プロパティをチェックすることで、構成セクションが暗号化されているかどうかを判断できます。 さらに、SectionInformation プロパティの ProtectSection(provider) および UnprotectSection メソッドを使用して、このセクションを暗号化または暗号化解除できます。

ProtectSection(provider) メソッドは、暗号化時に使用する保護された構成プロバイダーの名前を指定する文字列を入力として受け入れます。 EncryptConnString ボタンのイベント ハンドラーでは、DPAPI プロバイダーが使用されるように、DataProtectionConfigurationProvider を ProtectSection(provider) メソッドに渡します。 UnprotectSection メソッドは、構成セクションの暗号化に使用されたプロバイダーを特定できるため、入力パラメーターは必要ありません。

ProtectSection(provider) または UnprotectSection メソッドを呼び出した後、Configuration オブジェクトの Save メソッドを呼び出して変更を保存する必要があります。 構成情報が暗号化または暗号化解除され、変更が保存されると、DisplayWebConfig を呼び出して、更新された Web.config の内容を TextBox コントロールに読み込みます。

上記のコードを入力したら、ブラウザーから EncryptingConfigSections.aspx ページにアクセスしてテストします。 最初に、Web.config の内容を一覧表示するページが表示され、<connectionStrings> セクションがプレーンテキストで表示されます (図 3 を参照)。

Web ブラウザーに読み込まれた EncryptingConfigSections.aspx ページを示すスクリーンショット。

図 3: ページに TextBox および 2 つの Button Web コントロールを追加する (クリックするとフルサイズの画像が表示されます)

次に、[接続文字列の暗号化] ボタンをクリックします。 要求の検証が有効になっている場合、WebConfigContents テキスト ボックスからポストバックされたマークアップによって HttpRequestValidationException が生成され、"潜在的に危険な Request.Form 値がクライアントから検出されました" というメッセージが表示されます。 ASP.NET 2.0 で既定で有効になっている要求の検証では、エンコードされていない HTML を含むポストバックが禁止されており、スクリプトインジェクション攻撃を防げるように設計されています。 このチェックは、ページまたはアプリケーションレベルで無効にすることができます。 このページでこれをオフにするには、@Page ディレクティブで ValidateRequest 設定を false に設定します。 @Page ディレクティブは、ページの宣言型マークアップの上部にあります。

<%@ Page ValidateRequest="False" ... %>

要求の検証、その目的、ページおよびアプリケーションレベルで無効にする方法、およびマークアップを HTML エンコードする方法の詳細については、「要求の検証 - スクリプト攻撃の防止」を参照してください。

ページに対する要求の検証を無効にした後、もう一度 [接続文字列の暗号化] ボタンをクリックしてみてください。 ポストバック時に、構成ファイルにアクセスし、その <connectionStrings> セクションが DPAPI プロバイダーを使用して暗号化されます。 その後、テキスト ボックスが更新され、新しい Web.config の内容が表示されます。 図 4 に示すように、<connectionStrings> 情報が暗号化されるようになりました。

[接続文字列の暗号化] ボタンをクリックすると <connectionString> セクションが暗号化される

図 4: [接続文字列の暗号化] ボタンをクリックして <connectionString> セクションを暗号化する (クリックするとフルサイズの画像が表示されます)

コンピューターで生成された暗号化された <connectionStrings> セクションは次のとおりです。ただし、簡潔にするために、<CipherData> 要素の内容の一部は削除されています。

<connectionStrings 
    configProtectionProvider="DataProtectionConfigurationProvider">
  <EncryptedData>
    <CipherData>
      <CipherValue>AQAAANCMnd8BFdERjHoAwE/...zChw==</CipherValue>
    </CipherData>
  </EncryptedData>
</connectionStrings>

Note

<connectionStrings> 要素は、暗号化を実行するために使用されるプロバイダー (DataProtectionConfigurationProvider) を指定します。 この情報は、[接続文字列の暗号化解除] ボタンがクリックされたときに UnprotectSection メソッドによって使用されます。

接続文字列情報は Web.config からアクセスされると (記述したコード、SqlDataSource コントロール、または型指定されたデータセット内の TableAdapter から自動生成されたコードのいずれかによって)、自動的に暗号化解除されます。 つまり、暗号化された <connectionString> セクションを暗号化解除するために、追加のコードやロジックを追加する必要はありません。 これを実証するには、現時点で前のチュートリアルの 1 つ (「基本レポート」セクションの Simple Display に関するチュートリアル (~/BasicReporting/SimpleDisplay.aspx) など) を参照してください。 図 5 に示すように、チュートリアルは期待どおりに動作し、暗号化された接続文字列情報が ASP.NET ページによって自動的に暗号化解除されていることがわかります。

データ アクセス層によって自動的に接続文字列情報の暗号化が解除される

図 5: データ アクセス層が接続文字列情報を自動的に暗号化解除する (クリックするとフルサイズの画像が表示されます)

<connectionStrings> セクションをプレーンテキスト表現に戻すには、[接続文字列の暗号化解除] ボタンをクリックします。 ポストバック時に、Web.config 内の接続文字列がプレーンテキストで表示されます。 この時点で、このページに初めてアクセスしたときと同じように画面が表示されます (図 3 を参照)。

手順 3: aspnet_regiis.exe を使用して構成セクションを暗号化する

.NET Framework には、$WINDOWS$\Microsoft.NET\Framework\version\ フォルダーにさまざまなコマンド ライン ツールが含まれています。 たとえば、「SQL キャッシュ依存関係を使用する」チュートリアルでは、aspnet_regsql.exe コマンド ライン ツールを使用して、SQL キャッシュ依存関係に必要なインフラストラクチャを追加する方法について説明しました。 このフォルダーにあるもう 1 つの便利なコマンド ライン ツールは、ASP.NET IIS 登録ツール (aspnet_regiis.exe) です。 名前が示すように、ASP.NET IIS 登録ツールは主に、ASP.NET 2.0 アプリケーションを Microsoft のプロレベルの Web サーバーである IIS に登録するために使用されます。 IIS 関連の機能に加えて、ASP.NET IIS 登録ツールは、Web.config 内の指定された構成セクションを暗号化または暗号化解除するために使用することもできます。

次のステートメントは、aspnet_regiis.exe コマンドライン ツールを使用して構成セクションを暗号化するために使用される一般的な構文を示しています。

aspnet_regiis.exe -pef section physical_directory -prov provider

section は暗号化する構成セクション (connectionStrings など)、physical_directory は Web アプリケーションのルート ディレクトリへの完全な物理パス、provider は使用する保護された構成プロバイダーの名前 (DataProtectionConfigurationProvider など) です。 または、Web アプリケーションが IIS に登録されている場合は、次の構文を使用して物理パスの代わりに仮想パスを入力できます。

aspnet_regiis.exe -pe section -app virtual_directory -prov provider

次の aspnet_regiis.exe の例では、マシンレベルのキーを持つ DPAPI プロバイダーを使用して <connectionStrings> セクションを暗号化します。

aspnet_regiis.exe -pef
"connectionStrings" "C:\Websites\ASPNET_Data_Tutorial_73_CS"
-prov "DataProtectionConfigurationProvider"

同様に、aspnet_regiis.exe コマンドライン ツールを使用して構成セクションを暗号化解除することもできます。 -pef スイッチの代わりに -pdf を使用します (または -pe の代わりに -pd を使用します)。 また、暗号化を解除するときにプロバイダー名は必要ありません。

aspnet_regiis.exe -pdf section physical_directory
  -- or --
aspnet_regiis.exe -pd section -app virtual_directory

Note

コンピューター固有のキーを使用する DPAPI プロバイダーを使用しているため、Web ページが提供されているのと同じコンピューターから aspnet_regiis.exe を実行する必要があります。 たとえば、ローカル開発マシンからこのコマンド ライン プログラムを実行し、暗号化された Web.config ファイルを運用サーバーにアップロードした場合、接続文字列情報は開発マシン固有のキーを使用して暗号化されているため、運用サーバーでは接続文字列情報を暗号化解除できません。 RSA プロバイダーについては、RSA キーを別のコンピューターにエクスポートできるため、この制限はありません。

データベース認証オプションを理解する

アプリケーションが Microsoft SQL Server データベースに対して SELECTINSERTUPDATE、または DELETE クエリを発行する前に、データベースはまず要求元を識別する必要があります。 このプロセスは "認証" と呼ばれ、SQL Server では 2 つの認証方法が提供されています。

  • Windows 認証 - アプリケーションが実行されているプロセスは、データベースとの通信に使用されます。 Visual Studio 2005 の ASP.NET 開発サーバーを介して ASP.NET アプリケーションを実行する場合、ASP.NET アプリケーションは現在ログオンしているユーザーの ID を想定します。 Microsoft インターネット インフォメーション サーバー (IIS) 上の ASP.NET アプリケーションの場合、ASP.NET アプリケーションは通常、domainName``\MachineName または domainName``\NETWORK SERVICE の ID を想定しますが、これはカスタマイズ可能です。
  • SQL 認証 - 認証の資格情報としてユーザー ID とパスワードの値が指定されます。 SQL 認証では、ユーザー ID とパスワードが接続文字列で提供されます。

Windows 認証はより安全であるため、SQL 認証よりも優先されます。 Windows 認証では、接続文字列にユーザー名とパスワードは含まれず、Web サーバーとデータベース サーバーが 2 台の異なるマシンに存在する場合、資格情報がネットワーク上にプレーンテキストで送信されることはありません。 ただし、SQL 認証では、認証資格情報は接続文字列にハードコーディングされ、Web サーバーからデータベース サーバーにプレーンテキストで送信されます。

これらのチュートリアルでは、Windows 認証を使用しています。 接続文字列を調べることで、使用されている認証モードを判別できます。 チュートリアルの Web.config の接続文字列は次のとおりです。

Data Source=.\SQLEXPRESS; AttachDbFilename=|DataDirectory|\NORTHWND.MDF; Integrated Security=True; User Instance=True

Integrated Security=True であり、ユーザー名とパスワードがない場合は、Windows 認証が使用されていることを示します。 一部の接続文字列では、Integrated Security=True の代わりに Trusted Connection=Yes または Integrated Security=SSPI という用語が使用されますが、これら 3 つはすべて Windows 認証の使用を示しています。

次の例は、SQL 認証を使用する接続文字列を示しています。 $CREDENTIAL_PLACEHOLDER$ は、パスワード キーと値のペアのプレースホルダーです。 資格情報が接続文字列内に埋め込まれていることに注意してください。

Server=serverName; Database=Northwind; uid=userID; $CREDENTIAL_PLACEHOLDER$

攻撃者がアプリケーションの Web.config ファイルを表示できることを想像してみてください。 SQL 認証を使用してインターネット経由でアクセス可能なデータベースに接続する場合、攻撃者はこの接続文字列を使用して、SQL Management Studio または自分の Web サイトの ASP.NET ページからデータベースに接続できます。 この脅威を軽減するには、保護された構成システムを使用して Web.config 内の接続文字列情報を暗号化します。

Note

SQL Server で使用できるさまざまな種類の認証の詳細については、「セキュリティで保護された ASP.NET アプリケーションの構築: 認証、認可、セキュリティで保護された通信」を参照してください。 Windows および SQL 認証の構文の違いを示す接続文字列の例については、ConnectionStrings.com を参照してください。

まとめ

既定では、ASP.NET アプリケーション内の .config 拡張子を持つファイルには、ブラウザー経由でアクセスできません。 これらの種類のファイルは、データベース接続文字列、ユーザー名、パスワードなどの機密情報が含まれている可能性があるため返されません。 .NET 2.0 の保護された構成システムでは、指定した構成セクションを暗号化できるため、機密情報をさらに保護できます。 保護された構成プロバイダーが 2 つ組み込まれており、1 つは RSA アルゴリズムを使用し、もう 1 つは Windows データ保護 API (DPAPI) を使用します。

このチュートリアルでは、DPAPI プロバイダーを使用して構成設定を暗号化および暗号化解除する方法について説明しました。 これは、手順 2 で説明したようにプログラムで行うことも、手順 3 で説明した aspnet_regiis.exe コマンド ライン ツールを使用して行うこともできます。 ユーザーレベルのキーを使用する方法、または代わりに RSA プロバイダーを使用する方法の詳細については、「もっと読む」セクションのリソースを参照してください。

プログラミングに満足!

もっと読む

この記事で説明したトピックの詳細については、次のリソースを参照してください。

著者について

7 冊の ASP/ASP.NET 書籍の著者であり、4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジに取り組んでいます。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズは24時間で2.0 ASP.NET 自分自身を教えています。 にアクセスするか、ブログを使用して にアクセスmitchell@4GuysFromRolla.comできます。これは でhttp://ScottOnWriting.NET見つけることができます。

特別な感謝

このチュートリアル シリーズは、多くの役に立つ校閲者によってレビューされました。 このチュートリアルのリード レビュー担当者は、Teresa Murphy と Randy Schmidt でした。 今後の MSDN の記事を確認することに関心がありますか? その場合は、 にmitchell@4GuysFromRolla.com行をドロップしてください。