三个词,不断被混用
“这个密码加密了吗?”“把 URL 哈希一下就行。”“数据被编码了,所以它是安全的。”这些句子随处可见,而其中大多数用错了词。哈希、加密和编码是三种不同的操作,有三种不同的目的,把它们混淆会导致真实的安全错误,比如用一种什么也保护不了的方法存储密码。
好消息是,两个简单的问题就能把它们完全区分开。
两个问题
- 它可逆吗? 你能从输出取回原始输入吗?
- 它需要密钥吗? 是否需要一个秘密,还是任何人都能执行该操作?
把这三种操作对照这两个问题,图景便清晰了:
- 编码是可逆的,且不需要密钥。
- 哈希是不可逆的,且不需要密钥。
- 加密是可逆的,且需要密钥。
那张表就是整篇文章。其余只是细节。
编码:可逆,无密钥
编码把数据改写成另一种表示,使其能穿过一个期望特定格式的通道。Base64 把字节变成安全文本;URL 编码转义在 URL 中非法的字符;UTF-8 把字符变成字节。这一切都不是秘密。任何人都能把它解码回去,因为可逆性就是全部要义。编码提供零安全性。 如果你听到“令牌被编码了,所以它是安全的”,那是一个红色警报:编码意味着可读。
哈希:不可逆,无密钥
哈希函数把任意输入映射为固定大小的摘要,而你无法把它倒着运行以恢复输入。它不需要密钥,因此任何人都能从相同的输入算出相同的摘要。这使它非常适合验证:完整性检查、内容寻址和检测变化。当你需要确认两个东西相同而不存储原件时,它是正确的工具,但它不会以可逆方式隐藏任何东西,因为没有什么可逆转。
加密:可逆,带密钥
加密转换数据,使得只有持有正确密钥的人才能把它转换回去。这是三者中唯一为保密而建的。它在设计上可逆,但只有用密钥才行,这正是另外两者所缺乏的性质:编码人人可逆,哈希无人可逆,加密由持密钥者可逆。
选择正确的那一个
目的决定工具。需要数据以文本形式熬过传输吗?把它编码。需要验证完整性或在不存储原件的情况下比较吗?把它哈希。需要让数据对任何没有密钥的人保密吗?把它加密。
经典的错误是伸手去拿错误的那一列。用简单编码(人人可逆)甚至简单加密(一把被盗的密钥就暴露一切)存储密码,远弱于为此专门打造的密码哈希,那在它自己的文章里讲述。哈希工具 和 Base64 工具 让你观察哈希和编码在同一输入上的不同表现,摘要永不逆转,Base64 总能逆转。