适用场景
准备给 Windows 电脑或服务器安装维护工具时,文件名看起来正确,并不能证明它来自预期厂商。本教程在运行安装包之前,用系统自带的 PowerShell 读取数字签名,核对签名状态与证书主体,再保存一份简明记录,供变更审批或后续排查使用。
适用于 Windows 上能够读取的常见可执行文件、安装包或已签名脚本。整个核验过程不执行目标文件,普通用户通常就能完成。工具返回的结论取决于当前系统的信任配置及验证条件,不能替代来源审查和组织的软件准入流程。
原理
代码签名把文件内容与签名证书联系起来。验证时,系统检查签名相关的数据完整性和信任状态。签名证书主体用于识别签署者,但显示的公司名称仍需与厂商官方发布信息对照。
有效签名表示本次签名验证通过,不代表程序没有漏洞,也不代表它适合当前服务器。相反,未签名也不能直接证明文件恶意:某些项目可能采用独立校验文件等其他发布方式,需要按照项目官方说明另行核验。
PowerShell 的签名查询命令只在 Windows 平台提供;同一文件同时具有嵌入式签名和 Windows 目录签名时,该命令会使用目录签名。具体行为见 微软命令文档。
准备工作
先从厂商官方网站取得文件,保留下载页面、产品版本和预期发布者信息。不要双击目标文件,也不要为了消除提示而提前解除文件阻止或修改执行策略。
打开 Windows PowerShell。下面让读者在提示中输入实际文件路径,不预设用户名或下载目录。含空格的路径可以直接粘贴;若使用资源管理器的复制路径功能带入首尾双引号,输入代码会将其去除。
分步骤操作
第一步:确认检查的是实际文件
执行以下代码:
$inputPath = (Read-Host '请输入待核验文件的完整路径').Trim().Trim('"')
$item = Get-Item -LiteralPath $inputPath -ErrorAction Stop
if ($item.PSIsContainer) {
throw '请选择文件,不能选择目录。'
}
$item | Select-Object FullName, Length, LastWriteTime
inputPath 是输入路径,item 是系统读取到的文件对象,不需要修改变量名称。检查输出中的完整路径、大小和修改时间是否符合预期,避免核验了旧版本或同名副本。使用按字面路径读取参数,可以避免方括号等字符被解释成通配模式。
第二步:读取状态与证书
确认路径后,在同一个窗口执行:
$sig = Get-AuthenticodeSignature -LiteralPath $item.FullName -ErrorAction Stop
$sig | Format-List Path, Status, StatusMessage
$sig.SignerCertificate | Format-List Subject, Issuer, Thumbprint, NotBefore, NotAfter
$sig.TimeStamperCertificate | Format-List Subject, Issuer, NotBefore, NotAfter
依次查看状态(Status)、状态说明(StatusMessage)、证书主体(Subject)和颁发者(Issuer)。指纹(Thumbprint)用于标识证书;它不是这个安装包的文件哈希,不能拿来与下载页面的文件校验值比较。
最后一组用于展示时间戳证书信息。没有输出可能表示没有相应证书对象,不能仅据此判断文件遭到篡改。时间戳证书的有效期也不是文件签署日期。不要仅因为签名证书当前已过期,就绕过系统完整验证结果自行下结论。
第三步:解释不同状态
有效(Valid)表示签名验证通过,接下来仍须确认签署者符合预期。未签名(NotSigned)表示没有得到可用签名,应回到项目官方发布说明确认其核验方法。
哈希不匹配(HashMismatch)表示文件内容与签名中的哈希不匹配,应停止使用这一副本并重新取得官方文件。不受信任(NotTrusted)表示签署者不受当前系统信任,需要检查来源和系统信任条件。未知错误(UnknownError)则应结合状态说明继续排查,不能直接归入正常或恶意。
这些状态的定义来自 微软 SignatureStatus 枚举文档。状态说明可能随系统语言变化,自动处理时优先使用状态字段,不要匹配一整句中文提示。
第四步:保存核验记录
在同一窗口继续执行以下代码。报告写入系统临时目录下一个新生成的文件名,并在最后显示路径:
$report = [pscustomobject]@{
CheckedAt = (Get-Date).ToString('o')
Path = $item.FullName
Length = $item.Length
Status = [string]$sig.Status
StatusMessage = $sig.StatusMessage
SignerSubject = $sig.SignerCertificate.Subject
SignerThumbprint = $sig.SignerCertificate.Thumbprint
TimeStamperSubject = $sig.TimeStamperCertificate.Subject
}
$reportPath = Join-Path ([IO.Path]::GetTempPath()) ('signature-check-' + [guid]::NewGuid().ToString('N') + '.csv')
$report | Export-Csv -LiteralPath $reportPath -NoTypeInformation -Encoding UTF8
Import-Csv -LiteralPath $reportPath | Format-List
$reportPath
reportPath 是自动生成的报告位置。报告记录的是本次检查结果,没有复制目标程序。需要长期保留时,把报告移动到组织规定的变更记录目录;共享前注意完整路径可能暴露本机目录信息。
验证方法
把屏幕结果与重新导入的报告对照,确认路径、状态和签名主体一致。再与厂商官方发布页面核对软件版本及预期发布者,不能只看名称中是否包含熟悉的词。
核验后如果文件被替换、重新下载或移动过程中发生内容变化,应对最终准备运行的副本重新检查。保存的报告属于检查时刻的记录,不能替未来文件作保证。
常见错误
检查到有效签名就立即以管理员身份运行,是把来源验证扩大成了安全结论。签名主体与预期厂商名称不同,也不一定立即代表伪造,但必须从厂商官方资料确认其签署安排。
遇到不受信任或未知错误时,不要随意导入陌生根证书,更不要关闭系统安全功能。应检查系统时间、受控网络访问条件和证书更新状态,再由管理员按照组织流程处理。
安全与回退
本流程不安装软件、不更改证书库,也不修改执行策略。回退时关闭 PowerShell,删除自己生成且不再需要的报告即可。状态异常的目标文件先保持不执行,重新从官方渠道获取并核验;如果软件已经安装,签名查询无法撤销安装,应另外执行厂商支持的卸载或恢复流程。
参考资料与转载说明
本文依据上述公开资料进行中文原创整理,不是逐句翻译,也不替代厂商手册。操作前请核对自己的版本、型号和备份。
评论一下?