同名文件的内容一定相同吗?使用 PowerShell 比较 SHA-256

PowerShellカテゴリを表すパンダのイラスト PowerShell

关于本文
本文是通过使用生成式 AI 的自动化流程创建的。基于 PowerShell 和 .NET 的官方规范,整理了只读比较文件 SHA-256 的步骤。

验证状态:📘 基于官方规范的解说・未在 Windows 实机上确认

同名文件的内容一定相同吗?使用 PowerShell 比较 SHA-256

即使文件名相同也不能掉以轻心

保存通过电子邮件收到的报告时,发现文件名与昨天的报告相同。明明应该是更新版本,大小却很相似。在这种情况下,仅比较文件名是无法判断内容是否相同的。因为文件名只是人类给出的标记,而不是文件内容本身。修改时间也会因复制或保存操作而发生变化,因此它不能成为判断内容是否相同的决定性因素。

这时就可以使用名为 SHA-256 的哈希函数。它根据构成文件的字节序列计算出 256 位的值,通常显示为 64 位十六进制数。如果两个文件的哈希值不同,则这两个字节序列必然不同。如果值一致,则内容相同的可能性极高。但是,这并不在数学上保证完全一致,也不是向恶意接收方保证文件真实性的机制。这种区别是业务中应用时的重要界限。

首先安全地尝试虚拟数据

在 Windows 的 PowerShell 7 或 Windows PowerShell 5.1 中,使用不包含个人信息的简短文本。以下是在临时文件夹中创建新样本的步骤,不会修改现有的业务文件。在 PowerShell 中逐行检查并执行以下代码。如果在保存目标位置存在同名字段,它将被覆盖,因此请使用专用的新文件夹。

$dir = Join-Path ([System.IO.Path]::GetTempPath()) 'papanda-hash-demo-20261109'
[System.IO.Directory]::CreateDirectory($dir) | Out-Null
$a = Join-Path $dir 'report-a.txt'
$b = Join-Path $dir 'report-b.txt'
$utf8 = [System.Text.UTF8Encoding]::new($false)
[System.IO.File]::WriteAllText($a, '備品: 机 3台', $utf8)
[System.IO.File]::WriteAllText($b, '備品: 机 3台', $utf8)
Get-FileHash -LiteralPath $a -Algorithm SHA256
Get-FileHash -LiteralPath $b -Algorithm SHA256

这里需要观察的不是显示的 Path,而是 Hash 列。尽管两个路径不同,但写入的字符串和字符编码都相同,因此哈希值理应一致。这是预期结果,并非在此处获取 Windows 上的实际运行结果。文章中未将哈希值固定,是为了让读者亲自确认输出。

在此实验中,字符串是以无 BOM 的 UTF-8 格式编写的。BOM 是有时附加在文件开头的标记,即使外观相同的字符串,如果 BOM 的有无不同,字节序列也不同。哈希面向的是字节而非字符的含义,因此统一字符编码的指定是比较的前提。由于 PowerShell 的版本可能会导致文本输出命令的默认字符编码不同,因此使用 .NET 的写入 API 固定了条件。

仅更改一个字符进行比较

接下来仅更改 b 的数量。不更改 a 是比较实验的关键点。更改后执行相同的命令,预计 Hash 列将会不同。同时值得注意的是,不仅仅是哈希值的一部分发生变化,整体也可能会发生巨大改变。

[System.IO.File]::WriteAllText($b, '備品: 机 4台', $utf8)
(Get-FileHash -LiteralPath $a -Algorithm SHA256).Hash
(Get-FileHash -LiteralPath $b -Algorithm SHA256).Hash

仅仅更改一个字符也能得到不同的哈希,是因为 SHA-256 将整个输入混合并生成了固定长度的值。相反,仅看哈希值是无法知道更改了第几个字符,或者桌子的数量是增加还是减少了。如果将哈希理解为检测差异是否存在而非显示差异的工具,就会更容易掌握其用法。

通过图表阅读处理流程

图表的左侧表示文件内容,中间表示 SHA-256 计算,右侧表示值的大小比较。重要的是以读取的字节序列为判断标准,而不是文件名或修改时间。

flowchart LR
    A[ファイルAのバイト列] --> C[SHA-256計算]
    B[ファイルBのバイト列] --> D[SHA-256計算]
    C --> E{ハッシュ値は一致?}
    D --> E
    E -->|いいえ| F[内容は異なる]
    E -->|はい| G[同じ内容の可能性が極めて高い]

此图表示计算结果的含义,并不代表加密签名的验证或发送者的身份验证。即使哈希一致,在攻击者可以同时替换文件及其哈希值的情况下,也不能作为安全性的证据。当与可靠分发源通过其他途径发布的哈希值进行核对时,与信任同一封邮件中附带的哈希值时,确认的强度是不同的。

出现失败时应该检查哪里

如果文件不存在,Get-FileHash 将无法返回哈希值。请首先检查 LiteralPath 的字符串以及实际文件的位置。如果文件被其他应用程序独占打开,或者访问权限不足,读取操作也可能会失败。为了避免将失败情况错误地判定为空白匹配,在业务脚本中必须显式处理错误。

另一个陷阱是通过外观比较文本。Windows 的 CRLF 和类 Unix 系统的 LF 在屏幕上看起来可能是相同的换行符,但它们的字节序列不同。UTF-8 和 UTF-16 也可以表示相同的日语,但文件的字节序列不同。哈希值不同并不一定意味着句子的含义也不同。如果您想了解作为文本的差异,则需要进行在标准化字符编码和换行符之后进行差异比较的单独处理。但是,在检查原始文件完整性的场景下,最好不要通过标准化来掩盖原始差异。

如何在实际工作中进行区分使用

哈希在确认备份副本、分发前后文件比对以及防止混淆同名文件方面非常有用。例如,在将负责人创建的 CSV 复制到另一个文件夹后,通过比较复制源和复制目标的 SHA-256,至少可以确认读取的内容是否一致。在工作记录中保留目标路径、比对日期时间、算法、一致与否以及是否存在错误,将提高可复现性。但是,无需将业务文件的内容或个人信息完整输出到日志中。

如果文件在写入过程中发生更改,则比对时的状态将变得模糊。应在处理前固定文件,必要时以只读快照或副本作为目标。此外,应区分“两个文件内容是否相同”的问题和“该文件是否来自正确的发布方”的问题。后者需要进行其他确认,例如签名验证或通过可靠途径进行哈希比对。

在比对大量文件时,请首先限制文件的枚举范围和权限。由于哈希计算需要读取整个文件,因此重复扫描巨大的备份会消耗磁盘 I/O。按更新日期或大小缩小候选范围是提高性能的有效方法,但这与仅凭此进行最终的同一性判断是两码事。根据比对的目的,平衡性能和确认精度。

总结

即使是同名或同大小的文件,内容也不一定相同。使用 SHA-256 可以轻松检测出字节序列的差异。起初,可以通过两个内容相同的文件的匹配情况进行观察,接着更改一个字符来确认不匹配,这样很容易理解哈希的作用。在实际工作中,将字符编码、换行符、读取失败、处理过程中的更改以及分发源的真实性分开考虑,并组合所需的确认操作是非常重要的。

官方资料

  • Microsoft Learn: Get-FileHash https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-filehash

  • Microsoft Learn: UTF8Encoding https://learn.microsoft.com/en-us/dotnet/api/system.text.utf8encoding

  • NIST: Secure Hash Standard (FIPS 180-4) https://csrc.nist.gov/pubs/fips/180-4/upd1/final

文档信息

文章??
同名文件的内容一定相同吗?使用 PowerShell 比较 SHA-256
?布日期
更新日期
来源
https://papanda925.com/?p=18578&lang=zh

?可: ?于本站?有相??利的正文及原??表,除非?有?明,可依据 CC BY 4.0 使用。本文可能包含使用生成式AI?建或??的内容。若代??有?可声明,或?接的GitHub???定了?可,?代?以??可?准。引用内容、第三方?料、?片及商?不在本?可范?内。 使用政策

标题和URL已复制