目录

前端加解密实践:从「别明文传密码」开始

每次提到前端加密,评论区都会有人说:

有 HTTPS 了,还加什么密?
前端代码都是能看到的,没意义。

理论上没错,但在金融/政企等场景里,有些需求不是技术可不可行,而是「要不要多一层安全防护 + 满足合规要求」

这篇文章从实战出发,聊聊:

  • 常见的前端加密需求;
  • 对称 / 非对称加密如何组合使用;
  • 以及实际落地时的一些坑。

1. HTTPS 已经有了,为啥还要前端加密?

先说前提:HTTPS 必须有,这是基础。
在这个基础上,某些场景仍然会要求:

  1. 防止明文敏感信息出现在抓包里

    • 即便是 HTTPS,有些合规要求会明确写「不得以明文形式传输密码等敏感信息」;
    • 抓包截图里看到一串密文,和直接看到手机号/密码,感受是不一样的。
  2. 降低中间层日志泄露风险

    • 有时候请求会经过网关、代理、日志系统;
    • 如果这些地方有不规范的日志记录,敏感字段加密可以降低损害。
  3. 和现有后端架构/第三方接口对齐

    • 有些历史系统已经约定「密码字段用某种算法加密再传」;
    • 前端需要遵守既有协议。

前端加密不是代替 HTTPS,而是多一层「应用层加密」。


2. 两个基本工具:对称 & 非对称

简单回顾一下:

  • 对称加密(如 AES、SM4):同一把 key 加密解密;
  • 非对称加密(如 RSA):公钥加密,私钥解密(或反之)。

特性:

  • 对称加密:速度快,适合加密大量数据,但key 如何安全分发是问题;
  • 非对称加密:适合做「密钥交换」,但加密大数据性能较差。

所以常用组合是:

前端生成一个随机对称密钥 → 用后端公钥加密这个密钥 → 发给后端 → 后端用私钥解出密钥 → 后续用这个对称密钥加解密数据。

前端常见实现方式:

  • WebCrypto API;
  • 或成熟的 JS 加密库(CryptoJS / JSEncrypt / 国密相关库等)。

3. 一个典型的前端加密流程

以「登录密码不可明文传输」为例,设计一个简化流程:

3.1 拉取公钥

在进入登录页或打开系统时:

const resp = await api.getEncryptConfig();
// resp.publicKey / resp.keyId

接口返回:

{
  "keyId": "20220526",
  "publicKey": "-----BEGIN PUBLIC KEY-----...",
  "algorithm": "RSA"
}

前端缓存 publicKeykeyId

3.2 构造待加密数据

用户提交表单时,把密码打包:

const payload = JSON.stringify({
  password: plainPassword,
  timestamp: Date.now(),
});

3.3 使用公钥加密

借助加密库,例如:

import JSEncrypt from 'jsencrypt';

const encryptor = new JSEncrypt();
encryptor.setPublicKey(publicKey);
const cipher = encryptor.encrypt(payload);

3.4 携带 keyId 与密文

请求参数变为:

{
  "username": "test-user",
  "password": "Base64EncodedCipher",
  "keyId": "20220526"
}

后端据此:

  • 通过 keyId 找到对应私钥;
  • 解密出原始 payload
  • 再继续后续登录逻辑。

更高级一点的做法是上面提到的「前端用公钥加密对称密钥,再用对称密钥加密密码」,这里就不展开。


4. 实战中的几个常见坑

4.1 字符编码和长度

非对称加密(比如 RSA)对加密数据长度有限制:

  • 与 key 长度、填充方式有关;
  • 明文过长会导致加密失败。

解决方式:

  • 密码这种短字符串直接 RSA 问题不大;
  • 大字段(如 JSON 整包)用对称加密,再用 RSA 保护对称密钥。

同时注意:

  • 使用统一的编码(UTF-8);
  • 加密后用 Base64 进行传输。

4.2 性能问题

  • 加密/解密是 CPU 密集型操作;
  • 手机低端机上做多次 RSA 运算会有明显卡顿。

经验:

  • 只加密真正敏感的小字段(密码、交易 PIN 等);
  • 不要整页所有字段都做复杂加密;
  • 可以在「点击提交」时再进行加密,避免输入过程中阻塞。

4.3 密钥轮换

  • 公钥/私钥不可能永久不变;
  • 需要支持「新老 key 并存一段时间」。

前端配合方式:

  • 每次从服务端获取最新加密配置(可能包含多个 key);
  • 请求里带上 keyId,后端据此选用对应私钥解密;
  • 一段时间后下线老 key。

4.4 别把私钥/对称密钥塞前端

看似废话,但现实中真的有人这么干:

  • 在前端写死一个对称密钥;
  • 或者把私钥打进前端代码。

这两种做法都等于「没加密」,只会增加维护成本。
对称密钥和私钥都应该只存在于受控后端环境里。


5. HTTPS + 前端加密的边界

前端加密能防什么?

  • 防止敏感字段明文出现在抓包/中间日志里;
  • 满足某些「应用层加密」的合规要求;
  • 在后端内部链路转发时,即使某一环节日志没做好脱敏,也能减轻泄露影响。

它不能防什么?

  • 不能防止前端代码被调试、篡改(因为代码在用户手里);
  • 不能单独依赖它做「反爬/防脚本登录」;
  • 不能取代服务端的登录限流、风控、二次校验等安全手段。

所以把它当成:

安全体系里的一个「配角」,而不是主角。


6. 实战小 Checklist

如果你准备在前端上加一层加密,可以过一遍这个小清单:

  1. 业务/合规到底要求保护哪些字段?
  2. 是否已经有统一的「加密服务」接口(公钥下发、密钥轮换)?
  3. 前端是否使用成熟的加密库,还是要考虑国密算法?
  4. 是否评估过性能(尤其是移动端)?
  5. 错误处理是否友好(加密失败、配置获取失败)?
  6. 日志里是否避免输出密文原文、避免泄露敏感上下文?

7. 总结

前端加解密这个话题很容易被走极端:要么觉得「完全没用」,要么什么都想加密。
比较理性的做法是:

  1. 先确认业务和合规的真实诉求;
  2. 在 HTTPS 的基础上,对关键敏感字段加一层应用层保护;
  3. 用对称 + 非对称组合处理好「性能 vs 安全」;
  4. 避免自创算法,用成熟方案 + 足够的工程防守。

最后再强调一遍:安全永远是一个整体方案,前端加密只是其中一环,做对了能加分,做错了只能徒增复杂度。