前言
开发网站登录功能时,如何保证密码在传输过程/储存的安全?
相信不少前后端的朋友,在面试时都会被问到类似的问题。
在我对密码学一无所知时,也仅会回答:“MD5加密啊。”
诸不知,密码学在网络七层模型,甚至web开发中的应用比我想象得多得多。
1. 什么是密码学?
密码学是各种安全应用程序所必需的,现代密码学旨在创建通过应用数学原理和计算机科学来保护信息的机制。但相比之下,密码分析旨在解密此类机制,以便获得对信息的非法访问。
密码学具有三个关键属性:
- 机密性,为了防止未经授权的各方访问信息(换句话说,是要确保只有经过授权的人才能访问受限制的数据)。
- 完整性,是指保护信息不被随意篡改
- 真实性,与识别信息的所有者有关。
例如个人医疗数据:
- 机密性,个人医疗数据需要保密,这意味着只有医生或医护人员才能访问它。
- 完整性,还必须保护其完整性,因为篡改此类数据可能导致错误的诊断或治疗,并给患者带来健康风险。
- 真实性,患者数据应与已识别的个人联系起来,且患者需要知道操作者(医生)是谁。
在本文中,我们将从加密,哈希,编码和混淆四种密码学基础技术来入门。
2. 什么是加密?
加密定义:以保证机密性的方式转换数据的过程。
为此,加密需要使用一个保密工具,就密码学而言,我们称其为“密钥”。
加密密钥和任何其他加密密钥应具有一些属性:
- 为了保护机密性,密钥的值应难以猜测。
- 应该在单个上下文中使用它,避免在不同上下文中重复使用(类比 JS 作用域)。密钥重用会带来安全风险,如果规避了其机密性,则影响更大,因为它“解锁”了更敏感的数据。
2.1 加密的分类:对称和非对称
加密分为两类:对称和非对称
对称加密:
用途:文件系统加密,Wi-Fi 保护访问(WPA),数据库加密(例如信用卡详细信息)
非对称加密:
用途:TLS,VPN,SSH。
其主要区别是:所需的密钥数量:
- 在对称加密算法中,单个密用于加密和解密数据。只有那些有权访问数据的人才能拥有单个共享密钥。
- 在非对称加密算法中,使用了两个密钥:一个是公用密钥,一个是私有密钥。顾名思义,私钥必须保密,而每个人都可以知道公钥。
- 应用加密时,将使用公钥,而解密则需要私钥。
- 任何人都应该能够向我们发送加密数据,但是只有我们才能够解密和读取它。
- 通常使用非对称加密来在不安全的通道上进行通信时,两方之间会安全地建立公共密钥。
- 通过此共享密钥,双方切换到对称加密。
- 这种加密速度更快,更适合处理大量数据。
能被密码界承认的加密算法都是公开的:
- 某些公司使用专有或“军事级”加密技术进行加密,这些技术是“私有的”。且基于“复杂“算法,但这不是加密的工作方式。
- 密码界广泛使用和认可的所有加密算法都是公开的,因为它们基于数学算法,只有拥有密钥或先进的计算能力才能解决。
- 公开算法是得到广泛采用,证明了其价值的。
3. 什么是哈希?
哈希算法定义:·一种只能加密,不能解密的密码学算法,可以将任意长度的信息转换成一段固定长度的字符串。
加密算法是可逆的(使用密钥),并且可以提供机密性(某些较新的加密算法也可以提供真实性),而哈希算法是不可逆的,并且可以提供完整性,以证明未修改特定数据。
哈希算法的前提很简单:给定任意长度的输入,输出特定长度的字节。在大多数情况下,此字节序列对于该输入将是唯一的,并且不会给出输入是什么的指示。换一种说法:
- 仅凭哈希算法的输出,是无法确定原始数据的。
- 取一些任意数据以及使用哈希算法输出,就可以验证此数据是否与原始输入数据匹配,从而无需查看原始数据。
为了说明这一点,请想象一个强大的哈希算法通过将每个唯一输入放在其自己的存储桶中而起作用。当我们要检查两个输入是否相同时,我们可以简单地检查它们是否在同一存储桶中。
散列文件的存储单位称为桶(Bucket)
3.1 例子一:资源下载
提供文件下载的网站通常会返回每个文件的哈希值,以便用户可以验证其下载副本的完整性。
例如,在Debian的图像下载服务中,您会找到其他文件,例如SHA256SUMS,其中包含可供下载的每个文件的哈希输出(在本例中为SHA-256算法)。
- 下载文件后,可以将其传递给选定的哈希算法,输出一段哈希值
- 用该哈希值来与校验和文件中列出的哈希值作匹配,以校验是否一致。
在终端中,可以用openssl来对文件进行哈希处理:
- $ openssl sha256 /Users/hiro/Downloads/非对称.png
- SHA256(/Users/hiro/Downloads/非对称.png)= 7c264efc9ea7d0431e7281286949ec4c558205f690c0df601ff98d59fc3f4f64
同一个文件采用相同的hash算法时,就可以用来校验是否同源。
在强大的哈希算法中,如果有两个不同的输入,则几乎不可能获得相同的输出。
而相反的,如果计算后的结果范围有限,就会存在不同的数据经过计算后得到的值相同,这就是哈希冲突。(两个不同的数据计算后的结果一样)
这种称为:哈希碰撞(哈希冲突)。
如果两个不同的输入最终出现在同一个存储桶中,则会发生冲突。如MD5和SHA-1,就会出现这种情况。这是有问题的,因为我们无法区分哪个碰撞的值匹配输入。
强大的哈希算法几乎会为每个唯一输入创建一个新存储桶。
3.2 例子二:网站登陆
在web开发中,哈希算法使用最频繁的是在网站登陆应用上:
绝大多数的网站,在将登陆数据存入时,都会将密码哈希后存储。
- 这是为了避免他人盗取数据库信息后,还原出你的初始输入。
- 且下次登录时,Web 应用程序将再次对你的密码进行哈希处理,并将此哈希与之前存储的哈希进行比较。
- 如果哈希匹配,即使 Web 应用程序中没有实际的密码存储,Web 应用程序也确信你知道密码。
注册:
登陆:
哈希算法的一个有趣的方面是:无论输入数据的长度如何,散列的输出始终是相同的长度。
从理论上讲,碰撞冲突将始终在可能性的范围之内,尽管可能性很小。
与之相反的是编码。
4. 什么是编码?
编码定义:将数据从一种形式转换为另一种形式的过程,与加密无关。
它不保证机密性,完整性和真实性这三种加密属性,因为:
- 不涉及任何秘密且是完全可逆的。
- 通常会输出与输入值成比例的数据量,并且始终是该输入的唯一值。
- 编码方法被认为是公共的,普遍用于数据处理。
- 编码永远不适用于操作安全性相关。
4.1 URL编码
又叫百分号编码,是统一资源定位(URL)编码方式。URL地址(常说网址)规定了:
- 常用的数字,字母可以直接使用,另外一批作为特殊用户字符也可以直接用(/,:@等)
- 剩下的其它所有字符必须通过%xx编码处理。
现在已经成为一种规范了,基本所有程序语言都有这种编码,如:
- js:encodeURI、encodeURIComponent
- PHP:urlencode、urldecode 等。
编码方法很简单,在该字节ascii码的 16 进制字符前面加%. 如 空格字符,ascii码是 32,对应 16 进制是'20',那么urlencode编码结果是:%20。
- # 源文本:
- The quick brown fox jumps over the lazy dog
- # 编码后:
- #!shell
- %54%68%65%20%71%75%69%63%6b%20%62%72%6f%77%6e%20%66%6f%78%20%6a%75%6d%70%73%20%6f%76%65%72%20%74%68%65%20%6c%61%7a%79%20%64%6f%67
4.2 HTML实体编码
在HTML中,需要对数据进行HTML编码以遵守所需的HTML字符格式。转义避免 XSS 攻击也是如此。
4.3 Base64/32/16编码
base64、base32、base16可以分别编码转化 8 位字节为 6 位、5 位、4 位。
16,32,64 分别表示用多少个字符来编码,
Base64常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据。包括MIME的email,email via MIME,在XML中存储复杂数据。
编码原理:
Base64编码要求把 3 个 8 位字节转化为 4 个 6 位的字节
之后在 6 位的前面补两个 0,形成 8 位一个字节的形式
6 位 2 进制能表示的最大数是 2 的 6 次方是 64,这也是为什么是 64 个字符的原因
A-Z,a-z,0-9,+,/这 64 个编码字符,=号不属于编码字符,而是填充字符
Base64映射表,如下:
举个栗子:
- 第一步:“M”、“a”、"n"对应的ASCII码值分别为 77,97,110,对应的二进制值是01001101、01100001、01101110。如图第二三行所示,由此组成一个 24 位的二进制字符串。
- 第二步:如图红色框,将 24 位每 6 位二进制位一组分成四组。
- 第三步:在上面每一组前面补两个 0,扩展成 32 个二进制位,此时变为四个字节:00010011、00010110、00000101、00101110。分别对应的值(Base64编码索引)为:19、22、5、46。
- 第四步:用上面的值在 Base64 编码表中进行查找,分别对应:T、W、F、u。因此“Man”Base64编码之后就变为:TWFu。
上面的示例旨在指出,编码的用例仅是数据处理,而不为编码的数据提供保护。
4. 什么是混淆?
混淆定义:将人类可读的字符串转换为难以理解的字符串。
- 与加密相反,混淆处理不包含加密密钥。
- 与编码类似,混淆不能保证任何安全性,尽管有时会误将其用作加密方法
尽管不能保证机密性,但混淆仍有其它应用:
- 用于防止篡改和保护知识产权。
- APP 源代码通常在打包之前就被混淆了
- 因为源代码位于用户的设备中,可以从中提取代码。由于混淆后代码不友好,因此会阻止逆向工程,从而有助于保护知识产权。
- 反过来,这可以防止篡改代码并将其重新分发以供恶意使用。
但是,如此存在许多有助于消除应用程序代码混淆的工具。那就是其它话题了。。。
4.1 例子一:JavaScript混淆
JavaScript源代码:
- function hello(name) {
- console.log('Hello, ' + name);
- }
- hello('New user');
混淆后:
- var _0xa1cc=["\x48\x65\x6C\x6C\x6F\x2C\x20","\x6C\x6F\x67","\x4E\x65\x77\x20\x75\x73\x65\x72"];
- function hello(_0x2cc8x2){console[_0xa1cc[1]](_0xa1cc[0]+ _0x2cc8x2 "_0xa1cc[1]")}hello(_0xa1cc[2])
总结
从机密性,完整性,真实性分析四种密码技术:
- 加密,虽然是为了保证数据的机密性,但某些现代加密算法还采用了其他策略来保证数据的完整性(有时通过嵌入式哈希算法)和真实性。
- 哈希,只能保证完整性,但可以通过完整性对比来做权限控制,如:基于哈希的消息认证码(HMAC)和某些传输层安全性(TLS)方法。
- 编码,过去曾被用来表示加密,并在技术领域之外仍具有这种含义,但在编程世界中,它仅是一种数据处理机制,从未提供任何安全措施。
- 混淆,可以用来提高抵御攻击的能力;但是,它永远不能保证数据的机密性。狡猾的对手最终将绕过混淆策略。与编码一样,永远不要将混淆视为可靠的安全控制。
附录:哈希函数常用的哈希函数:
- MD5,一种被广泛使用的密码杂凑函数,可以产生出一个 128 位元(16 位元组)的哈希值,用于确保信息传输完整一致。*虽广泛,但过时。
- SHA-256/SHA512 , "加盐"。在比特币中,区块链使用SHA-256算法作为基础的加密哈希函数。
- 安全散列算法secure hash algorithm,是一个密码哈希函数家族。
- SHA家族有五个算法,分别是SHA-1,SHA-224,SHA-256,SHA-384,SHA-512
- 它们是美国的政府标准,后面的四个称之为SHA-2
- bcrypt:bcrypt算法相对来说是运算比较慢的算法。
在密码学界有句常话:越慢的算法越安全。算法越算,黑客破解成本越高:
通过salt和const这两个值来减缓加密过程,ta 的加密时间(百 ms 级)远远超过md5(大概1ms左右)。
对于计算机来说,Bcrypt 的计算速度很慢,但是对于用户来说,这个过程不算慢。
bcrypt是单向的,而且经过salt和cost的处理,使其受rainbow攻击破解的概率大大降低,同时破解的难度也提升不少。
相对于MD5等加密方式更加安全,而且使用也比较简单.
- 设计良好的密钥扩展算法,如PBKDF2,bcrypt,scrypt。
后记 & 引用
- How Secure Are Encryption, Hashing, Encoding and Obfuscation?[3]
- CTF 中那些脑洞大开的编码和加密[4]
- 散列文件的存储——‘桶’[5]
那么,如何保证密码在传输过程/储存的安全呢?
参考资料
How Secure Are Encryption, Hashing, Encoding and Obfuscation?: https://auth0.com/blog/how-secure-are-encryption-hashing-encoding-and-obfuscation/#What-is-Encoding-
引自:一篇文章彻底弄懂Base64编码原理: https://blog.csdn.net/wo541075754/article/details/81734770
How Secure Are Encryption, Hashing, Encoding and Obfuscation?: https://auth0.com/blog/how-secure-are-encryption-hashing-encoding-and-obfuscation/#What-is-Encoding-
CTF中那些脑洞大开的编码和加密: https://www.cnblogs.com/godoforange/articles/10850493.html
散列文件的存储——‘桶’: https://blog.csdn.net/Dearye_1/article/details/78492021