-
Notifications
You must be signed in to change notification settings - Fork 0
MS_ConfigEncryption
-
.NET の config
-
DevPartner の解析結果で気がついたのだけど、
*.config の RSA 暗号化は connectionStringSection 以外も可能らしい。
補足(本ページの対象は .NET Framework): 本ページが扱う
**保護された構成(Protected Configuration)**は、
System.Configurationの仕組みであり、
.NET Core 以降には存在しない。【.NET Framework】 Web.config / App.config → aspnet_regiis で【セクション単位に暗号化】できる ★ 本ページ 【.NET(Core 系)】 appsettings.json → 【暗号化の仕組みはない】 → 代わりに【秘密情報を config に置かない】設計にする ・環境変数 ・User Secrets(開発時) ・【Key Vault / Secrets Manager】(本番)★ ・マネージド ID(そもそも秘密情報を持たない)設計思想が「隠す」から「持たない」へ移った——
というのが最も重要な変化である。
詳細は FaaS config にも記した。本ページは、既存の .NET Framework 資産を保守する際に必要な知識
として読むのが妥当である。
app.config のビルド出力が、*.exe.config になる。
ASP.NET の Web アプリケーション毎の設定
マシンの設定として、暗号化・復号化、署名・検証のキーを含む。
- ASP.NET と MachineKey の関係をまとめてみた - しばやん雑記
https://blog.shibayan.jp/entry/20130331/1364728631
appSettingsSection を切り出した *.config など。
通常、暗号化の必要な機密情報を収めた Section を aspnet_regiis.exe で暗号化。
カスタム アプリケーションの設定
DBMS などへの、接続文字列
偽装資格情報
セッション状態プロバイダ用の接続文字列
-
以下の Section は通常、暗号化が出来ない。
- processModel
- runtime
- mscorlib
- startup
- system.runtime.remoting
- configProtectedData
- satelliteassemblies
- cryptographySettings
- cryptoNameMapping
- cryptoClasses
-
ただし、aspnet_setreg.exe ツールを使用すれば暗号化が可能。
- 例
- ASP.NET ユーティリティを使用して資格情報およびセッション状態の接続文字列を暗号化する方法
https://support.microsoft.com/ja-jp/help/329290/
- ASP.NET ユーティリティを使用して資格情報およびセッション状態の接続文字列を暗号化する方法
- 例
補足(なぜ暗号化できないセクションがあるのか): 一覧の顔ぶれには
理由がある。【暗号化できない理由】 ① 【暗号化の仕組みより先に読まれる】 configProtectedData … 復号プロバイダの定義そのもの cryptographySettings / cryptoClasses … 暗号アルゴリズムの定義 → これを暗号化すると【復号できなくなる】(鶏と卵)★ ② 【CLR の起動前に、ネイティブ コードが読む】 startup / runtime / mscorlib → マネージド コードの復号処理が動く前に必要 ③ 【IIS のワーカー プロセス起動時に読まれる】 processModel … プロセスの実行 ID を含む → w3wp.exe が起動する前に必要
aspnet_setreg.exeが別途用意された理由も、ここにある。aspnet_setreg は【レジストリに DPAPI で暗号化して格納】し、 config からは参照だけを書く <processModel userName="registry:HKLM\SOFTWARE\MyApp\ASPNET_SETREG,userName" password="registry:HKLM\SOFTWARE\MyApp\ASPNET_SETREG,password" /> → config 側は【平文の参照】。実際の値はレジストリにある → セクションの暗号化とは【別の仕組み】である ★
identityセクションは、
ASP.NETとSSRSの連携と認証 で触れた
<identity impersonate="true" userName="..." password="..." />の
平文パスワード問題に直結する。
現在は gMSA / マネージド ID を使い、
そもそもパスワードを config に書かないのが正しい。
以下の方法で暗号化できる。
CNG のプロバイダを使用している模様。
-
CNG キーコンテナ(鍵コンテナ)を使用する。
-
このため、キーコンテナ(鍵コンテナ)のアクセス権云々でハマることがある模様。
-
また、開発サーバから運用サーバへのデプロイのシナリオ、
Web ファームでの RSA 暗号化シナリオでは、
カスタムの RSA 暗号鍵をエクスポート&インポートすることで対応する。
-
-
参考
- web.configの暗号化 | どっとねっとふぁん
https://blogonos.wordpress.com/2006/02/23/web-config%E3%81%AE%E6%9A%97%E5%8F%B7%E5%8C%96/
- web.configの暗号化 | どっとねっとふぁん
補足(「アクセス権云々でハマる」の中身): 原文が記録している
このハマりどころは、実務で最も頻繁に起きる問題なので具体化しておく。【暗号化と復号は別の主体が行う】 暗号化: 開発者 / 配置担当者(管理者権限) aspnet_regiis -pe ... を実行 復号 : 【IIS のアプリケーション プール ID】(実行時) → w3wp.exe が鍵コンテナを読む → 【復号する側に鍵コンテナへのアクセス権がないと落ちる】★# 鍵コンテナへのアクセス権を付与する(これを忘れて落ちる) aspnet_regiis -pa "NetFrameworkConfigurationKey" "IIS APPPOOL\MyAppPool"典型的なエラー:
「構成セクションを復号化できませんでした。 RSA キー コンテナーを開くことができませんでした。」 → -pa でアクセス権を付与していない → またはアプリケーション プール ID を変更した後に付け直していない ★Web ファーム(複数台)での運用:
【既定の鍵はマシン固有】 → A サーバで暗号化した config は、B サーバでは復号できない 【対応】 ① カスタムの鍵コンテナを作る aspnet_regiis -pc "MyKeys" -exp ② 【エクスポートする】(-exp を付けないとエクスポートできない)★ aspnet_regiis -px "MyKeys" keys.xml -pri ③ 全サーバにインポート aspnet_regiis -pi "MyKeys" keys.xml ④ 各サーバでアクセス権を付与 aspnet_regiis -pa "MyKeys" "IIS APPPOOL\MyAppPool"【運用上の注意】 ・エクスポートした keys.xml は【秘密鍵そのもの】 → 安全に扱い、作業後は確実に破棄する ★ ・鍵を失うと復号できない= config を作り直すことになる ・この煩雑さが、現在 Key Vault 等の外部保管に移った理由でもある移行メモ: 原文は「CNG のプロバイダを使用している模様」と
推測形で書いているが、
RsaProtectedConfigurationProviderが使うのは
従来の CryptoAPI(CAPI)の RSA キー コンテナである
(CNG ではない)。
格納場所は以下になる。%ALLUSERSPROFILE%\Microsoft\Crypto\RSA\MachineKeys\ (マシン レベル) %APPDATA%\Microsoft\Crypto\RSA\ (ユーザー レベル)
- 既定のプロバイダ
- RSA 公開鍵暗号化を使用して、データの暗号化と暗号化解除
- Windows データ保護 API (DPAPI) を使用して、データの暗号化と暗号化解除
補足(2 つのプロバイダの使い分け):
RSAProtectedConfigurationProvider DPAPIProtectedConfigurationProvider 方式 RSA(鍵コンテナ) DPAPI(マシン鍵 / ユーザー鍵) 鍵の持ち出し できる(エクスポート/インポート) できない ★ Web ファーム 可(鍵を配る) 不可(1 台ごとに暗号化が必要) 設定の手間 鍵コンテナの作成・権限付与 少ない(すぐ使える) 既定 こちら — 【使い分け】 1 台構成・簡便さ優先 → DPAPI Web ファーム・配置の自動化 → RSA ★DPAPI の
useMachineProtectionに注意する。<configProtectedData> <providers> <add name="MyDPAPI" type="System.Configuration.DpapiProtectedConfigurationProvider, ..." useMachineProtection="true" /> <!-- ← マシン単位。既定は true --> </providers> </configProtectedData>useMachineProtection="true" … 【同じマシンなら誰でも復号できる】 → 他のアプリからも読める(防御が弱い) useMachineProtection="false" … ユーザー単位 → サービス アカウントのプロファイルが要る
-
Web.config しか暗号化出来ない(ディレクトリ指定しかサポートしない)ので、
*.config を対象とする場合は、Web.config にリネームして aspnet_regiis で暗号化処理をする。 -
参考
- 構成セクションの暗号化と複合化
https://learn.microsoft.com/ja-jp/previous-versions/aspnet/zhhddkxy(v=vs.100) - チュートリアル : 保護された構成を使用した構成情報の暗号化
https://learn.microsoft.com/ja-jp/previous-versions/aspnet/dtkwfdky(v=vs.100)
- 構成セクションの暗号化と複合化
補足(
aspnet_regiisの使い方と落とし穴): 原文が記録している
**「Web.config にリネームして暗号化する」**という回避策は、
実務でよく使われる手法である。# 物理ディレクトリを指定して暗号化する(-pef) aspnet_regiis -pef "connectionStrings" "C:\MyApp" # ↑ セクション名 ↑ Web.config があるフォルダ # 仮想パスを指定する場合(-pe) aspnet_regiis -pe "connectionStrings" -app "/MyApp" # 復号 aspnet_regiis -pdf "connectionStrings" "C:\MyApp"【App.config を暗号化する手順(原文の回避策)】 ① App.config → Web.config にリネーム ② aspnet_regiis -pef で暗号化 ③ Web.config → App.config に戻す ④ ビルド出力の MyApp.exe.config として配置 → デスクトップ アプリの config を暗号化する定石落とし穴:
① 【32bit / 64bit で aspnet_regiis の場所が違う】 %WINDIR%\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe %WINDIR%\Microsoft.NET\Framework64\v4.0.30319\aspnet_regiis.exe → 鍵コンテナは共通だが、実行する側は環境に合わせる ② 【暗号化した config はソース管理に入れない】 → 環境ごとに鍵が違うため、他環境で復号できない → 平文をテンプレートとして持ち、【配置時に暗号化】する ★ ③ 【暗号化しても「隠している」だけ】 → サーバに管理者権限で入れる人は復号できる → アプリ自身が復号できる= アプリを乗っ取れば読める → 【防御の深さの 1 層】であって、万能ではない暗号化後の Web.config は以下のようになる。
<connectionStrings configProtectionProvider="RsaProtectedConfigurationProvider"> <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" ...> <CipherData><CipherValue>rXbT8h...</CipherValue></CipherData> </EncryptedData> </connectionStrings>アプリ側のコードは変更不要である。
// 暗号化されていても、読み方は同じ(実行時に自動で復号される)★ var cs = ConfigurationManager.ConnectionStrings["MyDb"].ConnectionString;この**「アプリのコードを変えずに済む」**点が、
保護された構成の最大の利点である。
SectionInformation.ProtectSection メソッド、Configuration.Save メソッドを使用する。
-
ASP.NET から
- ASP.NETの構成ファイルを暗号化する: ある SE のつぶやき
http://fnya.cocolog-nifty.com/blog/2009/05/aspnet-a98d.html
- ASP.NETの構成ファイルを暗号化する: ある SE のつぶやき
-
Installer から
- yan note: .NET 構成ファイルapp.configの暗号化
http://yan-note.blogspot.jp/2010/06/netappconfig.html
- yan note: .NET 構成ファイルapp.configの暗号化
-
Microsoft Learn > .NET 開発 > .NET Framework 4.6 and 4.5 > .NET Framework クラス ライブラリ
- Configuration.Save メソッド (System.Configuration)
https://learn.microsoft.com/ja-jp/dotnet/api/system.configuration.configuration.save - SectionInformation.ProtectSection メソッド (String) (System.Configuration)
https://learn.microsoft.com/ja-jp/dotnet/api/system.configuration.sectioninformation.protectsection
- Configuration.Save メソッド (System.Configuration)
補足(API で行う場合の実装): 原文が挙げる 2 つのメソッドで、
インストーラや初回起動時に自動暗号化できる。static void ProtectSection(string sectionName) { var config = ConfigurationManager.OpenExeConfiguration( ConfigurationUserLevel.None); var section = config.GetSection(sectionName); if (section != null && !section.SectionInformation.IsProtected) { section.SectionInformation.ProtectSection( "RsaProtectedConfigurationProvider"); section.SectionInformation.ForceSave = true; // ← これが要る ★ config.Save(ConfigurationSaveMode.Modified); } }【注意点】 ・`ForceSave = true` を付けないと、 変更がないと判断されて【保存されない】ことがある ・config ファイルへの【書き込み権限】が必要 → Program Files 配下は管理者権限が要る ・IIS 配下で実行時に暗号化すると、 【config の変更でアプリケーション プールが再起動する】★ → 初回アクセスが再帰的に走らないよう注意
ProtectSectionの対称としてUnprotectSectionがある
(復号)。運用手順書に復号方法も残しておくこと。
補足(現在の推奨:そもそも config に秘密情報を置かない): 本ページの
技術は .NET Framework では有効だが、
現在の設計指針を明記しておく。① 開発時 — User Secrets
dotnet user-secrets init dotnet user-secrets set "ConnectionStrings:MyDb" "Server=...;"・プロジェクト外(ユーザー プロファイル配下)に保存される ・【ソース管理に絶対に入らない】★ ・IConfiguration から通常どおり読める② 本番 — Key Vault / Secrets Manager
builder.Configuration.AddAzureKeyVault( new Uri("https://myvault.vault.azure.net/"), new DefaultAzureCredential()); // → 以降、Configuration["MyDb"] で読める(値は Key Vault から)③ 最善 — 秘密情報そのものをなくす
// 接続文字列にパスワードを含めない(Entra ID 認証) "Server=tcp:myserver.database.windows.net;Database=MyDb; Authentication=Active Directory Default;"【マネージド ID の利点】 ・パスワードが【どこにも存在しない】 ・ローテーション不要 ・漏洩のしようがない ★ → 暗号化して隠すより、根本的に強い④ 漏洩を検知する仕組みを持つ
・GitHub の Secret Scanning / Push Protection ・git-secrets / gitleaks を CI に組み込む ・【一度リポジトリに入った秘密情報は、履歴から消えない】 → 漏れたら【必ずローテーションする】(履歴の書き換えより確実)★
- How To: RSA を使用して ASP.NET 2.0 内の構成セクションを暗号化する方法
https://learn.microsoft.com/ja-jp/previous-versions/msp-n-p/ff650304(v=pandp.10)
- むりせず♪なまけず? ~ぷろくらすてぃねいたーの言い訳雑記~
- ASP.NET Core での開発時のアプリ シークレットの安全な保存
https://learn.microsoft.com/ja-jp/aspnet/core/security/app-secrets - Azure Key Vault の構成プロバイダー
https://learn.microsoft.com/ja-jp/aspnet/core/security/key-vault-configuration - Azure リソースのマネージド ID
https://learn.microsoft.com/ja-jp/entra/identity/managed-identities-azure-resources/overview
Tags: 移行, .NET開発, セキュリティ, 暗号化
このWikiは「Open棟梁Project」,「OSSコンソーシアム 開発基盤部会」によって運営されています。