Windows证书存储实务指南 ── 应该放入用户存储还是计算机存储

· · 证书, Windows, 安全, PKI, TLS, PowerShell, 业务应用, 信息系统

「在线资格确认终端更换时,把客户端证书重新导入新电脑后就连不上了」「开发机上能连上银行API,一改成 Windows 服务就提示『找不到证书』」「说到底,certmgr.msc 里看到的证书和 certlm.msc 里看到的证书,哪个才是真的都搞不清楚」──在承接带客户端证书的 Web API 联动开发工作时,这类咨询会定期出现。

医疗机构的在线资格确认、电子申请、银行系 API、与合作伙伴之间的 EDI——过去只有大企业基础设施部门才会接触的客户端证书,如今中小企业的信息系统负责人和业务应用开发者也要经手。而与证书相关的事故,其实可以归结为寥寥几种模式。放错位置、忘记授予私钥权限、忘记有效期──就是这三种。

本文面向使用客户端证书的业务应用开发者,以及负责证书更换工作的信息系统负责人,以「应该放入用户存储还是计算机存储」这一判断为主线,从 Windows 证书存储的结构、私钥的权限授予、PowerShell 的到期日盘点,到 .NET 中的使用代码,一次性系统梳理。内容基于 2026 年 8 月时点 Microsoft Learn 的一手资料。

1. 先说结论

  • Windows 的证书存储分为「用户(CurrentUser)」和「计算机(LocalMachine)」两大系统。用户存储按账户各自独立(位于注册表 HKEY_CURRENT_USER 下),计算机存储则是整台电脑共用(位于 HKEY_LOCAL_MACHINE 下)。12
  • 管理工具也有两个。certmgr.msc 打开当前用户的存储,certlm.msc 打开本地计算机的存储。在 PowerShell 中则分别对应 Cert:\CurrentUserCert:\LocalMachine34
  • 放入哪个存储由「使用该证书的程序以谁的身份运行」决定。面向交互式用户的应用放用户存储,Windows 服务、IIS、任务计划程序等无人值守运行的程序原则上放计算机存储(第 3 章的判断表)。
  • 「开发阶段能用,改成服务后就找不到证书」的原因几乎只有一个。开发者放入自己用户存储的证书,服务以其他账户运行时打开的 CurrentUser 是看不到的(第 3 章)。
  • 证书和私钥是两码事。仅仅放入计算机存储,服务账户通常仍然无法读取私钥。需要在 certlm.msc 的「管理私钥」中为运行账户授予读取权限。5
  • 导入 pfx 时,私钥默认不可导出。Import-PfxCertificate 在不指定 -Exportable 的情况下,会以无法再次导出私钥的形式导入。这不是缺陷,而是理想的默认行为。6
  • 到期问题靠盘点自动化来防范。例如 Get-ChildItem Cert:\LocalMachine\My -ExpiringInDays 60,可以机械地筛选出在指定天数内到期的证书。4
  • 把指纹(拇指印)硬编码进代码或配置,每次更新证书都会出问题。因为新证书的指纹必定会变化。把指纹外置到配置中,并设置新旧并行期间,是设计的基本原则(第 5 章、第 7 章)。

2. 证书存储的全貌 ── 两个位置与逻辑存储

2.1. 用户与计算机两大系统

Windows 的证书存储大致分为两个「位置」。1

  • 计算机(本地计算机,LocalMachine)证书存储:每台电脑只有一份,供该电脑上的所有用户和服务共用。其实体位于注册表 HKEY_LOCAL_MACHINE\Software\Microsoft\SystemCertificates 下。2
  • 用户(当前用户,CurrentUser)证书存储按用户账户各自独立。其实体位于 HKEY_CURRENT_USER\Software\Microsoft\SystemCertificates 下,也就是用户配置文件的一部分。2

此外还存在按服务账户划分的存储3,其实体是按服务名区分的注册表项。2 实务中首先要掌握的是前面这两个。

有一条重要规则需要注意。用户存储下的各逻辑存储,除了「个人」以外,都会继承显示计算机存储中同名存储的内容。1 例如把内部 CA 的证书放进计算机存储的「受信任的根证书颁发机构」,那么所有用户的「受信任的根证书颁发机构」中也会出现这张证书。反过来说,唯独「个人」存储不会被继承,因此客户端证书(也就是放入个人存储的证书)需要自己决定「应该让谁能看到」。这种不对称性,正是本文通篇的主题。

用户 CurrentUser按账户各自独立计算机 LocalMachine每台电脑一份,所有用户和服务共用继承并显示内容继承继承个人 My不会被继承,需自行决定放入位置受信任的根证书颁发机构 Root中间证书颁发机构 CA受信任的发布者 TrustedPublisher个人 My受信任的根证书颁发机构 Root中间证书颁发机构 CA受信任的发布者 TrustedPublisher

2.2. 主要的逻辑存储

各个位置内部又按用途分为不同的逻辑存储。这些就是在 certmgr.msc / certlm.msc 中看到的文件夹,从 PowerShell 或命令行查看时使用英文内部名称。24

显示名称 内部名称 用于存放什么
个人 My 自己(本机、本用户)使用的证书。客户端证书、服务器证书都放在这里,与私钥关联的也是这里
受信任的根证书颁发机构 Root 作为信任起点的根 CA 证书。放入这里的 CA 及其下级都会被「信任」
中间证书颁发机构 CA 连接根与末端之间的中间 CA 证书,是构建证书链的素材
受信任的发布者 TrustedPublisher 作为已签名软件发布者而信任的证书(第 8 章)

2.3. 三个窗口 ── certmgr.msc / certlm.msc / Cert: 驱动器

查看同一存储的方式有三种。34

  • certmgr.msc:打开当前用户存储的管理控制台。
  • certlm.msc:打开本地计算机存储的管理控制台。
  • PowerShell 的 Cert: 驱动器:可以像操作文件系统一样,在 Cert:\CurrentUser\...Cert:\LocalMachine\... 的层级结构下操作存储。证书以指纹进行识别。

另外,手动向 mmc.exe 添加证书管理单元时,需要从「用户账户」「计算机账户」「服务账户」三种类型中选择目标。非管理员用户只能管理自己用户账户的存储。3

排查故障的第一步,是让「应用查看的是哪个存储」与「自己正在查看的是哪个存储」保持一致。一边盯着 certmgr.msc 一边调查服务的故障,由于看的地方不同,永远也得不出答案。

3. 应该放入哪个存储 ── 按程序的运行形态判断

判断标准只有一个:使用该证书的程序,是以谁的账户运行的。

运行形态 运行账户 应放入的存储 备注
交互式用户启动的桌面应用 登录用户本人 用户(Cert:\CurrentUser\My) 需要按使用者的账户分别导入。若共享电脑由多人使用,也可以考虑计算机存储
Windows 服务 LocalSystem / NETWORK SERVICE / 专用服务账户 计算机(Cert:\LocalMachine\My) 除 LocalSystem 以外(NETWORK SERVICE、专用账户等)必须授予私钥读取权限(第 4 章)。LocalSystem 凭默认的 SYSTEM 权限即可读取
IIS 上的 Web 应用 应用程序池的标识 计算机 同上
任务计划程序的无人值守运行(无论用户是否登录都执行) 任务中指定的账户 建议计算机 也可以用运行账户的用户存储来运行,但只会增加配置文件和存储可见性方面的验证工作,好处有限
浏览器中的电子申请、Web 身份验证 登录用户本人 用户 从「不让被分发者本人以外的人使用」的角度看也很自然

拿不准时,无人运行的放计算机存储,由人操作的放用户存储。

3.1. 常见事故剖析 ── 「开发阶段能用,改成服务后就找不到证书」

这类事故可以按下面的步骤精确复现。

  1. 开发者在自己的电脑上双击 pfx 进行导入。由于向导默认选择「当前用户」,证书便进入了开发者账户的用户存储。
  2. 开发中的应用从 Visual Studio 启动,也就是以开发者账户运行,因此打开 StoreLocation.CurrentUser 就能找到证书——能用。
  3. 在生产服务器上把它注册为 Windows 服务。服务以 NETWORK SERVICE 或专用账户运行。
  4. 服务代码打开的 CurrentUser,是服务运行账户的用户存储,那里是空的——「找不到证书」。
生产服务器开发机部署相同的程序代码打开的 CurrentUser 是服务账户的用户存储注册为 Windows 服务运行账户为 NETWORK SERVICE 等那里是空的→「找不到证书」进入开发者账户的用户存储双击 pfx 进行导入向导默认选择「当前用户」从 Visual Studio 运行=以开发者账户运行打开 CurrentUser 即可找到→ 能用

关键在于,用户存储「有多少账户,就有多少份」。即便管理员打开 certmgr.msc 确认「明明已经放进去了?」,那也只是管理员自己的存储,而不是服务账户的存储。正确的应对不是临时复制了事,而是重新放入计算机存储,并把代码也统一改为 StoreLocation.LocalMachine。而且这与下一章的权限授予是配套的一整套工作。

4. 私钥与访问权限 ── 第二大常见事故

4.1. 证书与私钥是两码事

证书存储列表中看到的是证书(公开信息),而不是私钥本身。客户端身份验证实际需要的是使用私钥完成的签名处理,因此「列表中能看到」和「能用」是两回事。混淆这一点,就会遇到「明明有证书,TLS 握手却失败」「出现 Access Denied 类的内部错误」这类表面上难以理解的故障。

4.2. pfx导入实务 ── 是否可导出是一项决策

证书与私钥的配对通过 pfx(PKCS #12)文件传递,可以用 Import-PfxCertificate 导入存储。6

$pwd = Get-Credential -UserName '(在下方输入密码)' -Message 'PFX 的密码'
Import-PfxCertificate -FilePath C:\certs\client.pfx `
    -CertStoreLocation Cert:\LocalMachine\My -Password $pwd.Password

这里需要注意的重要行为是:除非指定 -Exportable,否则导入的私钥默认无法再次导出6 出于「以后方便迁移」的考虑而一律以可导出方式导入,等于给私钥多开了一条外泄途径。把原始 pfx 妥善保管,存储中的私钥以不可导出为基本原则——这是本公司的推荐做法。另外,原始 pfx 及其密码的保管,恰恰是最容易被以明文形式放任不管的地方。相关思路整理在「Windows 应用程序不要把敏感信息以明文存进配置文件的最佳实践」与「PowerShell 中凭据的安全处理方式 ── 把明文密码逐出脚本」中。

4.3. 向服务账户授予私钥权限

放入计算机存储的证书私钥,默认情况下通常只有管理员和 SYSTEM 才能读取。因此,以 LocalSystem 运行的服务在默认状态下就能读取私钥,但如果以 NETWORK SERVICE、专用服务账户、IIS 应用程序池标识等其他账户运行,就需要向运行账户明确授予读取权限。操作可以通过证书管理单元的界面完成。5

  1. 打开 certlm.msc(或以计算机账户为对象的证书管理单元)。
  2. 在「个人」→「证书」中右键点击目标证书,从「所有任务」打开「管理私钥」
  3. 在「安全」标签页中添加运行账户(NETWORK SERVICE、专用服务账户、IIS 的应用程序池标识等),并允许「读取」5

不需要完全控制。只是用于签名的话,读取权限就足够了。反过来,因为「不生效」就把完全控制授予 Everyone,等于把私钥降格为和明文密码同等的待遇,请务必避免。放入计算机存储与授予私钥权限,永远是配套的一整套操作——只要把这一点写进操作手册,这类事故就会消失。

5. 防止到期事故 ── 盘点、更换、台账

5.1. 用 PowerShell 盘点

证书的有效期存放在 NotAfter 属性中。对 Cert: 驱动器执行 Get-ChildItem,就能机械地进行盘点。4

# 按有效期顺序列出计算机存储的「个人」存储
Get-ChildItem Cert:\LocalMachine\My |
    Sort-Object NotAfter |
    Format-Table Thumbprint, Subject, NotAfter

# 只提取 60 天内到期的证书(指定 0 则列出已过期的证书)
Get-ChildItem -Path Cert:\LocalMachine\My -ExpiringInDays 60

-ExpiringInDays 是返回「在指定天数内到期的证书」的参数,指定 0 则会列出已经过期的证书。4 把它做成按月执行的计划任务,遍历所有服务器,再把结果汇总到邮件或台账中──光是这样,就能基本防住「因证书过期,周一早上开始资格确认就无法通过」这类事故。

5.2. 更换步骤 ── 新旧并行期间与指纹陷阱

证书的更新不是「先删除再放入」,而是「先添加再切换,确认无误后再删除」。

  1. 把新证书(pfx)导入到同一存储。由于指纹不同,新旧证书可以在同一存储中共存。
  2. 为新证书授予私钥权限(第 4 章)。更新时最容易忘记的就是这一步。权限是按证书的私钥各自设置的,所以更换证书后授权也要重新做一遍。
  3. 继续用旧证书运行的同时,先完成向对方系统的申报(针对需要证书事前登记的 API),确保有一段新旧证书都能被接受的并行期间。如果先切换再申报,对方可能拒绝新证书,导致生产环境的通信中断。
  4. 把应用的配置切换到新证书,并验证运行情况。
  5. 经过足够长的一段时间后,删除旧证书。
1. 把新 pfx 导入到同一存储 - 新旧共存2. 为新证书授予私钥权限3. 向对方事先登记- 继续用旧证书运行4. 改写配置中的指纹并切换、验证5. 并行期间结束后删除旧证书

此时最大的陷阱,是写在配置文件或代码里的指纹。指纹对每个证书都是唯一的,更新之后必定会变化。哪怕只有一处仍引用旧指纹,就会出现「证书明明更新了却连不上」的情况。用台账管理指纹被写在哪些地方(应用配置、IIS 绑定、脚本、对合作方的申报),是最可靠的做法。

5.3. 建议建立证书台账

所谓台账,一开始一张 Excel 表就够了。至少要建立用途 / 颁发者 / 使用者主体 / 指纹 / 存放位置(服务器名 + 存储)/ 拥有私钥权限的账户 / 有效期 / 更新步骤链接 / 负责人这些列,并与 5.1 的盘点结果进行核对。证书事故的实质并不是技术问题,而是「没有人掌握完整清单」的问题,所以台账最见效。

6. 验证与解读故障 ── 证书链与根证书分发

6.1. 证书链验证基础与 certutil

「此证书不受信任」类的错误,是从末端证书到根 CA 之间的证书链(信任路径)在某处断裂的状态。排查时 certutil 很好用。7

无法取得提示、AIA、存储均未找到未被分发已过期末端证书客户端证书、服务器证书中间 CA 证书存放位置 - 中间证书颁发机构 CA 存储根 CA 证书存放位置 - 受信任的根证书颁发机构 Root无法构建证书链常见原因 1「不受信任」错误常见原因 2有效期错误常见原因 3
:: 构建并验证证书文件的证书链(附带获取吊销确认用的 URL)
certutil -urlfetch -verify client.cer

:: 若目标应用使用用户存储,加上 -user 以相同上下文进行验证
certutil -user -urlfetch -verify client.cer

:: 转储存储中的内容(加上 -user 则为用户存储)
certutil -store My
certutil -user -store My

certutil -verify 会验证证书、CRL 和证书链,如果不指定 CACertFile,就会构建完整的证书链并加以验证。7 输出内容较长,但可以从中读出信任在哪一层断裂、以及是否取得了吊销信息。典型原因有三个:(1)无法取得中间 CA 证书(TLS 对方没有发送,从证书的 AIA 信息中也取不到,「中间证书颁发机构」存储中也没有放入);(2)内部 CA 的根证书没有分发到「受信任的根证书颁发机构」;(3)证书本身已过期。由于中间 CA 也可以通过对方提示或经由 AIA 自动获取来解决,因此把证书放入存储只能算是「确保成功的手段之一」。

6.2. 内部 CA、自签名证书的根证书分发用 GPO/Intune

使用内部 CA 或用于验证目的的自签名证书时,需要把其根证书分发到各台电脑。不应逐台手动导入,而应纳入统一的分发机制。

  • Active Directory 环境(GPO):把证书导入组策略中「计算机配置\策略\Windows 设置\安全设置\公钥策略」下的「受信任的根证书颁发机构」,就会分发到目标电脑。8
  • Intune 管理的环境:通过「受信任的证书」配置文件分发根/中间 CA 证书。在 Windows 上可以选择分发到的存储(计算机的根/中间、用户的中间)。9

正如 2.1 所述,放入计算机存储的根证书会被所有用户信任。1 正因如此,也请正视其反面的风险。把自签名证书放入「受信任的根证书颁发机构」的做法,等于在那台电脑上植入了一个新的信任起点。一旦其私钥泄露,就会成为签发冒充任意网站或软件的证书的立足点。若要长期运行,正确做法是搭建妥善保护私钥的内部 CA,或改用公共 CA 颁发的证书;自签名根证书应遵循「仅限验证环境使用、设定有效期」的原则。

7. 开发者视角 ── 在 .NET 中正确使用证书存储

7.1. 用 X509Store 按指纹检索

.NET 中通过 X509Store 打开存储,用 Find 获取证书。1011

using System.Security.Cryptography.X509Certificates;

static X509Certificate2 GetClientCertificate(string thumbprint)
{
    using var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
    store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

    var found = store.Certificates.Find(
        X509FindType.FindByThumbprint, thumbprint, validOnly: true);

    if (found.Count == 0)
        throw new InvalidOperationException(
            $"找不到证书: 指纹={thumbprint}, " +
            $"位置={store.Location}\\{store.Name}");

    var cert = found[0];
    if (!cert.HasPrivateKey)
        throw new InvalidOperationException(
            $"证书存在但未关联私钥(可能是从 .cer" +
            $"导入等原因): 指纹={thumbprint}, 位置={store.Location}\\{store.Name}");

    return cert;
}

第 3 章的判断在这里直接体现出来:服务中运行的代码用 StoreLocation.LocalMachine,交互式应用用 StoreLocation.CurrentUser。另外还要留意 Find 的第三个参数 validOnly。设为 true只会返回通过验证的有效证书11 这一方面能保证不会取到过期证书,另一方面,证书链不受信任的测试用自签名证书也会被判定为「找不到」,所以「明明放进去了却找不到」时,这里也要怀疑一下。此外,在找不到证书时的错误消息中,务必像上面的示例那样写明查找了哪个存储。这会让第 3 章那类事故的排查时间产生数量级的差异。

7.2. 把客户端证书装载到 HttpClient

获取到的证书,添加到 HttpClientHandler.ClientCertificates 中即可提示给服务器。这个集合就是基于证书的客户端身份验证中,提示给服务器的证书集合。12

var handler = new HttpClientHandler();
handler.ClientCertificates.Add(GetClientCertificate(thumbprint));

var client = new HttpClient(handler);
// 之后按普通的 HttpClient 使用即可

另外需要注意,在 .NET Core 系列中,文档明确指出:如果证书带有密钥用法(Key Usage)属性,若其中不包含「Digital Signature」,该证书就不会被用于请求发送。12 如果你处于申请签发客户端证书的一方,请务必正确传达用途(客户端身份验证)。另外,HttpClient 如果创建模式用错,会引发套接字耗尽、DNS 追踪失效等问题。把处理程序连同一起设计成长生命周期的做法,正如「不要用 using 包裹 HttpClient —— C# 业务应用的 HTTP 通信实务(创建模式・超时设计・重试)」一文所述。

7.3. 硬编码的指纹在更换证书时会出问题

按指纹检索虽然可靠,但把指纹嵌入代码,会导致每次更新证书都需要重新构建和发布。在设计层面,应对办法分为以下三个阶段。

  • 最低限度:把指纹外置到配置文件(appsettings 等)中,做到无需发布即可替换。配置所在位置记入 5.3 的台账。
  • 进一步:按使用者主体名或颁发者进行检索,并结合 validOnly: true,从「该名称下当前有效的证书」中选出 NotAfter 最靠后的那一个。这样在新旧并行期间会自动切换到新证书。不过存在意外获取到同名证书的风险,因此应把颁发者校验和日志输出配套使用。此外,这种自动切换只有在对方不需要证书事前登记时才成立。对于需要事前登记的 API(5.2),可能会擅自切换到仅仅导入、尚未登记的证书,导致通信中断,因此应保持配置外置方式,确认登记完成后再手动切换。
  • 靠运维收尾:无论采用哪种方式,都要在启动时把「选中了哪个证书(指纹、有效期)」记入日志。无论是故障排查还是与台账核对,这一行日志都很管用。

8. 与代码签名证书的关系 ── 「受信任的发布者」存储

到目前为止讨论的都是用于通信(TLS)的证书,但证书存储中还共存着另一个世界──代码签名。2.2 表格中出现的「受信任的发布者(TrustedPublisher)」存储正是两者的交汇点,用于把已签名软件的发布者证书登记为受信任。它同时存在于用户和计算机两个位置10,常见于通过 GPO 把内部分发应用的发布者证书配置到各电脑的 TrustedPublisher 这类运维场景。

作为应用的「分发方」,如果需要处理代码签名或 SmartScreen 警告(「Windows 已保护你的电脑」),可以参考另一篇文章「Windows出现“Windows 已保护你的电脑”提示的原因」中的整理。本文的知识(存储的两大系统、根证书分发)可以直接作为其前提知识使用。

9. 总结

  • 证书存储分为用户(CurrentUser)和计算机(LocalMachine)两大系统。certmgr.msc / certlm.msc / Cert: 驱动器是查看同一事物的三个窗口。排查故障的第一步是先统一「在讨论哪个存储」。
  • 放入的位置由「程序以谁的身份运行」决定。无人运行(服务、IIS、任务)原则上放计算机存储,交互式应用放用户存储。
  • 「开发阶段能用,生产环境找不到」的原因,是开发者的用户存储与服务账户的用户存储互不相同。统一为计算机存储 + StoreLocation.LocalMachine 即可解决。
  • 放入计算机存储与在「管理私钥」中授予读取权限是配套的一整套操作,更新时别忘了重新授权。
  • pfx 导入默认不可导出,-Exportable 只在确实需要时才使用。原始 pfx 及密码的保管也应纳入设计范围。
  • 到期问题靠 Get-ChildItem Cert: ... -ExpiringInDays 的定期盘点与证书台账来防范。更换证书按「添加→切换→确认→删除」的顺序进行,注意配置中的指纹是否有遗漏未更新的地方。
  • 排查证书链用 certutil -urlfetch -verify。内部 CA 的根证书通过 GPO/Intune 分发,把自签名证书放入根存储的做法应仅限验证环境并设定有效期。
  • 代码层面把指纹外置到配置中,并将选中的证书记入日志。仅凭这一点,证书引发的故障处理就会大不相同。

相关文章

相关咨询领域

合同会社小村软件承接嵌入客户端证书的 Web API 联动(银行系 API、在线资格确认等)的业务应用开发,「找不到证书」「更新后无法连接」类故障的排查,以及证书更换步骤的整理完善等工作。哪怕您目前只处于「不知道该看存储的哪个位置」这个阶段,也欢迎咨询。

参考链接

  1. Microsoft Learn, Local Machine and Current User Certificate Stores. 关于计算机证书存储对该电脑而言是本地的、且为所有用户共用并位于 HKEY_LOCAL_MACHINE 下,用户证书存储按用户账户各自独立并位于 HKEY_CURRENT_USER 下,以及用户存储除「个人」存储外会继承计算机存储内容(计算机的「受信任的根证书颁发机构」中添加的证书会同样出现在各用户的同一存储中)的说明。  2 3 4

  2. Microsoft Learn, System Store Locations. 关于 CERT_SYSTEM_STORE_CURRENT_USER / CERT_SYSTEM_STORE_LOCAL_MACHINE 的注册表位置(分别位于 HKEY_CURRENT_USER / HKEY_LOCAL_MACHINE 的 Software\Microsoft\SystemCertificates 下)、预定义逻辑存储为 MY・Root・Trust・CA、服务用存储位于按服务名区分的注册表项(Software\Microsoft\Cryptography\Services\ServiceName\SystemCertificates)、以及另外存在用于组策略分发的存储的说明。  2 3 4 5

  3. Microsoft Learn, How to: View certificates with the MMC snap-in. 关于 certlm.msc 用于管理本地设备(本地计算机)证书、certmgr.msc 用于管理当前用户证书、证书管理单元的目标分为「计算机账户」「用户账户」「服务账户」三种、以及非管理员用户只能管理自己用户账户证书的说明。  2 3 4

  4. Microsoft Learn, about_Certificate_Provider. 关于 PowerShell 的 Cert: 驱动器是拥有 CurrentUser 与 LocalMachine 两个存储位置的层级命名空间、可用 Get-ChildItem 列举存储与证书、-ExpiringInDays 参数会返回指定天数内到期的证书(0 则为已过期证书)、-CodeSigningCert 等动态参数、NotAfter 属性存放有效期、以及证书按指纹识别的说明。  2 3 4 5 6

  5. Microsoft Learn, How to Modify Private Key Permissions to Support Management Server or Streaming Server. 关于在面向本地计算机证书存储的证书管理单元中打开「管理私钥」(Manage Private Keys),并在「安全」标签页为服务运行账户(如 Network Service)添加「读取」访问权限的步骤说明。  2 3

  6. Microsoft Learn, Import-PfxCertificate. 关于 Import-PfxCertificate 会从 PFX 文件把证书与私钥导入指定存储、若不指定 -Exportable 开关则导入的私钥无法导出、以及 -CertStoreLocation・-Password・-FilePath 各参数的语法与使用示例的说明。  2 3

  7. Microsoft Learn, certutil. 关于 certutil -verify 会验证证书・CRL・证书链,若不指定 CA 证书文件则会构建完整证书链并加以验证、可使用 -urlfetch 选项、以及 certutil -store 会转储证书存储、加上 -user 选项可访问用户存储而非计算机存储的说明。  2

  8. Microsoft Learn, Distribute Certificates to Client Computers by Using Group Policy. 关于把证书导入组策略「计算机配置\策略\Windows 设置\安全设置\公钥策略」下的「受信任的根证书颁发机构」,从而分发到域内客户端计算机的步骤,以及所需权限(相当于 Domain Admins / Enterprise Admins)的说明。 

  9. Microsoft Learn, Create trusted certificate profiles in Microsoft Intune. 关于 Intune 的「受信任的证书」配置文件是将根或中间 CA 证书分发到受管设备的机制、作为 SCEP/PKCS 证书配置文件建立对根 CA 信任的前提而被使用、以及在 Windows 上可选择分发到的存储为「计算机证书存储 - 根」「计算机证书存储 - 中间」「用户证书存储 - 中间」的说明。 

  10. Microsoft Learn, X509Store Class. 关于 X509Store 可通过指定 StoreName 与 StoreLocation(CurrentUser / LocalMachine)构造、可用 Open 方法和 OpenFlags(ReadOnly、OpenExistingOnly 等)打开存储、通过 Certificates 属性获取证书集合、标准存储名包含 My・Root・CA・TrustedPublisher 等、以及 TrustedPublisher 存储在 CurrentUser 与 LocalMachine 两处均存在的说明。  2

  11. Microsoft Learn, X509Certificate2Collection.Find(X509FindType, Object, Boolean) Method. 关于 Find 方法通过 X509FindType(如 FindByThumbprint)与检索值查找证书、第三个参数 validOnly 指定为 true 时只返回通过验证的有效证书的说明。  2

  12. Microsoft Learn, HttpClientHandler.ClientCertificates Property. 关于 ClientCertificates 属性是基于证书的客户端身份验证中提示给服务器的 X509CertificateCollection、以及在 .NET Core 中若证书存在密钥用法属性则必须包含「Digital Signature」的说明。  2

共享相同标签的最新文章。可以围绕相近的主题进一步加深理解。

与本文相近的主题页面。以本文为起点,可以进一步了解相关服务和其他文章。

本文与以下服务页面相关联,欢迎从最接近的入口查看。

常见问题

汇总了咨询这一主题时常见的问题。

certmgr.msc 和 certlm.msc 有什么区别?
两者面向的存储不同。certmgr.msc 打开的是登录用户的证书存储(当前用户,CurrentUser),certlm.msc 打开的是计算机的证书存储(本地计算机,LocalMachine)。计算机存储是该电脑上所有用户和服务共用的,管理它需要管理员权限;非管理员用户只能管理自己的用户存储。两者内部都分为「个人」「受信任的根证书颁发机构」等逻辑存储,从 PowerShell 来看,Cert:\CurrentUser 与 Cert:\LocalMachine 呈现的是相同的结构。
客户端证书应该放入用户存储还是计算机存储?
这取决于使用该证书的程序「以谁的身份」运行。如果是由交互式用户启动的桌面应用,基本原则是放入使用者本人的用户存储(Cert:\CurrentUser\My)。如果是通过 Windows 服务、IIS 应用程序池、任务计划程序等无人值守运行的程序,则应放入计算机存储(Cert:\LocalMachine\My),并为运行账户授予私钥的读取权限。由于用户存储按账户各自独立,开发者放入自己用户存储的证书,从以其他账户运行的服务那里是看不到的。这正是「开发阶段能用,生产环境却找不到」这类事故的典型原因。
Windows服务找不到或无法使用证书时应该检查什么?
需要分两个阶段确认。第一,「正在查看的是哪个存储」——如果代码打开的是 StoreLocation.CurrentUser,那就是服务运行账户的用户存储,与管理员在 certmgr.msc 中看到的自己的存储并不是一回事。应把证书移动到计算机存储,并把代码也统一改为 StoreLocation.LocalMachine。第二,「私钥是否可读」——证书列表中能看到与能使用私钥是两回事,计算机存储中的私钥默认通常只有管理员和 SYSTEM 才能访问。请在 certlm.msc 中对目标证书打开「管理私钥」,为服务的运行账户(如 NETWORK SERVICE)授予「读取」权限。
如何用 PowerShell 提前发现证书到期?
可以对 Cert: 驱动器执行 Get-ChildItem 来进行盘点。例如执行 Get-ChildItem Cert:\LocalMachine\My | Sort-Object NotAfter | Format-Table Thumbprint, Subject, NotAfter,就能按有效期顺序列出计算机存储中的个人存储。再配合 -ExpiringInDays 参数,还能只提取「在指定天数内到期的证书」,指定 0 则会列出已经过期的证书。把这项操作做成按月对所有服务器执行,并把结果与证书台账核对的运维流程,就能基本防住「因证书过期,一大早就无法连接」这类事故。

作者简介

本文作者的个人简介页面。

Go Komura

小村软件有限公司 代表

以 Windows 软件开发、技术咨询与故障排查为中心,擅长难以复现的故障调查,以及既有资产仍在运行的项目。

返回博客列表