[{"data":1,"prerenderedAt":67},["ShallowReactive",2],{"article-162":3},{"code":4,"msg":5,"data":6,"count":14},200,"查询成功",{"id":7,"title":8,"keywords":9,"description":10,"category_id":11,"content":12,"body_html":13,"thumb_up":14,"clicks":11,"sort":14,"remark":13,"status":11,"is_open":11,"is_deleted":14,"is_top":11,"is_recommend":11,"create_time":15,"update_time":15,"image_id":16,"url":13,"member_id":14,"cate_name":17,"prev":18,"next":21,"tags":22,"words":38,"read_time":39,"comments":14,"cover":40,"relevant":41},162,"什么是哈希算法？从文件校验、密码存储到 Git 与区块链","哈希算法、SHA-256、密码哈希、数据完整性","哈希算法把长消息映射为固定长度摘要，但它不是加密，也不等于绝对不可逆或天然防篡改。本文从 SHA-256 的基本性质出发，解释原像、第二原像与碰撞抗性，并梳理文件校验、密码存储、哈希表、Git 和 Bitcoin 中不同的使用边界。",1,"你登录网站时输入的密码、从官网下载的软件安装包、Git 中的一次提交，以及 Bitcoin 的区块链，看起来属于完全不同的系统，却都离不开哈希。它们使用哈希的目的也不相同：有的要校验内容，有的要提高猜密码的成本，有的要给对象命名，有的则把历史记录连接起来。\n\n**一句话结论：哈希算法把实际工程中的长消息映射为固定长度摘要；安全用途依赖的是特定攻击在现实计算条件下足够困难，而不是“摘要能证明一切”或“数学上绝对不可逆”。**\n\n\n## 哈希到底做了什么\n\n可以把哈希函数写成：\n\n```text\ndigest = H(message)\n```\n\n`message` 可以是文本、图片、压缩包或经过规范序列化的数据。哈希函数读取消息，输出固定长度的比特串。以 SHA-256 为例，无论输入是一个字符还是一个大型文件，输出都是 256 bit，也就是 32 byte；通常写成 64 个十六进制字符，因为每个十六进制字符表示 4 bit。\n\n“任意长度输入”是便于理解的科普说法，不应理解为算法规范允许真正无限的输入。具体算法对消息长度存在边界。例如 SHA-256 的消息填充和长度编码受 [FIPS 180-4](https:\u002F\u002Fnvlpubs.nist.gov\u002Fnistpubs\u002FFIPS\u002FNIST.FIPS.180-4.pdf) 约束；对普通开发者来说，更准确的表达是：它能处理实际工程中的长消息，并始终给出固定长度结果。\n\n![任意工程消息映射为固定长度 SHA-256 摘要](https:\u002F\u002Ftp.myong.top\u002Fstorage\u002Fmarkdown\u002F20260718\u002Fdad2159acaa0bdc8589053ab9c569d0d.png)\n\n*图 2：不同大小的输入经过 SHA-256 后，都得到 256 bit（32 byte、通常显示为 64 个十六进制字符）的摘要。*\n\n理解哈希，还要抓住三个直观性质：\n\n- **确定性**：同一个算法、同一份字节输入，总会得到同一摘要。注意“看起来相同”的文本可能因编码、换行符或末尾空格不同而产生不同结果。\n- **固定输出**：输出长度由算法决定，不随输入增大。摘要不是原文的压缩包，不能靠“解压”恢复消息。\n- **雪崩效应**：好的密码学哈希函数通常追求这样的性质：输入发生很小变化时，输出会广泛变化，而且难以从变化规律推测原输入。这使摘要适合敏感地发现内容差异。\n\n## “不可逆”不是准确的安全定义\n\n日常表达常说哈希“不可逆”，但这容易造成两个误解：一是把它当成严格的数学证明，二是以为攻击者无法猜输入。密码学更关心下面三种“在现实资源下难以完成”的能力：\n\n1. **原像抗性**：给定摘要 `h`，寻找一个满足 `H(m) = h` 的消息 `m`，计算上应当困难。\n2. **第二原像抗性**：给定某个消息 `m1`，寻找另一个不同消息 `m2`，使二者摘要相同，计算上应当困难。\n3. **碰撞抗性**：寻找任意一对不同消息，使它们摘要相同，计算上应当困难。\n\n![原像抗性、第二原像抗性与碰撞抗性](https:\u002F\u002Ftp.myong.top\u002Fstorage\u002Fmarkdown\u002F20260718\u002Fa036e856b43408502d91d10e01f34db9.png)\n\n*图 3：三种安全性质对应不同的攻击目标，不能用一句“不可逆”混为一谈。*\n\n固定长度输出意味着输出空间有限，而输入集合远大于输出空间，所以从数学上看，碰撞必然存在。密码学算法承诺的不是“没有碰撞”，而是攻击者在现实计算条件下难以构造有用碰撞。算法是否仍适合安全用途，也要看公开研究、标准与具体应用，不能只看摘要长度。\n\n同样，原像抗性并不会保护低熵输入。若输入只是常见的六位数字，攻击者完全可以枚举候选、逐一计算摘要并比对。哈希函数没有被“逆运算”，但原输入仍可能被猜中。这正是密码不能直接使用快速通用哈希保存的原因。\n\n## 文件校验：摘要相同能证明什么\n\n下载大型软件后，官网常会公布 SHA-256 摘要。正确的校验链路包含三个步骤：\n\n1. 从可信渠道取得官方公布的摘要，例如使用 HTTPS 访问项目官网、已验证的发布页，或检查带数字签名的校验文件。\n2. 在本地对实际下载的文件重新计算 SHA-256。\n3. 比较本地结果与可信摘要归一化后的摘要值，可以忽略十六进制 `A-F` 的大小写及展示空白，但不能漏掉任何字符，也不能混淆文件版本。\n\n```powershell\nGet-FileHash .\\installer.exe -Algorithm SHA256\n```\n\n![文件校验的可信摘要、重算与比对流程](https:\u002F\u002Ftp.myong.top\u002Fstorage\u002Fmarkdown\u002F20260718\u002F3a75dbf84c468292d7a53f51f3a84939.png)\n\n*图 4：先从可信来源取得摘要，再在本地重算并归一化后比较摘要值；三个环节缺一不可。*\n\n结果一致，只能说明“这份文件的内容与那个摘要相匹配”。如果安装包和网页上的摘要同时被攻击者替换，两者仍然可以一致。因此，哈希校验主要解决内容完整性比对；来源真实性还需要 HTTPS、代码签名、发布签名或其他可信分发机制。不能把“摘要一致”扩大解释成“发布者身份必然可信”。\n\n## 密码存储：为什么不能直接使用 SHA-256\n\n数据库不应保存明文密码，也不应保存一次普通 SHA-256，甚至“SHA-256 加盐”仍然不是现代密码存储的充分方案。SHA-256 为快速处理消息而设计；攻击者拿到数据库后，可以离线高速尝试候选密码，服务器的登录限流此时不起作用。\n\n专用密码哈希或密码派生函数（KDF）通过两类机制提高离线猜测成本：\n\n- 每条记录使用 `salt`，使相同密码通常产生不同结果，并阻止攻击者直接复用预计算表。\n- 使用可调的时间、内存或迭代成本，让每次猜测更昂贵，并能随硬件能力调整参数。\n\n常见选择包括 Argon2id、scrypt、bcrypt 和 PBKDF2。新系统应优先调用成熟框架提供的密码哈希 API，让框架负责安全随机盐、结果编码、参数保存、验证以及将来的重新哈希；不要自行拼接字符串设计格式。\n\n![专用密码哈希的 salt、成本参数与记录结构](https:\u002F\u002Ftp.myong.top\u002Fstorage\u002Fmarkdown\u002F20260718\u002F77eeaff06138b2875b7ab7dddda8b9a5.png)\n\n*图 5：每条密码记录保存 salt、哈希结果与成本参数；验证时用同一参数重新计算并比较。*\n\n[NIST SP 800-63B-4 的密码验证要求](https:\u002F\u002Fpages.nist.gov\u002F800-63-4\u002Fsp800-63b.html#passwordver)明确规定：`salt` **必须（SHALL）**至少 32 bit，并且每条记录的 `salt` 与哈希结果都必须保存；成本因子**应当（SHOULD）**在不对验证性能产生负面影响的前提下尽可能高，并随硬件性能调整。这不是要求永远采用某个固定迭代次数，而是要求系统能维护和升级参数。\n\n对 Argon2，[RFC 9106](https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc9106.html)推荐密码哈希使用 16 byte `salt`；文档在空间受限场景讨论过 64 bit，但不应把它当作所有实现的统一强制下限。为每条密码生成独立、不可预测的 `salt` 是稳妥的工程实践，但不要把“盐必须全局唯一”错误表述成 RFC 9106 的原文强制条款。`salt` 可以随记录公开保存；它不是需要保密的加密密钥。\n\n## 同叫“哈希”，工程目标却不同\n\n### 哈希表：重点是快速查找\n\n哈希表利用哈希值把键分布到桶中，以便快速定位数据。它通常追求计算快、分布均匀和较低冲突率，并不要求原像抗性或碰撞抗性。若键来自不可信输入，还要考虑攻击者制造大量冲突导致性能退化，但解决方案也不等于一律换成 SHA-256。数据结构哈希与密码学哈希应按威胁模型选择。\n\n### Git：对象 ID 来自规范表示\n\n传统 Git 并非只对文件内容裸算 SHA-1。Git 对对象的规范序列化表示计算摘要，其输入形式可概括为：\n\n```text\n\u003Ctype> \u003Clength>\\0\u003Ccontent>\n```\n\n所得 SHA-1 用作对象 ID，因此对象类型、长度和内容共同影响标识。[Git 的哈希函数迁移设计](https:\u002F\u002Fgit-scm.com\u002Fdocs\u002Fhash-function-transition)选择 SHA-256 作为新哈希方案，并描述了不同格式之间的兼容与映射问题；这不表示所有现有仓库已经默认使用 SHA-256。讨论某个仓库时，应先确认它实际采用的对象格式。\n\n### Bitcoin：哈希负责连接，安全来自完整机制\n\nBitcoin 区块头包含前一区块的哈希。若历史区块内容改变，其区块哈希会变化，后续区块中记录的连接也随之失效，攻击者必须从被修改区块起，重做该区块自身及后续区块的工作量证明（PoW）。可是，“使用哈希”本身并不会自动产生不可篡改性。\n\nBitcoin 的历史修改成本还依赖工作量证明（Proof of Work，PoW）、链选择规则、网络传播以及多数诚实算力等假设。[Bitcoin 白皮书](https:\u002F\u002Fbitcoin.org\u002Fbitcoin.pdf)把这些机制放在一个整体中讨论。准确说法是：哈希提供内容承诺与链式连接，PoW 和共识假设让重写历史在特定威胁模型下变得昂贵；不能简化成“有哈希就不可篡改”。\n\n## 场景选择：先问目标，再选工具\n\n| 场景 | 核心目标 | 推荐做法 | 常见误区 |\n| --- | --- | --- | --- |\n| 文件下载校验 | 检查内容是否匹配 | 从可信来源取得摘要，本地重算并归一化后比较摘要值 | 把摘要一致当成发布者身份认证 |\n| 密码存储 | 提高离线猜测成本 | 使用成熟框架的 Argon2id、scrypt、bcrypt 或 PBKDF2 API | 直接用 SHA-256，或认为 SHA-256 加盐就足够 |\n| 哈希表 | 快速分布与查找 | 使用语言或框架的数据结构实现，结合输入威胁评估 | 默认要求密码学安全 |\n| Git 对象 | 内容寻址与完整性标识 | 依据仓库对象格式使用 Git 自身机制 | 认为所有仓库默认都是 SHA-256 |\n| 区块链 | 内容连接与共识记账 | 同时分析哈希、PoW、链规则与参与者假设 | 认为仅靠哈希即可防篡改 |\n\n## 可以复述的总结\n\n哈希算法把工程中的长消息映射为固定长度摘要，具有确定性；好的密码学哈希函数通常追求雪崩效应。SHA-256 输出 256 bit，也就是 32 byte，通常显示为 64 个十六进制字符。安全性应分别讨论原像抗性、第二原像抗性与碰撞抗性；理论碰撞必然存在，关键是现实攻击成本。\n\n使用时记住三句话：文件校验必须先有可信摘要来源；密码必须交给带盐和可调成本的专用密码哈希；Git 与区块链中的哈希只是系统机制的一部分。先明确目标与威胁模型，再选择算法和 API，才是哈希真正可靠的用法。\n\n## 主要参考资料\n\n- [NIST：FIPS 180-4 项目页](https:\u002F\u002Fcsrc.nist.gov\u002Fpubs\u002Ffips\u002F180-4\u002Fupd1\u002Ffinal)\n- [NIST：FIPS 180-4 PDF](https:\u002F\u002Fnvlpubs.nist.gov\u002Fnistpubs\u002FFIPS\u002FNIST.FIPS.180-4.pdf)\n- [NIST SP 800-63B-4：Password Verifiers](https:\u002F\u002Fpages.nist.gov\u002F800-63-4\u002Fsp800-63b.html#passwordver)\n- [RFC 9106：Argon2 Memory-Hard Function](https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc9106.html)\n- [Git：Hash Function Transition](https:\u002F\u002Fgit-scm.com\u002Fdocs\u002Fhash-function-transition)\n- [Bitcoin: A Peer-to-Peer Electronic Cash System](https:\u002F\u002Fbitcoin.org\u002Fbitcoin.pdf)\n",null,0,"2026-07-18 12:42:19",279,"技术杂谈",{"id":19,"title":20},161,"Redis 为什么这么快？单线程只是答案的一部分",[],[23,26,29,32,35],{"id":24,"name":25},172,"计算机基础",{"id":27,"name":28},138,"后端开发",{"id":30,"name":31},173,"网络安全",{"id":33,"name":34},174,"密码学",{"id":36,"name":37},175,"哈希算法",4146,10,"https:\u002F\u002Ftp.myong.top\u002Fstorage\u002Farticle\u002F20260718\u002Fa15ddc5f3a113edcb260db69c85ebb4a.png",[42,47,52,57,62],{"id":43,"title":44,"create_time":45,"description":46},89,"获取腾讯“邮我”的链接","2020-06-16 10:47:34","腾讯QQ邮箱提供了“邮我”组件，可以放在自己的网站上，让别人点击提供的图片或者链接就可以发Email过来，该文章分享的是如何获取到其中的链接。",{"id":48,"title":49,"create_time":50,"description":51},98,"本站点JavaScript相关特效使用方法整理","2021-04-22 18:38:53","本站的页面用的特效有，粒子线canvas-nest，动态彩带canvas-ribbon，鼠标点击特效以及音乐播放器，本文整理了特效的使用方法",{"id":53,"title":54,"create_time":55,"description":56},106,"阿里开源数据同步组件Canal","2023-10-26 22:43:32","最开始听说canal是从mysql与redis双写一致性解决方案，当时并没有太在意，最近由于需要实时同步数据，如果在代码对insert\u002Fupdate\u002Fdelete做拦截也可以实现，但对代码侵入性太大了，并且后期更改时容易有遗漏，风险太高，这时就又想到了canal，canal的好处在于对业务代码没有侵入，因为是基于监听binlog日志去进行同步数据，这个真的是太爽爽爽了。并且实时性也能做到准实时，这也是canal为什么这么流行，因为确实很多企业会用来做数据同步的方案。",{"id":58,"title":59,"create_time":60,"description":61},62,"内网使用Composer","2019-10-08 23:29:23","最近本地部署Laravel开发环境时，遇到公司的内网无法正常使用Composer下载Laravel，后来发现是要设置公司内网代理",{"id":63,"title":64,"create_time":65,"description":66},75,"Hexo-SEO优化开启静态文件压缩功能","2019-12-30 21:34:32","个人对HEXO搭建博客的SEO优化方案进行总结，从本地的文章结构到定期推送，再到SEO关键词优化做一个全面体系的汇总，如果有更好的方法可以私聊我。\n\n",1785081777933]