KB5025823 .NET 應用程式匯入 X.509 憑證方式的變更

套用到
.NET

註: 2023年6月22日修訂,更新解決方案與解決方法

註: 2023年6月15日修訂,更新了選項4與5的相關工作

背景

2023 年 6 月 13 日,Microsoft 發布了 .NET Framework 與 .NET 的安全更新,影響執行環境匯入 X.509 憑證的方式。 這些變更可能導致 X.509 憑證匯入在更新前匯入成功的情況下觸發 CryptographicException。

本文件說明受影響應用程式的變更及可利用的變通方法。

受影響的軟體

  • .NET Framework 2.0
  • .NET Framework 4.6.2、4.7、4.7.1、4.7.2
  • .NET Framework 4.8
  • .NET Framework 4.8.1
  • .NET 6.0
  • .NET 7.0

受影響的 API

變化描述

在 2023 年 6 月 13 日變更之前,當 .NET Framework 和 .NET 以二進位憑證 blob 進行匯入時,.NET Framework 和 .NET 通常會將 blob 的驗證與匯入委派給底層作業系統。 例如,在 Windows 上,.NET Framework 和 .NET 通常會依賴 PFXImportCertStore API 來驗證和匯入。

自 2023 年 6 月 13 日變更起,當 .NET Framework 與 .NET 呈現可匯入的二進位憑證 blob 時,.NET Framework 與 .NET 在某些情況下會在將 blob 交給底層作業系統前進行額外驗證。 這項額外的驗證會進行一系列啟發式檢查,以判斷匯入憑證是否會在匯入時惡意耗盡資源。 由於這是 超出 底層作業系統通常執行的額外驗證,它可能會阻擋在 2023 年 6 月 13 日變更前已成功匯入的憑證塊狀資料。

已知迴歸

  1. 如果 X.509 憑證以 PFX blob 格式匯出,且密碼迭代次數異常高,該憑證可能無法匯入。 大多數憑證出口設施的迭代次數介於 2,000 到 10,000 之間。 安全更新套用後,對於迭代次數超過 600,000 的憑證,匯入將失敗。

  2. 如果 X.509 憑證是使用 密碼匯出的(例如 via X509Certificate.Export(X509ContentType.Pfx, (string)null) 或無 X509Certificate.Export(X509ContentType.Pfx)]密碼),該憑證現在可能會無法匯入。
     

    注意

    上述迴歸問題已在 2023 年 6 月 22 日的更新中被討論,該更新在 KB5028608 中討論。

  3. 如果 X.509 憑證以 PFX blob 格式匯出,利用 Windows 保護 SID 私鑰的功能,該憑證可能無法匯入。 這會影響以下方式產生的 PFX blobs:

    • 透過 Windows 的 憑證匯出精靈 ,並在精靈中指定私鑰應保護給網域使用者;或
    • 透過 PowerShell 的 Export-PfxCertificate 指令檔,提供明確參數 -ProtectTo ;或
    • 透過 certutil 工具,提供明確 -protectto 參數;或
    • 透過提供 PKCS12_PROTECT_TO_DOMAIN_SIDS 標誌的 PFXExportCertStoreEx API。

解決 & 變通方法

有各種變通方法,取決於你想針對程式碼中個別呼叫地點做特定變更,或是改變單一應用程式的行為,或是想做全機範圍的變更。

選項一 (首選) - 安裝更新的修補程式

注意

這是首選方案,因為它能解決常見的客戶迴歸問題,且不需更改應用程式程式碼。

適用性:此選項適用於所有版本的 .NET Framework 與 .NET。

此問題已於 2023 年 6 月 22 日的更新中被討論,該更新於 KB5028608 中討論。

Microsoft 建議,遇到 2023 年 6 月 13 日版本中出現的回歸問題的客戶,先嘗試安裝此更新的修補程式,再嘗試本文後續列出的變通方法。

選項二 - 修改通話地點

適用性:此選項適用於所有版本的 .NET Framework 與 .NET。

考慮你匯入的 blob 是否值得信賴。 例如,blob 是從你控制的可信地點取得,例如資料庫或設定檔,還是透過未認證或無權限的用戶端發出的網路請求?

Microsoft 強烈建議您不要匯入由未經認證或未特權客戶端提供的 PFX blobs,因為這些 blob 可能包含惡意的資源耗盡行為。

如果你需要匯入由不受信任方提供的 公鑰 憑證 blob,你可以使用以下程式碼安全地匯入這樣的 blob。 這段範例程式碼使用 GetCertContentType 方法來判斷憑證 blob 的底層類型,並且在你只預期匯入公鑰憑證 blob 的情況下,會拒絕 PFX blob。 當給予不受信任的非 PFX blob 時,建 X509Certificate2(byte[]) 構子仍可安全使用。


using System.Security.Cryptography.X509Certificates;
public static X509Certificate2 ImportPublicCertificateBlob(byte[] blob)
{
     if (X509Certificate2.GetCertContentType(blob) == X509ContentType.Pfx)
    {
          throw new Exception("PFX blobs are disallowed.");
    }
   else
   {
         // Import only after we have confirmed it's not a PFX.
        return new X509Certificate2(blob);
    }
} 

如果你需要匯入無密碼私鑰憑證 blob,且你已判斷該 blob 可信,可以透過呼叫不同的建構器過載來抑制 2023 年 6 月 13 日安全版本所執行的額外驗證檢查。 例如,你可以呼叫建構子 overload,它接受 字串密碼 參數,並傳遞 null 來取得參數值。

byte[] blobToImport = GetBlobToImport(); // fetch this from a database, config, etc. 

// REGRESSION - byte[] ctor performs additional security checks X509Certificate2 certA = new X509Certificate2(blobToImport);

// RECOMMENDED WORKAROUND - different ctor overload suppresses additional security checks X509Certificate2 certB = new X509Certificate2(blobToImport, (string)null);

選項三 - 使用環境變數修改或抑制額外的驗證

適用性:此選項僅適用於所有版本的 .NET Framework。  此規定不適用於 .NET 6.0+。

雖然 .NET Framework 預設限制匯入操作不超過 600,000 次密碼迭代,但此限制可透過環境變數在整個應用程式或機器範圍內設定。 此新限制將適用於上述所有受影響 API 的調用。

要更改限制,請將環境變數 COMPlus_Pkcs12UnspecifiedPasswordIterationLimit 設為新限制應有的值。 例如,若要將限制設為 1,000,000 次 (一百萬次) 迭代,請設定如下所示的環境變數。

  • 此數值控制 迭代次數,即 MAC 迭代次數、加密保險箱內容物與 shrouded 包包重複次數的總和。 如果你手動匯出了 PFX,並用明確的迭代次數 <iter_count (> ,例如透過 openssl pkcs12 -export -iter <iter_count>) ,並且想匯入那個 PFX blob,請將這個環境變數設定為至少等於所有預期迭代總和的值。 實務上,.NET Framework 與 .NET 可能會允許總迭代次數略高於此處設定的任何明確限制。

COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=1000000

若要完全抑制額外的檢查,請將環境變數設為特殊哨兵值 -1,如下所示。

  • ⚠️ 警告:只有當你確定目標應用程式沒有處理不受信任的憑證輸入時,才把環境變數值設為 -1。

COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=-1

選項四 - 使用 AppContext 修改或抑制額外的驗證

適用性:此選項僅適用於 .NET 6.0+。  這不適用於 .NET Framework

雖然 .NET 預設限制匯入操作不超過 600,000 次密碼迭代,但此限制可透過 AppContext 開關在全應用程式範圍內設定。 此新限制將適用於上述所有受影響 API 的調用。

要更改限制,請將 AppContext switch System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit 設為新限制應有的值。 例如,若要設定限制為 1,000,000 次 (一百萬次) 迭代,請依照下方所示設定開關。

  • 此數值控制總迭代次數,即 MAC 迭代次數、加密保險箱內容物與 shrouded 包包重複次數的總和。 如果你手動匯出了 PFX,並用明確的迭代次數 <iter_count (> ,例如透過 openssl pkcs12 -export -iter <iter_count>) ,並且想匯入那個 PFX blob,請將這個環境變數設定為至少等於所有預期迭代總和的值。 實務上,.NET 可能允許總迭代次數略高於此處設定的任何明確限制。

要在應用程式的專案檔案中設定開關,請 (.csproj 或 .vbproj) :

<!--

  • 此切換僅在當前專案檔案代表應用程式時有效。 如果目前的專案檔案代表共享函式庫,則不會有影響。

-->

<ItemGroup>

  • <RuntimeHostConfigurationOption include=“System.Security.Cryptography.pkcs12UnspecifiedPasswordIterationLimit” value=“1000000” />

</ItemGroup>

或者,您也可以將名為 runtimeconfig.template.json 的檔案放入包含您應用程式專案檔案的同一目錄中,內容如下:

{

     "configProperties": {

  • 「System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit」:1000000

      }

}

欲了解更多關於更改 .NET 執行時設定的資訊,請參閱文件頁面中的 .NET 執行時設定設定

為了完全抑制額外的檢查,請將配置開關設為特殊的哨兵值 -1,如下所示。

⚠️ 警告: 只有在你確定目標應用程式沒有處理不受信任憑證輸入時,才把 AppContext 切換設為 -1。

在應用程式的專案檔案中, (.csproj 或 .vbproj) :

<!--

  • 此切換僅在當前專案檔案代表應用程式時有效。 如果目前的專案檔案代表共享函式庫,則不會有影響。

-->

<ItemGroup>

  • <RuntimeHostConfigurationOption include=“System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit” value=“-1” />

</ItemGroup>

或者在runtimeconfig.template.json檔案中:

{

  • “configProperties”: {
  • 「System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit」:-1

     }

}

選項 5 - 透過.NET Framework) 登錄檔在 Windows 專用中修改或抑制額外的驗證功能 (

適用性:此選項僅適用於所有版本的 .NET Framework。  此規定不適用於 .NET 6.0+。

雖然 .NET Framework 預設限制匯入操作不超過 600,000 次密碼迭代,但此限制可透過 HKLM 登錄檔在全機範圍內設定。 此新限制將適用於上述所有受影響 API 的調用。

要更改限制,在登錄檔鍵 HKLM\Software\Microsoft\.NETFramework下,將值 Pkcs12UnspecifiedPasswordIterationLimit 設為新限制應有的值。 例如,若要設定限制為 1,000,000 次 (一百萬次) 迭代,請從升高的命令提示字元執行以下所示指令。

  • 此數值控制 迭代次數,即 MAC 迭代次數、加密保險箱內容物與 shrouded 包包重複次數的總和。 如果你手動匯出了 PFX,使用明確的迭代次數 <iter_count> (,例如透過 openssl pkcs12 -export -iter <iter_count>) ,並且想匯入那個 PFX blob,請將這個登錄檔值設定為至少等於所有預期迭代總和的值。 實務上,.NET Framework 可能允許總迭代次數略高於此處設定的任何明確限制。
  • 登錄檔設定依架構而異。 為確保應用程式無論其目標架構如何都能觀察到您的設定值,請 記得修改 32 位元與 64 位元登錄檔,如下所示。

reg add "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /t REG_DWORD /d 1000000 /reg:32
reg add "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /t REG_DWORD /d 1000000 /reg:64

若要完全抑制額外檢查,請從提升的命令提示字元將登錄檔值設為 -1,如下所示。

  • ⚠️ 警告:只有當你確定目標機器上的服務沒有處理不受信任的憑證輸入時,才把登錄檔值設為 -1。
  • 要設定 -1 哨兵,請使用 REG_SZ 類型而非 REG_DWORD 類型。 登錄檔設定依架構而異。 為確保應用程式無論其目標架構如何都能觀察到您的設定值,請 記得修改 32 位元與 64 位元登錄檔,如下所示。

reg add "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /t REG_SZ /d -1 /reg:32
reg add "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /t REG_SZ /d -1 /reg:64

若要還原登錄檔變更,請從升高的命令提示字元刪除 Pkcs12UnspecifiedPasswordIterationLimit 的 reg 值。

reg delete "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /reg:32
reg delete "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /reg:64

Windows 專屬備註

在 Windows 上,.NET Framework 透過 PFXImportCertStore 函式匯入憑證。 此函式自行驗證,包括對 PFX blob 最大允許迭代次數設置限制。 這些檢查在 PFX 匯入時仍會進行。 該 .上述 NET 特定的環境變數與登錄鍵不會影響 PFXImportCertStore 執行這些檢查的方式。