Windows 10 版本 2004 及更低版本的 2020 年 11 月累积更新预览版以及适用于 .NET Framework 4.8 的 2021 年 1 月安全和质量汇总版本发布了一项更改,用于改进 X509Certificate2 证书的清理过程。 下面,我们提供了有关 Windows 上的私钥生存期的其他说明。
自 .NET Framework 2.0 以来,有两种不同的方法可以从 PKCS#12 PFX 文件加载证书及其关联的私钥:作为一个证书对象,通过 X509Certificate2 类的成员,或者作为 PFX 中存在的所有证书通过 X509Certificate2Collection.Import 方法。
默认行为是通过系统加密库之一将私钥加载到名为) 密钥的持久化 (,后者间接将文件写入磁盘。 加载 PFX 的大多数调用方仅暂时使用证书对象,因此,当 .NET 释放与证书关联的本机资源时,也会删除私钥。 此行为的main异常是
-
X509KeyStorageFlags.PersistKeySet 标志,这会导致文件被写入但未删除,
-
X509KeyStorageFlags.EphemeralKetSet 标志,这会导致私钥加载到内存中,而没有后备文件,
-
异常进程终止,在密钥删除挂起时可能发生。
相反,加载证书的两种不同方式在删除私钥的适当时间时始终使用不同的跟踪机制。 通过 X509Certificate2 类加载单个证书使用仅对 .NET 运行时可见且仅适用于该对象引用的标记。 通过 X509Certificate2Collection.Import 加载 PFX 将使用本机证书对象的标记,这会导致“删除责任”在表示相同本机证书的任何托管对象之间共享。 这意味着新的 X509Certificate2 (otherCert.Handle) 。如果通过 X509Certificate2Collection.Import 从 PFX 加载 otherCert,则 Dispose () 将导致在调用 Dispose () 期间清除私钥文件,但如果通过任何 X509Certificate2 类成员从 PFX 加载该私钥文件,则不会清除该文件。 .NET 的某些部分从本机证书句柄内部创建新的托管 X509Certificate2 对象,例如 X509Chain 类和 X509Certificate2Collection.Find 方法。 框架的这些部分以及直接或间接使用它们的任何部分都可能导致过早的键擦除,因为它们创建的对象被垃圾回收。
.NET Framework 4.8 的初始版本中引入了一个 bug,导致 X509Certificate2Collection.Import 不应用删除标记,即使未指定 PersistKeySet 和 EphemeralKeySet 也是如此。 .NET 在 2021 年 1 月安全和质量汇总中 发布了针对此 bug 的修补程序,以防止意外累积已放弃的私钥文件。 受此修复影响的调用方可以指定 PersistKeySet 标志以返回 (无意中不同的) .NET Framework 4.8 RTM 行为,但这样做将导致文件累积,需要使用自定义清理逻辑来解决。
适用于 Windows 的 .NET Core 和适用于 Windows 的 .NET 5+ 上的 X509Certificate2Collection.Import 的行为方式与 .NET Framework 2.0-4.7.2 (和 .NET Framework 4.8 相同,所有更新都) 应用。 .NET 团队正在考虑将 .NET 6 (或未来版本中的改进设计) ,但此设计更新不适用于 .NET Framework、.NET Core 或 .NET 5。