SecureApi使用文档SecureApi使用文档
主页
开始使用
版本历史
  • 中国大陆
  • 国际
  • 简体中文
  • English
主页
开始使用
版本历史
  • 中国大陆
  • 国际
  • 简体中文
  • English
  • 快速开始

    • 开始使用
    • 安装
    • 配置
    • 试一下
  • 指南

    • 注解
    • URL匹配
    • 异常处理
    • 加密算法
    • CipherUtils
    • 两种模式
    • DH密钥协商
    • 数字签名校验
  • JS示例
  • 最佳实践
  • 微服务调用
  • 黑金刚

两种模式

简介

前面章节介绍的加密模式中,有 common 和 session-key,先说结论, common 更方便, session-key 更安全。

common模式

commom 模式,需要前后端都保存一份相同的密钥或密钥对进行加解密。(接口加密不限于前后端,也可以是两台服务器通信,下面以前后端举例)

举例:

  • SecureApi 设置加密算法为 AES ,生成一个密钥,可以等待组件自动生成或使用 CipherUtils 生成,也可以使用在线网站生成,然后保存在 SecureApiPropertiesConfig 的 key 字段中,前端也保存此密钥,前端向后端发送使用该密钥加密后的数据,后端收到后用该密钥解密。

缺点:

  • 密钥存在前端有泄露风险(客户端被黑、被F12调试)
  • 密钥无法动态生成,需前后端商量好各自写死(明文密钥在网络中传输危险性大于存储在前端,需要接口加密的业务也绝对不会允许你在网络中传输明文密钥)

优点:

  • 实现简单,无需关心密钥协商问题
  • 性能高,密钥在前后端各自保存一份,无需额外的网络通信来协商密钥

session-key模式

session-key 模式需要同时使用 RSA 和 对称加密算法 配合实现,由前端为每次请求生成新的 对称加密密钥 (也可以每隔一段时间更新密钥),然后使用此密钥加密数据,再使用 RSA 公钥加密此密钥,把加密后的数据和密钥都传输给后端,后端使用 RSA 私钥解密得到 会话密钥,使用 会话密钥 解密数据,返回值就比较简单了,只需要使用 会话密钥 加密返回值给前端,前端使用 会话密钥 解密就可以了。

举例:

  • 后端使用 SecureApi 设置加密模式为 session-key ,指定加密算法为 RSA ,指定会话密钥加密算法为 AES ,生成 RSA 密钥对,保存在 SecureApiPropertiesConfig 的 publicKey 和 privateKey 字段中
  • 第一次通信:前端请求后端的 RSA 公钥
  • 第二次通信:前端使用后端 RSA 公钥加密任意数据,把加密后的数据传输给后端,后端使用自己的 RSA 私钥解密,如果能解密成功,告诉前端校验成功,如果解密失败,除了代码原因,说明第一次通信公钥传输过程中被篡改,需要重新生成 RSA 密钥对重新验证
  • 验证成功后,后续的的接口加密方式就是:前端为请求生成 会话密钥,使用 会话密钥 加密数据,再使用后端 RSA 公钥加密 会话密钥,把加密后的数据和密钥都传输给后端,后端可以写一个拦截器,把 会话密钥 保存到 SecureApiPropertiesConfig 的 key 字段中(无需自行解密),SecureApi 会自动使用 RSA 私钥解密得到 会话密钥,后续 SecureApi 也会自动使用 会话密钥 解密和加密数据了
  • 你可以为每个请求生成一个不同的会话密钥,也可以定时更新密钥,后端的 RSA 密钥对也可以定期重新更新,以增强安全性

缺点:

  • 可以看出,流程比较复杂
  • 每次请求生成新密钥并且后端使用 RSA 私钥解密密钥显然会损失更多的性能

优点:

  • 安全、安全、还是 TMD 安全

借助 SecureApi 实现 session-key 模式只需要下面简简单单的两个文件,代码示例:

@Bean
public SecureApiPropertiesConfig secureApiPropertiesConfig() {
    SecureApiPropertiesConfig secureApiPropertiesConfig = new SecureApiPropertiesConfig();
    secureApiPropertiesConfig.setEnabled(true);
    // 设置模式为 session-key
    secureApiPropertiesConfig.setMode(SecureApiProperties.Mode.SESSION_KEY);
    // 设置会话密钥算法
    secureApiPropertiesConfig.setSessionKeyCipherAlgorithm(CipherAlgorithmEnum.AES_ECB_PKCS5);
    // session-key 模式必须设置加密算法为 RSA
    secureApiPropertiesConfig.setCipherAlgorithmEnum(CipherAlgorithmEnum.RSA_ECB_SHA256);

    // 密钥可以不设置,组件会自动生成一个,并打印在控制台,如果需要手动生成,只需要使用组件提供的CipherUtils
    CipherUtils cipherUtils = new CipherUtils(CipherAlgorithmEnum.RSA_ECB_SHA256);
    // getRandomRsaKeyPair("1")可传入seed参数,在测试时可用于控制每次生成的密钥相同
    RsaKeyPair randomRsaKeyPair = cipherUtils.getRandomRsaKeyPair();
    // 把生成的密钥对设置到secureApiPropertiesConfig
    secureApiPropertiesConfig.setPublicKey(randomRsaKeyPair.getPublicKey());
    secureApiPropertiesConfig.setPrivateKey(randomRsaKeyPair.getPrivateKey());

    return secureApiPropertiesConfig;
}

在拦截器中把每次请求的 会话密钥 设置到 secureApiPropertiesConfig 的 key 值即可,后续操作全部由 SecureApi 自动完成

@Component
public class SecureKeyInterceptor implements HandlerInterceptor {
    private static final Logger log = LoggerFactory.getLogger(SecureKeyInterceptor.class);
    
    @Autowired
    private SecureApiPropertiesConfig secureApiPropertiesConfig;

    @Override
    public boolean preHandle(HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) {
        // 这里只需要在拦截器中修改secureApiPropertiesConfig的key值即可,后续操作全部由 SecureApi 自动完成
        if (secureApiPropertiesConfig.getMode().equals(SecureApiProperties.Mode.SESSION_KEY)) {
            String sessionKey = request.getHeader("sessionKey");
            log.info("前端传来会话密钥:{}", sessionKey);
            secureApiPropertiesConfig.setKey(sessionKey);
        }
        return true;
    }
}
在 Github 上编辑
最近更新:
编著者: XuYijie
Prev
CipherUtils
Next
DH密钥协商