Windows 内网 HTTPS 自签名证书:永久信任与关闭根证书查询

内网工控机访问自签名 HTTPS 服务时,永久信任指定证书或关闭 Windows 自动根证书更新的操作方法。

在完全隔离的内网中,Windows 首次访问使用自签名证书的 HTTPS 服务时,可能因为自动根证书联网查询而等待十几秒。可通过以下两种方案解决:

  1. 将指定证书永久导入本地计算机的受信任根证书库;
  2. 关闭整台工控机的 Windows 自动根证书更新。

优先推荐方案一。


方案一:永久信任指定证书(推荐)

该方案只信任指定的内网证书,不改变系统对其他证书的处理策略,影响范围最小。

如果程序可能由 Windows 服务、开机自启账户或不同用户运行,应将证书安装到:

1
2
本地计算机
└─ 受信任的根证书颁发机构

不要只安装到“当前用户”。

1. 检查证书文件

以管理员身份打开 PowerShell:

1
2
3
$certPath = "C:\certs\intranet-server.crt"

Test-Path -LiteralPath $certPath

返回 True 后,检查证书主题、有效期和指纹:

1
certutil -dump $certPath

导入前应通过安全渠道核对证书的 SHA-256 或 SHA-1 指纹,确认该文件确实来自目标服务器。

2. 导入本地计算机根证书库

1
2
3
Import-Certificate `
    -FilePath $certPath `
    -CertStoreLocation "Cert:\LocalMachine\Root"

也可以使用:

1
certutil -addstore -f Root $certPath

3. 验证安装结果

将下面的值替换为证书的 SHA-1 指纹,不要包含空格:

1
2
3
4
5
$thumbprint = "替换为证书的SHA1指纹"

Get-ChildItem "Cert:\LocalMachine\Root" |
    Where-Object { $_.Thumbprint -eq $thumbprint } |
    Format-List Subject, Issuer, NotBefore, NotAfter, Thumbprint

安装完成后,应关闭原来的应用进程,再启动一个全新进程测试第一次 HTTPS 请求。

4. 删除当前用户中的临时证书

如果此前曾将证书临时导入 CurrentUser\Root,可删除该临时副本,只保留 LocalMachine\Root 中的正式配置:

1
2
3
Get-ChildItem "Cert:\CurrentUser\Root" |
    Where-Object { $_.Thumbprint -eq $thumbprint } |
    Remove-Item

5. 回滚永久信任

需要撤销时,只按精确指纹删除:

1
2
3
Get-ChildItem "Cert:\LocalMachine\Root" |
    Where-Object { $_.Thumbprint -eq $thumbprint } |
    Format-List Subject, Issuer, Thumbprint

确认无误后执行:

1
2
3
Get-ChildItem "Cert:\LocalMachine\Root" |
    Where-Object { $_.Thumbprint -eq $thumbprint } |
    Remove-Item

不要使用模糊主题匹配,也不要批量清理根证书库。

6. 过期证书的处理

不要把已经过期的旧证书作为长期方案。应重新生成或签发一张新证书,并满足:

  • 证书处于有效期内;
  • EKU 包含 Server Authentication
  • SAN 包含实际使用的 DNS 名称;
  • 如果通过 IP 访问,SAN 还应包含对应的 IP;
  • 服务器绑定的新证书与工控机导入的证书一致。

对于多台域内工控机,可以通过组策略统一分发:

1
2
3
4
5
计算机配置
→ Windows 设置
→ 安全设置
→ 公钥策略
→ 受信任的根证书颁发机构

方案二:关闭 Windows 自动根证书更新

该方案影响整台计算机,仅适用于完全隔离、专机专用,并且所有可信根证书都由管理员离线维护的环境。

普通联网电脑不建议使用。

一键脚本

下载:Set-RootCertificateAutoUpdate.ps1

查看当前状态:

1
2
3
powershell.exe -NoProfile -ExecutionPolicy Bypass `
    -File ".\Set-RootCertificateAutoUpdate.ps1" `
    -Action Status

全局关闭自动根证书更新:

1
2
3
powershell.exe -NoProfile -ExecutionPolicy Bypass `
    -File ".\Set-RootCertificateAutoUpdate.ps1" `
    -Action Disable

恢复执行脚本前的原始策略:

1
2
3
powershell.exe -NoProfile -ExecutionPolicy Bypass `
    -File ".\Set-RootCertificateAutoUpdate.ps1" `
    -Action Restore

脚本第一次执行 Disable 时,会将原注册表状态保存到:

1
C:\ProgramData\RootCertificateAutoUpdatePolicy\original-state.json

重复执行 Disable 不会覆盖第一次备份;执行 Restore 时会恢复原值,并在成功后删除备份文件。如果找不到备份,脚本会拒绝恢复,避免覆盖机器原有策略。

方法一:通过组策略配置

运行:

1
gpedit.msc

进入:

1
2
3
4
5
6
计算机配置
→ 管理模板
→ 系统
→ Internet 通信管理
→ Internet 通信设置
→ 关闭自动根证书更新

将“关闭自动根证书更新”设置为“已启用”。

注意:启用该策略,代表关闭自动根证书更新。

应用策略:

1
gpupdate /force

建议重启工控机后,再用全新应用进程验证。

方法二:通过注册表策略配置

以管理员身份执行:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$policyPath =
    "HKLM:\SOFTWARE\Policies\Microsoft\SystemCertificates\AuthRoot"

New-Item -Path $policyPath -Force | Out-Null

New-ItemProperty `
    -Path $policyPath `
    -Name "DisableRootAutoUpdate" `
    -PropertyType DWord `
    -Value 1 `
    -Force

gpupdate /force

验证策略:

1
2
Get-ItemProperty -Path $policyPath |
    Select-Object DisableRootAutoUpdate

结果含义:

1
2
3
1        关闭自动根证书更新
0        开启自动根证书更新
值不存在 Windows 默认开启自动根证书更新

恢复默认行为

1
2
3
4
5
6
Remove-ItemProperty `
    -Path $policyPath `
    -Name "DisableRootAutoUpdate" `
    -ErrorAction SilentlyContinue

gpupdate /force

恢复后建议重启工控机。


方案选择

方案影响范围适用场景建议
导入指定证书到 LocalMachine\Root仅指定证书固定内网服务、少量工控机推荐
内部 CA + 组策略分发根证书企业内部全部受控服务多服务器、多工控机最佳长期方案
关闭自动根证书更新整台计算机完全离线、证书统一离线维护谨慎使用

验证

修复后必须启动一个全新的应用进程,不能只在原进程中重复请求。

如果证书已续签、SAN 正确并完成信任配置,可以使用不带 -k 的 curl 验证:

1
2
3
curl.exe -sS -o NUL `
    -w "HTTP=%{http_code} TCP=%{time_connect}s TLS=%{time_appconnect}s TTFB=%{time_starttransfer}s TOTAL=%{time_total}s`n" `
    $url

预期结果:

1
2
3
4
5
HTTP=200
不再出现 SEC_E_UNTRUSTED_ROOT
不再出现证书过期
不再出现名称不匹配
第一次请求不再等待十几秒

参考资料

记录工业视觉、C++ 与端侧 AI 部署实践