Laravel使用用户专属密钥实现密码加密解密的方案咨询
基于Laravel实现用户自持密钥的密码管理软件方案
核心前提
- 所有用户的密码数据加密密钥仅在用户侧留存,服务端全程不持久化存储该密钥,也无权获取明文密钥
- 密钥派生、加解密的敏感操作优先放在前端执行,降低密钥泄露风险
实现流程
1. 用户密钥生成逻辑
用户注册时完成以下操作:
- 前端引导用户设置独立的库主密码(和登录密码可共用,推荐单独设置,安全等级更高)
- 服务端为每个用户生成独立的16位随机盐值,存入用户表,盐值仅用于密钥派生,可公开存储无泄露风险
- 前端使用Argon2id或PBKDF2算法,结合用户输入的库主密码+服务端返回的用户盐值,派生得到32位长度的AES-256加密密钥,该密钥仅保存在前端内存中,用户登出/关闭页面后立即销毁,全程不主动上传到服务端
2. 加解密实现方案
有两种可选实现方案,可根据业务安全等级选择:
方案1:前端加解密+Laravel仅存密文(安全等级最高,推荐)
所有加解密操作全部在前端用Web Crypto API或crypto-js完成,Laravel服务端仅负责存储密文、校验用户登录状态,全程不接触明文密码数据和用户加密密钥,完全符合零知识要求。
对应Laravel侧仅需要做密文的增删改查操作,无需处理加密逻辑:
// 存储用户上传的密文数据 auth()->user()->passwordEntries()->create([ 'platform' => $request->input('encrypted_platform'), 'account' => $request->input('encrypted_account'), 'password' => $request->input('encrypted_password'), ]);
方案2:Laravel临时密钥加解密(开发成本更低)
如果前端加解密开发成本太高,可选择将用户密钥临时通过HTTPS请求头传给后端,Laravel用自定义密钥完成加解密,请求处理完成后立即销毁密钥,不做任何持久化存储。
Laravel的Encrypter原生支持自定义密钥,无需修改核心源码,实现代码如下:
use Illuminate\Encryption\Encrypter; // 从请求头获取用户临时传入的密钥,禁止日志记录该请求头 $userKey = request()->header('X-User-Enc-Key'); // 校验密钥合法性,AES-256-GCM要求密钥长度为32位 if (strlen($userKey) !== 32 || !ctype_print($userKey)) { abort(400, '无效的加密密钥'); } // 实例化自定义加密器,使用AES-256-GCM算法 $customEncrypter = new Encrypter($userKey, 'AES-256-GCM'); // 加密明文密码 $encryptedPwd = $customEncrypter->encrypt($request->input('plain_password')); // 解密密文 $plainPwd = $customEncrypter->decrypt($userPasswordEntry->password);
必须遵守的安全规则
- 全程禁止将用户加密密钥存储到服务端的数据库、缓存、日志、Session、Cookie等任何持久化存储介质中
- 全链路必须使用HTTPS协议,防止临时传输的密钥被窃听
- 禁止使用Laravel默认的
APP_KEY加密用户的密码数据,该密钥为服务端全局持有,不符合用户自持密钥的要求 - 用户丢失库主密码后,服务端无法恢复加密的密码数据,需要提前引导用户备份主密码或密钥派生助记词
- 不要在服务端日志中打印任何和用户密钥、明文密码相关的内容,生产环境需要关闭请求参数全量日志
内容的提问来源于stack exchange,提问作者Amardeep Dubey
相关产品推荐
相关产品推荐

