我设计的一个安全的 web 系统用户密码管理流程
作为一名有多年经验的前端,在刚开始学习web后端的时候,就对如何设计一个安全的 web 系统用户密码管理流程有很多疑问。之前自己也实践过几种方法,但一直觉得不是十分安全。
我们知道,用户在注册或登录界面填写的密码是明文的,我们需要将密码安全的传输到后端,保存到数据库,或者完成登录校验。
我一开始担心的是在网络传输中造成密码的泄露,所以确定了以下方案,1. 使用 https; 2. 使用 rsa 公钥加密。具体流程如下:
注册流程:前端获取公钥 -> 前端用公钥加密明文密码 -> https 传输给后端 -> 后端私钥解密(确保密文是可以解密的) -> 存入密文至数据库
登录流程:前端获取公钥 -> 前端用公钥加密明文密码 -> https 传输给后端 -> 后端私钥解密,读取数据库密文并解密 -> 对比密码是否一致
在这样设计了以后,很快被后端同学打脸。你在私钥被窃且拖库的情况下,所有用户的明文密码都会被解密出来。
很快,我经过思考后,调整了流程
注册流程:前端获取公钥 -> 前端用公钥加密明文密码 -> https 传输给后端 -> 后端私钥解密得到明文密码 -> 生成随机盐 -> 明文密码+盐并计算 hash 值 -> 存入 hash 值至数据库
登录流程:前端获取公钥 -> 前端用公钥加密明文密码 -> https 传输给后端 -> 后端私钥解密得到明文密码 -> 读取数据库用户信息得到该用户盐值 -> 明文密码+盐并计算 hash 值 -> 对比计算出来的 hash 值和数据库中的 hash 值是否一致
经过这样的设计以后,数据库中就没有任何用户明文密码了。即便私钥被窃且被拖库,所有用户的明文密码都不会泄露。
我自己开发的某个系统,用这样的设计跑了很久,也没有遇到什么问题。但是最近我再思考这个问题的时候发现,这样还是不安全。
假设,服务器的 root 权限被攻破,黑客可以通过修改程序,直接打印私钥解密明文密码的结果,这样,用户的明文密码还是会被泄露。
怎么办?我再想了很久,发现,只要增加一个流程,即可避免这个问题。
注册流程:前端获取公钥 -> 前端将明文密码取 hash 值 -> 前端用公钥加密 hash 值 -> https 传输给后端 -> 后端私钥解密得到前端传的 hash 值 -> 生成随机盐 -> hash 值+盐并计算二次 hash 值 -> 存入 二次hash 值至数据库
登录流程:前端获取公钥 -> 前端将明文密码取 hash 值 -> 前端用公钥加密 hash 值 -> https 传输给后端 -> 后端私钥解密得到前端传的 hash 值 -> 读取数据库用户信息得到该用户盐值 -> hash 值 +盐并计算 hash 值 -> 对比计算出来的 hash 值和数据库中的 hash 值是否一致
通过这样的设计,明文密码只存在用户前端填写的表单上,在传输过程中,以及程序运行和数据存储中,都是没有明文密码的。也就是说,即便私钥被窃,数据库被拖库,服务器 root 权限被攻陷,整个系统崩溃,用户的明文密码依然被保护二不会泄露。
我将我的设计扔给 deepseek,它表示这样的设计已经是非常高等级的安全了。同时,它表示,如果要实现金融级别的安全,还需要做如下完善:
- 给每个请求分配一个随机盐值,让前端用明文密码加随机盐值计算 hash ,确保每次用户传输的数据中的 hash 值是不一样的,防止被彩红攻击。
- 对接口请求进行频次限制,防治被暴力破解。
我觉得除非是真的开发金融及的应用,否则上面两点增加的复杂度不值得一般的小的系统。所以,我就不打算在我开发的这个小的工具系统里采用这样高等级的措施了。
那么各位看官,您觉得还有没有更好的实现方式呢?
一位多年后端开发经验的老哥给我讲,你想得太TM复杂了,绝大多数系统都是 https + 明文密码传输的,后端弄个盐在数据库存个 hash 就算很注重安全了……我听后大为震惊……