开始前,会这些就够了
- 能读懂简单字符串比较
遇到不熟悉的词,先看这 3 个解释
- 哈希
- 哈希用规定的计算方法,把输入数据变成便于比较的结果;常见摘要算法会输出固定长度。同样的输入得到同样的结果,但不同输入仍可能得到相同结果。
- 加密
- 加密用算法和密钥把原来的内容变成难以直接阅读的数据,让拥有相应解密条件的人能够恢复内容。它主要解决谁能读到信息的问题,密钥的保存同样重要。
- 安全随机数
- 安全随机数强调别人难以预测接下来的结果,适合生成保密凭据等用途。它通常由系统提供的可靠随机来源产生,不能只凭数字看起来杂乱或没有重复来判断安全。
下载页给出一长串 SHA-256,数据库里也可能保存一长串密码校验值。它们看起来都像乱码,却不一定是密文。判断用途时,最先要问的是:以后需要把原文取回来,还是只需要核对这次输入是否匹配?
哈希把内容变成固定长度的摘要
以 SHA-256 为例,不同长度的数据会得到二百五十六位结果,常显示成六十四个十六进制字符。同样的字节使用同一算法会得到同样结果,所以可以拿两份摘要比较。它像内容的简短指纹,但这个比喻有边界:输入种类远多于固定长度结果,理论上必然存在相同摘要的不同输入。
安全哈希追求的是让人很难故意找到这样的碰撞,而不是宣布碰撞在数学上不存在。普通哈希也不带保密钥匙,知道原文的人都能重新计算。如果下载文件和校验值一起被替换,仅仅看到二者匹配,不能证明它来自可信发布者。
空格也是内容的一部分
下面只处理三段公开练习文字。两次输入 note 得到相同摘要,加一个空格后,这组输入得到的摘要不同。长度仍然是六十四个十六进制字符。实验说明了确定性和按字节计算,不能凭三个输入证明算法对所有输入都没有碰撞。
看似一样的文字也可能有不同换行或编码。跨程序比较之前,需要确认双方到底对哪一串字节计算。把摘要变成大写或小写,是显示写法;先删空格再计算,则已经改变输入规则。两者对结果的影响不能混着理解。
const { createHash } = require("node:crypto");
const hash = text => createHash("sha256").update(text, "utf8").digest("hex");
const first = hash("note");
console.log(first.length);
console.log(first === hash("note"));
console.log(first === hash("note "));怎样运行:保存为 hash-demo.cjs,用 Node.js 24 运行:node hash-demo.cjs。只处理代码中的练习字符串。
运行后对照结果
64
true
false加密的目标,是让持有密钥的人读回来
如果你要保存一份日后还能阅读的私人备忘录,只留下摘要显然不够:摘要不是压缩包,没有通用的解压或解密步骤能把任意原文完整还原。加密则把原文变成密文,让掌握正确密钥的一方按算法恢复内容;密钥怎样保管,是方案中不可省略的一部分。
“加过密”也不自动表示能发现篡改。有些模式只负责隐藏内容,还需要配套的完整性保护。带认证的加密方式会检查内容是否被改动。这里先理解职责即可;写实际系统时应采用成熟库和经过审核的方案,不靠自己拼接几个数学运算来替代。
不能解密,不代表猜不出来
假设原文只可能是十个常见词。别人完全可以逐个计算摘要,与拿到的值比较,不需要发明“反向哈希”。密码尤其容易遇到这种猜测,因此一次快速 SHA-256 不适合作为完整的密码存储方案。密码校验需要专门设计的算法与成本设置。
密码方案常为每条记录加入随机盐,让相同密码不直接形成可复用的相同结果;盐通常不需要像密钥那样保密。它的作用也不是让弱密码突然变强。理解这些区别后,就能把文件核对、保密存储和登录校验分别交给适合的工具。
记住这三点
- 摘要主要用于比较和校验;需要恢复原文时应考虑合适的加密方案。
- 摘要相同不是数学上的绝对唯一证明,也不自动证明发布者身份。
- 密码存储需要专用算法和参数,不能照搬一次快速文件哈希。
别把例子用过头
- “没有通用逆运算”不等于短输入或弱密码无法被猜测。
- 哈希的十六进制外观与保密能力无关。
- 示例只观察 SHA-256 输入输出,不是一套密码存储或文件认证系统。
自己试一小步
照片备份、下载校验、登录校验分别需要什么能力?
- 给三个场景分别写下是否需要恢复原始内容。
- 判断是否需要保密、识别篡改和确认发送者,允许一个场景同时需要多项。
- 对下载校验补充说明:你从哪里取得可信的预期摘要。
做到这些,就算完成
- 没有把“输出像乱码”当作加密的判断理由。
- 能解释普通摘要为什么不足以独自解决全部场景。
- 不使用真实密码或个人文件作练习输入。
查原始资料
想确认一个细节,先看这份资料对应的部分,不必从头读完所有文档。
- SubtleCrypto: digest() (新标签页)↗
固定长度摘要、碰撞抵抗和 SHA-256 输出长度。
- SubtleCrypto: encrypt() (新标签页)↗
加密与解密操作以及带认证加密对篡改检查的作用。
- Password Storage Cheat Sheet (新标签页)↗
密码哈希与加密的用途区别、快速哈希的局限及盐的作用。
- Node.js 24: crypto.createHash() (新标签页)↗
本地例子使用
createHash、update 和 digest 生成摘要。
找一份资料继续练
先选一项,按下面的范围继续学;不必从头读完整门课程。
UC Berkeley CS161:计算机与应用安全 (新标签页)↗
只读开放教材的哈希概述与性质两节,分清单向计算和碰撞,再检查用于核对的哈希值是否来自可信来源。
查看学习准备与访问说明 →内容摘要:把一段文字变成固定长度的检查值 (新标签页)↗
对照两段固定文字的摘要,区分字节长度、显示字符数、加密和认证。
查看学习准备与访问说明 →