使用 Microsoft 登录
登录或创建帐户。
你好,
使用其他帐户。
你有多个帐户
选择要登录的帐户。

注意: 已于 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 的验证和导入委托给基础 OS。 例如,在 Windows 上,.NET Framework和 .NET 通常依赖于 PFXImportCertStore API 进行验证和导入。

从 2023 年 6 月 13 日开始,当 .NET Framework 和 .NET 提供用于导入的二进制证书 Blob 时,.NET Framework 和 .NET 在某些情况下将执行其他验证,然后再将 blob 交给基础 OS。 此附加验证执行一系列启发式检查,以确定传入的证书是否会在导入时恶意耗尽资源。 由于 这是基础 OS 通常执行的其他验证,因此可能会阻止在 2023 年 6 月 13 日更改之前成功导入的证书 Blob。

已知回归

  1. 如果 X.509 证书已导出为 PFX Blob,并且密码迭代计数异常高,该证书现在可能无法导入。 大多数证书导出设施使用介于 2,000 到 10,000 之间的迭代计数。 应用安全更新后,对于迭代计数大于 600,000 的证书,导入将失败。

  2. 如果 X.509 证书已使用密码 [例如,通过X509Certificate.Export(X509ContentType.Pfx, (string)null)或无密码X509Certificate.Export(X509ContentType.Pfx)]导出,则该证书现在可能无法导入。
     

    注意: 上述回归已在 KB5028608 中讨论的 2023 年 6 月 22 日更新中得到解决。

  3. 如果使用 Windows 保护 SID 私钥的功能将 X.509 证书导出为 PFX Blob,该证书现在可能无法导入。 这将影响以以下方式创建的 PFX Blob:

    • 通过 Windows 的 证书导出向导 并在向导中指定应保护域用户的私钥;或

    • 通过 PowerShell 的 Export-PfxCertificate cmdlet,其中提供了显式 -ProtectTo 参数;或

    • 通过 certutil 实用工具,其中提供了显式 -protectto 参数;或

    • 通过 PFXExportCertStoreEx API,其中提供了 PKCS12_PROTECT_TO_DOMAIN_SIDS 标志。

解决方法&解决方法

存在各种解决方法,具体取决于是要在代码中的单个调用站点上进行有针对性的更改,还是要更改单个应用程序的行为,或者要进行计算机范围的更改。

选项 1 (首选) - 安装更新的修补程序

注意: 这是首选选项,因为它解决了经常报告的客户回归问题,并且不需要对应用程序进行任何代码更改。

适用性:此选项适用于所有版本的 .NET Framework 和 .NET。

此问题已在 KB5028608 中讨论的 2023 年 6 月 22 日更新中得到解决。

Microsoft 建议遇到 2023 年 6 月 13 日版本引入的回归的客户先尝试安装此更新的修补程序,然后再尝试本文档后面列出的解决方法。

选项 2 - 修改呼叫站点

适用性:此选项适用于所有版本的 .NET Framework 和 .NET。

考虑要导入的 Blob 是否可信。 例如,Blob 是从受信任的位置(如受你控制的数据库或配置文件)检索的,还是通过未经身份验证或未经特权的客户端发出的网络请求提供的?

Microsoft 强烈建议不要导入未经身份验证或未经特权的客户端提供的 PFX Blob,因为这些 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 日安全版本执行的其他验证检查。 例如,可以调用构造函数重载,该重载接受字符串密码参数,并为参数值传递 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);

选项 3 - 使用环境变量修改或取消附加验证

适用性:此选项仅适用于.NET Framework的所有版本。  它不适用于 .NET 6.0+。

虽然.NET Framework默认将导入操作限制为密码的迭代次数不超过 600,000 次,但可以使用环境变量在应用范围或计算机范围内配置此限制。 此新限制将应用于上面列出的受影响的 API 的所有调用。

若要更改限制,请将环境变量COMPlus_Pkcs12UnspecifiedPasswordIterationLimit设置为新限制的值。 例如,若要将限制设置为 1,000,000 (100 万次) 迭代,请将环境变量设置为如下所示。

  • 此数字控制 迭代限制,即 MAC 迭代计数、加密的安全内容和掩码包的迭代计数的总和。 如果已使用显式迭代计数<iter_count> (手动导出 PFX,例如,通过 openssl pkcs12 -export -iter <iter_count>) 并希望导入该 PFX Blob,请将此环境变量设置为至少与所有预期迭代的总和相同的值。 实际上,.NET Framework和 .NET 可能允许总迭代计数略高于此处配置的任何显式限制。

COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=1000000

若要完全取消附加检查,请将环境变量设置为特殊 sentinel 值 -1,如下所示。

  • ⚠️ 警告:仅当确定目标应用程序未处理不受信任的证书输入时,才会将环境变量值设置为 -1。

COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=-1

选项 4 - 使用 AppContext 修改或取消附加验证

适用性:此选项仅适用于 .NET 6.0+。  它不适用于.NET Framework

虽然 .NET 默认将导入操作限制为密码的迭代次数不超过 600,000 次,但可以使用 AppContext 开关在应用程序范围内配置此限制。 此新限制将应用于上面列出的受影响的 API 的所有调用。

若要更改限制,请将 AppContext 开关 System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit 设置为新限制的值。 例如,若要将限制设置为 1,000,000 (100 万次) 迭代,请将开关设置为如下所示。

  • 此数字控制总迭代限制,即 MAC 迭代计数、加密的安全内容和掩码包的迭代计数的总和。 如果已使用显式迭代计数<iter_count> (手动导出 PFX,例如,通过 openssl pkcs12 -export -iter <iter_count>) 并希望导入该 PFX Blob,请将此环境变量设置为至少与所有预期迭代的总和相同的值。 实际上,.NET 可能允许总迭代计数略高于此处配置的任何显式限制。

若要在应用程序的项目文件 (.csproj 或 .vbproj) 中设置开关,请执行以下操作:

<!--

  • This switch only works if the current project file represents an application. It has no effect if the current project file represents a shared library.

-->

<ItemGroup>

  • <RuntimeHostConfigurationOption Include="System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit" Value="1000000" />

</ItemGroup>

或者,可以将包含以下内容的名为 runtimeconfig.template.json 的文件放在包含应用程序项目文件的同一目录中:

{

     "configProperties": {

  • "System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit": 1000000

      }

}

有关更改 .NET 运行时配置设置的详细信息,请参阅文档页 .NET 运行时配置设置

若要完全取消其他检查,请将配置开关设置为特殊 sentinel 值 -1,如下所示。

⚠️ 警告:仅当确定目标应用程序未处理不受信任的证书输入时,才会将 AppContext 开关设置为 -1。

在应用程序的项目文件 (.csproj 或 .vbproj) :

<!--

  • This switch only works if the current project file represents an application. It has no effect if the current project file represents a shared library.

-->

<ItemGroup>

  • <RuntimeHostConfigurationOption Include="System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit" Value="-1" />

</ItemGroup>

或在 runtimeconfig.template.json 文件中:

{

  • "configProperties": { 
  •     "System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit": -1

     }

}

选项 5 - 通过注册表 (仅限 Windows 来修改或取消计算机范围的附加验证.NET Framework)

适用性:此选项仅适用于.NET Framework的所有版本。  它不适用于 .NET 6.0+。

虽然.NET Framework默认将导入操作限制为密码的迭代次数不超过 600,000 次,但可以使用 HKLM 注册表在计算机范围内配置此限制。 此新限制将应用于上面列出的受影响的 API 的所有调用。

若要更改限制,请在注册表项HKLM\Software\Microsoft\.NETFramework下,将Pkcs12UnspecifiedPasswordIterationLimit的值设置为新的限制。 例如,若要将限制设置为 1,000,000 (100 万次) 迭代,请在提升的命令提示符中运行如下所示的命令。

  • 此数字控制 迭代限制,即 MAC 迭代计数、加密的安全内容和掩码包的迭代计数的总和。 如果已使用显式迭代计数<iter_count> (手动导出 PFX,例如,通过 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 sentinel,请使用 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 执行这些检查的方式。

需要更多帮助?

需要更多选项?

了解订阅权益、浏览培训课程、了解如何保护设备等。

社区可帮助你提出和回答问题、提供反馈,并听取经验丰富专家的意见。

此信息是否有帮助?

你对语言质量的满意程度如何?
哪些因素影响了你的体验?
按“提交”即表示你的反馈将用于改进 Microsoft 产品和服务。 你的 IT 管理员将能够收集此数据。 隐私声明。

谢谢您的反馈!

×