基于Symfony的Web应用敏感数据安全存储与授权访问问题咨询
问题1:用户私钥的安全存储方案
你完全不用让普通用户手动管理私钥,采用「用户密码派生密钥加密私钥」的方案即可,流程如下:
- 用户注册时,客户端通过Web Crypto API生成用户专属的公私钥对,公钥直接明文上传服务端存储
- 用用户输入的登录密码,通过Argon2或PBKDF2算法派生一个对称加密密钥,用该密钥加密用户的私钥,将加密后的私钥密文上传服务端存储
- 用户每次登录时,输入密码后客户端用相同算法派生密钥,从服务端拉取加密后的私钥密文,在本地解密得到可用私钥,仅存储在浏览器内存中,页面关闭或退出登录时自动清除
这个方案里服务端仅存储加密后的私钥密文,没有用户登录密码无法解密,完全符合你要求的「服务端不持有可解密的密钥」规则,且用户仅需记住普通登录密码即可,无需额外操作,适配无技术背景的用户群体。
问题2:新增用户公钥的适配方案
你提到的第二种思路其实已经接近最优解,核心是用信封加密机制,刚好和openssl_seal()的设计逻辑完全匹配:
- 每次新增敏感数据时,生成一个随机的对称数据加密密钥(DEK),用DEK加密原始敏感数据得到密文存储在服务端
- 调用
openssl_seal()时,用所有当前有权限的用户公钥加密这个DEK,得到多份DEK密文,和原始敏感数据密文关联存储,PHP原生的openssl_seal()完全支持这个逻辑,不需要额外改造 - 新增有权限的用户时,不需要重新加密所有原始敏感数据,只需要找任意一个已有权限的用户,在客户端解密得到明文DEK,再用新用户的公钥加密DEK得到新的DEK密文,上传服务端和原数据关联即可
这种方案里服务端存储的DEK全是密文,没有用户私钥无法解密,完全符合你的安全要求,新增/删除权限用户都不需要触碰原始加密数据,效率极高。
问题3:思路正误核查
你的两个核心安全假设(密钥不落地服务端、解密全在客户端完成)是完全正确的,符合端侧加密的最佳实践,仅存在两个小的认知偏差:
- 私钥不一定需要明文存储在客户端或服务端,通过用户密码加密后存在服务端是行业通用的安全方案,不会泄露私钥
openssl_seal()本身就是为多用户解密同一份数据设计的信封加密实现,不需要对原始数据做全量重加密,仅需维护DEK的多份密文即可
落地补充注意点
- 所有客户端加解密操作优先调用浏览器原生Web Crypto API,不要自行实现加密算法逻辑
- 全程强制HTTPS传输,防止密码派生参数、加密私钥等内容在传输过程中被窃听
- 如果担心用户忘记密码导致私钥丢失,可以提前设置管理员恢复机制:用管理员公钥额外加密一份DEK密文存储,用户密码丢失时可由管理员协助恢复权限。
内容的提问来源于stack exchange,提问作者Émile Perron
相关产品推荐
相关产品推荐

