密码
HTTPS 用明文传输密码的问题,看到很多次了,个人观点不赞成,单开个帖 - V2EX



1.HTTP
2.HTTPS
HTTPS 解决数据传输安全问题的方案就是使用加密算法,具体来说是混合加密算法,也就是对称加密和非对称加密的混合使用,这里有必要先了解一下这两种加密算法的区别和优缺点。
2.1 对称加密
对称加密,顾名思义就是加密和解密都是使用同一个密钥,常见的对称加密算法有 DES、3DES 和 AES 等,其优缺点如下:
- 优点:算法公开、计算量小、加密速度快、加密效率高,适合加密比较大的数据。
- 缺点:
- 交易双方需要使用相同的密钥,也就无法避免密钥的传输,而密钥在传输过程中无法保证不被截获,因此对称加密的安全性得不到保证。
- 每对用户每次使用对称加密算法时,都需要使用其他人不知道的惟一密钥,这会使得发收信双方所拥有的钥匙数量急剧增长,密钥管理成为双方的负担。对称加密算法在分布式网络系统上使用较为困难,主要是因为密钥管理困难,使用成本较高。
从图中可以看出,被加密的数据在传输过程中是无规则的乱码,即便被第三方截获,在没有密钥的情况下也无法解密数据,也就保证了数据的安全。但是有一个致命的问题,那就是既然双方要使用相同的密钥,那就必然要在传输数据之前先由一方把密钥传给另一方,那么在此过程中密钥就很有可能被截获,这样一来加密的数据也会被轻松解密。那如何确保密钥在传输过程中的安全呢?这就要用到非对称加密了。
2.2 非对称加密
非对称加密,顾名思义,就是加密和解密需要使用两个不同的密钥:公钥(public key)和私钥(private key)。公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密;如果用私钥对数据进行加密,那么只有用对应的公钥才能解密。非对称加密算法实现机密信息交换的基本过程是:甲方生成一对密钥并将其中的一把作为公钥对外公开;得到该公钥的乙方使用公钥对机密信息进行加密后再发送给甲方;甲方再用自己保存的私钥对加密后的信息进行解密。如果对公钥和私钥不太理解,可以想象成一把钥匙和一个锁头,只是全世界只有你一个人有这把钥匙,你可以把锁头给别人,别人可以用这个锁把重要的东西锁起来,然后发给你,因为只有你一个人有这把钥匙,所以只有你才能看到被这把锁锁起来的东西。
- 优点:算法公开,加密和解密使用不同的钥匙,私钥不需要通过网络进行传输,安全性很高。
- 缺点:计算量比较大,加密和解密速度相比对称加密慢很多。
2.3 HTTPS
2.3.1 HTTPS = HTTP + SSL / TLS

2.3.2 流程
HTTPS(Hypertext Transfer Protocol Secure)是通过在传统的HTTP协议上加入SSL(Secure Sockets Layer)或TLS(Transport Layer Security)协议层来加密数据的。以下是HTTPS加密数据的基本步骤:
- 建立连接:
- 用户通过浏览器访问一个HTTPS网站。
- 服务器向浏览器发送它的SSL/TLS证书,这个证书通常由第三方证书颁发机构(CA)签发,包含服务器的公钥。
- 验证证书:
- 浏览器检查证书的有效性,包括证书是否由受信任的CA签发,证书是否过期,以及证书中的域名是否与访问的网站匹配。
- 如果证书验证通过,浏览器会生成一个随机的对称密钥(会话密钥)。
- 密钥交换:
- 浏览器使用服务器的公钥加密这个对称密钥,并将其发送给服务器。
- 服务器使用自己的私钥解密这个对称密钥。
- 加密通信:
- 一旦双方都有了这个对称密钥,它们就可以使用它来加密和解密通信数据。
- 对称加密算法(如AES)用于加密数据,因为它们在加密和解密时使用相同的密钥,而且速度相对较快。
- 安全通信:
- 从现在开始,所有的HTTP请求和响应都会被这个对称密钥加密,确保数据在传输过程中的安全。
- 即使数据被拦截,攻击者没有密钥也无法解密数据。
这个过程的关键点在于:
- 非对称加密:用于安全的密钥交换,确保对称密钥在传输过程中不被窃取。
- 对称加密:用于实际的通信加密,因为它的速度更快,适合加密大量数据。
- 证书验证:确保通信双方的身份是可信的,防止中间人攻击。
HTTPS的加密机制大大提高了数据传输的安全性,保护用户数据免受窃听和篡改。
图6. B站 CA 证书

图7. 浏览器安全警告
2.3.3 为什么只用非对称来传输对称密钥
HTTPS使用非对称加密来传输对称密钥的原因主要与加密效率、性能和安全性有关。
- 加密效率:非对称加密算法(如RSA、ECC)的加解密速度通常比对称加密算法(如AES、ChaCha20)慢得多。非对称加密涉及到复杂的数学运算,特别是在处理大量数据时,其性能远不如对称加密。因此,如果直接使用非对称加密对整个通信过程的所有数据进行加密,会大大降低传输效率。
- 性能开销:由于非对称加密的加解密速度慢,它会导致服务器和客户端的CPU负担加重,特别是在高流量的Web服务器上,这种性能开销是不必要的。
- 密钥管理:非对称加密需要一对密钥(公钥和私钥),而对称加密只需要一个密钥。在大量客户端和服务器之间进行通信时,使用对称加密可以简化密钥管理。每个客户端与服务器之间的通信只需要生成和使用一个临时的对称密钥。
| 特性 | HTTP | HTTPS |
|---|---|---|
| 安全性 | 数据以明文传输,不安全 | 数据加密传输,安全 |
| 加密 | 无 | 使用SSL/TLS加密 |
| 端口号 | 默认80 | 默认443 |
| 认证 | 不提供服务器身份验证 | 提供服务器身份验证(通过CA证书) |
| 性能 | 消耗资源较少 | 消耗资源较多,可能导致稍慢的传输速度 |
| 连接方式 | 无状态的明文连接 | 加密的握手过程,建立安全连接 |
| HSTS | 不支持 | 支持HSTS策略,强制使用HTTPS |
| 应用场景 | 适用于不涉及敏感信息的网站 | 适用于需要处理敏感信息的网站,如电子商务、在线银行等 |
3.密码存储
3.1 明文存储
这是最不安全的方式,直接将密码以明文形式存储在数据库中。这种方式存在极大的安全风险,因为一旦数据库被泄露,所有用户的密码都会暴露。
| 密码 | 存储 |
|---|---|
| Bb123456. | Bb123456. |
3.2 哈希存储
将密码进行哈希处理后存储在数据库中。哈希是一种单向函数,可以将输入数据转换成固定长度的摘要,但无法从摘要中恢复原始数据。常用的哈希算法包括SHA-256、SHA-1、MD5等。
| 密码 | 存储 |
|---|---|
| Bb123456. | 668f050e6d8992526f4b6936e1dbcf70 |

3.3 哈希加盐存储
在哈希的基础上,添加一个随机的盐值。盐值是唯一的,并且与每个用户的密码相关联。这种方式可以防止使用预计算的哈希表(如彩虹表)进行攻击。
- 系统随机生成一个盐值,例如:
$2a$10$N9qo8uLOickgx2ZMRZoMyeOZyYVfYJ3OJvM3VgI - 这个盐值应该足够长(通常至少64位),并且足够随机,以确保每个用户的盐值都是唯一的。
- 将盐值与密码连接起来,例如:
Bb123456.$2a$10$N9qo8uLOickgx2ZMRZoMyeOZyYVfYJ3OJvM3VgI - 使用哈希函数(如bcrypt)对组合后的字符串进行哈希处理
- 将盐值存储在数据库中,与用户账户关联
- 将哈希值也存储在数据库中,与盐值关联
| 密码 | 盐 | 存储 |
|---|---|---|
| Bb123456. | 10$N9qo8uLOickgx2ZMRZoMyeOZyYVfYJ3OJvM3VgI | 10$N9qo8uLOickgx2ZMRZoMyeOZyYVfYJ3OJvM3VgI.hqZrOAnYi2 |
3.4 密文存储
使用加密算法(如AES)将密码加密后存储在数据库中。这种方式需要妥善管理加密密钥,以确保加密的安全性。
| 密码 | 密钥 | 存储 |
|---|---|---|
| Bb123456. | kuaijin | U2FsdGVkX187L7gNPCKNC/Qu34BHPyqTOkXuuOjY5e0= |
3.5 哈希加盐密文存储
结合哈希加盐和密文存储的方式,先对密码进行哈希加盐处理,然后将哈希值加密后存储在数据库中。
3.6 使用专用密码哈希函数:
使用专门为密码哈希设计的函数,如bcrypt、scrypt或Argon2。这些函数不仅进行哈希加盐处理,还故意设计得较慢,以增加暴力破解的难度。
import org.mindrot.jbcrypt.BCrypt;
public class BCryptTest {public static void main(String[] args) { String pwd = "123456"; String encodePwd = BCrypt.hashpw(pwd, BCrypt.gensalt()); // 加密,核心代码 System.out.println(encodePwd); boolean flag = BCrypt.checkpw(pwd, encodePwd); // 验证加密是否正确 System.out.println(flag); }}
//输出://$2a$10$EKXOFOjn2Bve3t45194KkOdzGzywmeRw3yeekVf.YeURs2Z4.IaHi//true同一个密码,每次生成的hash都是不一样的。
既然每次hash都不一样,那么如何判断加密是否正确呢? 是这样的:在加密的时候,先随机获取salt,然后跟password进行hash。在下一次校验的时候,从hash中取出salt,salt跟password进行hash,得到的结果跟保存在在数据库的hash进行比较。
生成的密码中,$是分割符,无意义;2a是bcrypt加密版本号;10是cost的值(默认值);而后的前22位是salt值;再然后的字符串就是密码的密文了
BCrypt是单向的,而且经过salt和cost的处理,使其受rainbow攻击破解的概率大大降低,同时破解的难度也提升不少
| 密码 | 密钥 | 存储 |
|---|---|---|
| Bb123456. | kuaijin | 10$WPRrebJ/h/1az3znpXa3iO.WysJRwtDWZLjfioWeVrggTJfmjCOfK |
3.7 MFA(Multi-Factor Authentication 多因素认证)
2FA(Two-Factor Authentication 双因素认证)的实现方式:
- 密码 + 短信验证码

- 密码 + 硬件令牌

- 密码 + 生物识别(指纹/面部/虹膜)
- 密码 + USB安全密钥
- 密码 + 智能卡
- 密码 + 电子邮件验证码
- 密码 + 行为分析
- 密码 + 地理位置验证
- 密码 + 时间限制
TOTP(Time-Based One-Time Password 基于时间的一次性密码)的应用:
- TOTP(身份验证应用)可以离线


3.8 密码管理器
使用密码管理器生成和存储复杂的随机密码,用户只需记住一个主密码即可。
你连 HTTPS 原理都不懂,还讲”中间人攻击”? - 掘金