「在线资格确认终端更换时,把客户端证书重新导入新电脑后就连不上了」「开发机上能连上银行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:\CurrentUser与Cert:\LocalMachine。34 - 放入哪个存储由「使用该证书的程序以谁的身份运行」决定。面向交互式用户的应用放用户存储,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 的证书放进计算机存储的「受信任的根证书颁发机构」,那么所有用户的「受信任的根证书颁发机构」中也会出现这张证书。反过来说,唯独「个人」存储不会被继承,因此客户端证书(也就是放入个人存储的证书)需要自己决定「应该让谁能看到」。这种不对称性,正是本文通篇的主题。
flowchart TB
subgraph LM["计算机 LocalMachine<br/>每台电脑一份,所有用户和服务共用"]
LMMY["个人 My"]
LMROOT["受信任的根证书颁发机构 Root"]
LMCA["中间证书颁发机构 CA"]
LMTP["受信任的发布者 TrustedPublisher"]
end
subgraph CU["用户 CurrentUser<br/>按账户各自独立"]
CUMY["个人 My<br/>不会被继承,需自行决定放入位置"]
CUROOT["受信任的根证书颁发机构 Root"]
CUCA["中间证书颁发机构 CA"]
CUTP["受信任的发布者 TrustedPublisher"]
end
LMROOT -.->|"继承并显示内容"| CUROOT
LMCA -.->|"继承"| CUCA
LMTP -.->|"继承"| CUTP
2.2. 主要的逻辑存储
各个位置内部又按用途分为不同的逻辑存储。这些就是在 certmgr.msc / certlm.msc 中看到的文件夹,从 PowerShell 或命令行查看时使用英文内部名称。24
| 显示名称 | 内部名称 | 用于存放什么 |
|---|---|---|
| 个人 | My | 自己(本机、本用户)使用的证书。客户端证书、服务器证书都放在这里,与私钥关联的也是这里 |
| 受信任的根证书颁发机构 | Root | 作为信任起点的根 CA 证书。放入这里的 CA 及其下级都会被「信任」 |
| 中间证书颁发机构 | CA | 连接根与末端之间的中间 CA 证书,是构建证书链的素材 |
| 受信任的发布者 | TrustedPublisher | 作为已签名软件发布者而信任的证书(第 8 章) |
2.3. 三个窗口 ── certmgr.msc / certlm.msc / Cert: 驱动器
- 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. 常见事故剖析 ── 「开发阶段能用,改成服务后就找不到证书」
这类事故可以按下面的步骤精确复现。
- 开发者在自己的电脑上双击 pfx 进行导入。由于向导默认选择「当前用户」,证书便进入了开发者账户的用户存储。
- 开发中的应用从 Visual Studio 启动,也就是以开发者账户运行,因此打开
StoreLocation.CurrentUser就能找到证书——能用。 - 在生产服务器上把它注册为 Windows 服务。服务以 NETWORK SERVICE 或专用账户运行。
- 服务代码打开的
CurrentUser,是服务运行账户的用户存储,那里是空的——「找不到证书」。
flowchart TB
subgraph DEV["开发机"]
D1["双击 pfx 进行导入<br/>向导默认选择「当前用户」"] --> D2["进入开发者账户的<br/>用户存储"]
D2 --> D3["从 Visual Studio 运行<br/>=以开发者账户运行"]
D3 --> D4["打开 CurrentUser 即可找到<br/>→ 能用"]
end
subgraph PROD["生产服务器"]
P1["注册为 Windows 服务<br/>运行账户为 NETWORK SERVICE 等"] --> P2["代码打开的 CurrentUser 是<br/>服务账户的用户存储"]
P2 --> P3["那里是空的<br/>→「找不到证书」"]
end
D4 -.->|"部署相同的程序"| P1
关键在于,用户存储「有多少账户,就有多少份」。即便管理员打开 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
- 打开 certlm.msc(或以计算机账户为对象的证书管理单元)。
- 在「个人」→「证书」中右键点击目标证书,从「所有任务」打开「管理私钥」。
- 在「安全」标签页中添加运行账户(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. 更换步骤 ── 新旧并行期间与指纹陷阱
证书的更新不是「先删除再放入」,而是「先添加再切换,确认无误后再删除」。
- 把新证书(pfx)导入到同一存储。由于指纹不同,新旧证书可以在同一存储中共存。
- 为新证书授予私钥权限(第 4 章)。更新时最容易忘记的就是这一步。权限是按证书的私钥各自设置的,所以更换证书后授权也要重新做一遍。
- 在继续用旧证书运行的同时,先完成向对方系统的申报(针对需要证书事前登记的 API),确保有一段新旧证书都能被接受的并行期间。如果先切换再申报,对方可能拒绝新证书,导致生产环境的通信中断。
- 把应用的配置切换到新证书,并验证运行情况。
- 经过足够长的一段时间后,删除旧证书。
flowchart LR
I["1. 把新 pfx 导入到<br/>同一存储 - 新旧共存"] --> P["2. 为新证书<br/>授予私钥权限"]
P --> R["3. 向对方事先登记<br/>- 继续用旧证书运行"]
R --> SW["4. 改写配置中的指纹<br/>并切换、验证"]
SW --> DEL["5. 并行期间结束后<br/>删除旧证书"]
此时最大的陷阱,是写在配置文件或代码里的指纹。指纹对每个证书都是唯一的,更新之后必定会变化。哪怕只有一处仍引用旧指纹,就会出现「证书明明更新了却连不上」的情况。用台账管理指纹被写在哪些地方(应用配置、IIS 绑定、脚本、对合作方的申报),是最可靠的做法。
5.3. 建议建立证书台账
所谓台账,一开始一张 Excel 表就够了。至少要建立用途 / 颁发者 / 使用者主体 / 指纹 / 存放位置(服务器名 + 存储)/ 拥有私钥权限的账户 / 有效期 / 更新步骤链接 / 负责人这些列,并与 5.1 的盘点结果进行核对。证书事故的实质并不是技术问题,而是「没有人掌握完整清单」的问题,所以台账最见效。
6. 验证与解读故障 ── 证书链与根证书分发
6.1. 证书链验证基础与 certutil
「此证书不受信任」类的错误,是从末端证书到根 CA 之间的证书链(信任路径)在某处断裂的状态。排查时 certutil 很好用。7
flowchart TB
LEAF["末端证书<br/>客户端证书、服务器证书"] --> INT["中间 CA 证书<br/>存放位置 - 中间证书颁发机构 CA 存储"]
INT --> ROOT["根 CA 证书<br/>存放位置 - 受信任的根证书颁发机构 Root"]
INT -.->|"无法取得<br/>提示、AIA、存储均未找到"| E1["无法构建证书链<br/>常见原因 1"]
ROOT -.->|"未被分发"| E2["「不受信任」错误<br/>常见原因 2"]
LEAF -.->|"已过期"| E3["有效期错误<br/>常见原因 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 分发,把自签名证书放入根存储的做法应仅限验证环境并设定有效期。 - 代码层面把指纹外置到配置中,并将选中的证书记入日志。仅凭这一点,证书引发的故障处理就会大不相同。
相关文章
- Windows出现“Windows 已保护你的电脑”提示的原因
- Windows 应用程序不要把敏感信息以明文存进配置文件的最佳实践
- PowerShell 中凭据的安全处理方式 ── 把明文密码逐出脚本
- 不要用 using 包裹 HttpClient —— C# 业务应用的 HTTP 通信实务(创建模式・超时设计・重试)
- 刷个人编号保险证(マイナ保険証)会发生什么 ── 从ORCA源代码解读在线资格确认与诊疗报酬结算系统(レセコン)的联动
相关咨询领域
合同会社小村软件承接嵌入客户端证书的 Web API 联动(银行系 API、在线资格确认等)的业务应用开发,「找不到证书」「更新后无法连接」类故障的排查,以及证书更换步骤的整理完善等工作。哪怕您目前只处于「不知道该看存储的哪个位置」这个阶段,也欢迎咨询。
参考链接
-
Microsoft Learn, Local Machine and Current User Certificate Stores. 关于计算机证书存储对该电脑而言是本地的、且为所有用户共用并位于 HKEY_LOCAL_MACHINE 下,用户证书存储按用户账户各自独立并位于 HKEY_CURRENT_USER 下,以及用户存储除「个人」存储外会继承计算机存储内容(计算机的「受信任的根证书颁发机构」中添加的证书会同样出现在各用户的同一存储中)的说明。 ↩ ↩2 ↩3 ↩4
-
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
-
Microsoft Learn, How to: View certificates with the MMC snap-in. 关于 certlm.msc 用于管理本地设备(本地计算机)证书、certmgr.msc 用于管理当前用户证书、证书管理单元的目标分为「计算机账户」「用户账户」「服务账户」三种、以及非管理员用户只能管理自己用户账户证书的说明。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, about_Certificate_Provider. 关于 PowerShell 的 Cert: 驱动器是拥有 CurrentUser 与 LocalMachine 两个存储位置的层级命名空间、可用 Get-ChildItem 列举存储与证书、-ExpiringInDays 参数会返回指定天数内到期的证书(0 则为已过期证书)、-CodeSigningCert 等动态参数、NotAfter 属性存放有效期、以及证书按指纹识别的说明。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, How to Modify Private Key Permissions to Support Management Server or Streaming Server. 关于在面向本地计算机证书存储的证书管理单元中打开「管理私钥」(Manage Private Keys),并在「安全」标签页为服务运行账户(如 Network Service)添加「读取」访问权限的步骤说明。 ↩ ↩2 ↩3
-
Microsoft Learn, Import-PfxCertificate. 关于 Import-PfxCertificate 会从 PFX 文件把证书与私钥导入指定存储、若不指定 -Exportable 开关则导入的私钥无法导出、以及 -CertStoreLocation・-Password・-FilePath 各参数的语法与使用示例的说明。 ↩ ↩2 ↩3
-
Microsoft Learn, certutil. 关于 certutil -verify 会验证证书・CRL・证书链,若不指定 CA 证书文件则会构建完整证书链并加以验证、可使用 -urlfetch 选项、以及 certutil -store 会转储证书存储、加上 -user 选项可访问用户存储而非计算机存储的说明。 ↩ ↩2
-
Microsoft Learn, Distribute Certificates to Client Computers by Using Group Policy. 关于把证书导入组策略「计算机配置\策略\Windows 设置\安全设置\公钥策略」下的「受信任的根证书颁发机构」,从而分发到域内客户端计算机的步骤,以及所需权限(相当于 Domain Admins / Enterprise Admins)的说明。 ↩
-
Microsoft Learn, Create trusted certificate profiles in Microsoft Intune. 关于 Intune 的「受信任的证书」配置文件是将根或中间 CA 证书分发到受管设备的机制、作为 SCEP/PKCS 证书配置文件建立对根 CA 信任的前提而被使用、以及在 Windows 上可选择分发到的存储为「计算机证书存储 - 根」「计算机证书存储 - 中间」「用户证书存储 - 中间」的说明。 ↩
-
Microsoft Learn, X509Store Class. 关于 X509Store 可通过指定 StoreName 与 StoreLocation(CurrentUser / LocalMachine)构造、可用 Open 方法和 OpenFlags(ReadOnly、OpenExistingOnly 等)打开存储、通过 Certificates 属性获取证书集合、标准存储名包含 My・Root・CA・TrustedPublisher 等、以及 TrustedPublisher 存储在 CurrentUser 与 LocalMachine 两处均存在的说明。 ↩ ↩2
-
Microsoft Learn, X509Certificate2Collection.Find(X509FindType, Object, Boolean) Method. 关于 Find 方法通过 X509FindType(如 FindByThumbprint)与检索值查找证书、第三个参数 validOnly 指定为 true 时只返回通过验证的有效证书的说明。 ↩ ↩2
-
Microsoft Learn, HttpClientHandler.ClientCertificates Property. 关于 ClientCertificates 属性是基于证书的客户端身份验证中提示给服务器的 X509CertificateCollection、以及在 .NET Core 中若证书存在密钥用法属性则必须包含「Digital Signature」的说明。 ↩ ↩2
相关文章
共享相同标签的最新文章。可以围绕相近的主题进一步加深理解。
Windows 防火墙与业务应用 ── 入站规则要通过安装程序注册
「开发机上正常运行,但在客户现场却无法通信」的常见原因就是 Windows 防火墙。本文讲解入站默认阻止与网络配置文件、不能把生产环境交给通知对话框处理的原因,以及通过安装程序注册入站规则的方法与排查步骤。
Windows 安全审核策略与事件日志排查实务 ── 成为看得懂 4625 的信息系统人员
这是一份用于应对「帮忙查一下登录失败日志」需求的实务指南。内容涵盖基本审核策略与高级审核策略的关系、至少应启用的子类别、事件 ID 4624/4625/4688 的解读方法、Security 日志的容量设计,直至用 Get-WinEvent 提取日志。
Windows LAPS实务指南 ── 告别全部PC通用的本地管理员密码
全部PC通用的本地管理员密码,是「一台被攻破、全部沦陷」的Pass-the-Hash攻击温床。本文讲解已成为OS标准功能的Windows LAPS如何自动轮换密码、如何配置保存到AD/Entra ID,以及运维中的常见陷阱。
SMB 签名与 LDAP 通道绑定 ── 用实务收紧 NTLM 对策的「另一半」
在停用 NTLM 之前,用来抑制中继攻击损害的防御手段就是 SMB 签名与 LDAP 签名・通道绑定。本文从实务角度整理各操作系统的默认值、审核事件的解读方法、推进到强制的步骤,直至业务应用与设备的修复方法。
NTLM 停用会导致业务应用停止运行吗 ── 审核日志的获取方法与消除依赖的顺序
围绕 NTLM 停用,本文整理了排查自身 Windows 环境与业务应用在何处依赖 NTLM 的步骤。内容涵盖审核策略、NTLM/Operational 日志中事件 8001~8004 的追踪方法、回退到 NTLM 的典型模式及修复方式,直至 SMB 的 NTLM 拦截功能。
相关主题
与本文相近的主题页面。以本文为起点,可以进一步了解相关服务和其他文章。
Windows 技术主题
汇整 KomuraSoft LLC 关于 Windows 开发、故障调查与既有资产活用文章的主题中心。
常见问题
汇总了咨询这一主题时常见的问题。
- 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 则会列出已经过期的证书。把这项操作做成按月对所有服务器执行,并把结果与证书台账核对的运维流程,就能基本防住「因证书过期,一大早就无法连接」这类事故。