Java API加密 从sign签名验证到RSA、AES数据加密的实际应用

目录

 

前言

一. 传输加密思路

二. 加密操作的具体实现过程

1. 客户端sign签名的生成规则

2. 服务端验证

3. 服务端数据加密以及数据返回

4. 客户端解密数据

三. 总结


 

前言

在新一轮需求中,我方系统需要与某一系统进行数据传输,由于这些数据需要保证安全不外泄,并在后期交付时要做等保检测,因此在设计接口实现时,需要保证数据传输的安全性。

 

一般来说,API接口的安全性能一般要考虑以下几点:

1. 接口请求来源合法。

2. 数据传输途中不能被篡改。

A. 请求参数不能被篡改。

B. 返回结果不能被篡改。

3. 数据加密返回,保证数据安全。

4. 防重放攻击。即将拦截请求的参数,重新用于接口调用。

5. 防伪装攻击。这种情况一般是token被劫持时,攻击者伪装请求。

 

 

一. 传输加密思路

 

下文中,客户端皆指接口请求方,服务端皆指提供API的接口提供方。

 

本次接口开发中的大体思路如下:

1. 客户端生成sign签名,调用服务端接口。

2. 服务端对sign签名进行验证。

3. 服务端对验证成功的请求,返回加密数据。

4. 客户端接收加密数据,解密并使用。

 

 

二. 加密操作的具体实现过程

 

服务端API接口详情:

URL:IP:PORT/api/getSecretData

请求方式:POST

请求头:Content-type:application/json

这里省略了其他业务参数,示例参数如下:

timestamp
nonce
sign

 

1. 客户端sign签名的生成规则

以上参数中,加入sign签名,保证在未获取license以及其具体算法未被破解前的数据无法篡改;加入timestamp时间戳让sign签名更具变化;加入timestamp和nonce的组合以防止重放攻击。

 

参数生成规则说明:

A. nonce取的是随机数再MD5的值。

B. sign的生成则是将所有参数拼接后取MD5特征码再转base64。

 

客户端sign签名的Java生成代码,代码中的工具类见文末

    
  // 生成nonce
  public String generateNonce(long timestamp) {
    return Md5Util.encrypt(String.valueOf(new Random(timestamp)));
  }

  // sign生成
  public String generateSign(long timestamp, String nonce) {
    String data = "license=" + license + "&timestamp=" + timestamp + "&nonce=" + nonce;
    String encrypt = Md5Util.encrypt(data);
    return RSAUtil.str2Base64(encrypt);
  }

 

2. 服务端验证

接收到客户端请求的数据之后,服务端需要验证请求参数是否被修改,验证sign签名是否正常。

 

参数校验:

A. 首先验证时间戳,确定该请求处于当前时间的60s以内。

B. 验证nonce,在redis中查看24小时内的数据中是否存在该nonce。

C. 验证sign签名,将服务端提供的license等字段拼接,根据sign生成的相同规则判断sign的正确性。

 

服务器验证Java代码

  // 验证时间
  public boolean checkTime(long timestamp) {
    long current = System.currentTimeMillis();
    return current <= (timestamp + 60 * 1000);
  }

  // 验证nonce
  public boolean checkNonce(String nonce) {
    String key = "nonce";
    Set<String> nonceList = redisTemplate.opsForValue().get(key);
    if (CollectionUtils.isEmpty(nonceList)) {
      nonceList = new HashSet<>();
    }
    else if (nonceList.contains(nonce)) {
      return false;
    }
    nonceList.add(nonce);
    redisTemplate.opsForValue().set(key, nonceList, 24, TimeUnit.HOURS);
    return true;
  }
 

  // 验证签名
  // data为参数拼接字符串
  public boolean checkSign(String data, String sign) throws IOException {
    String str = RSAUtil.base642Str(sign);
    return Md5Util.matches(data, str);
  }

 

 

3. 服务端数据加密以及数据返回

当上述的请求验证通过后,服务端从库中获取数据后,并对要返回的数据进行加密操作。

 

数据加密流程:

A. 生成AES密钥种子(以下称为种子),这里的种子可以通过任意方法生成。

B. 使用种子生成AES密钥,并加密数据。

C. 使用RSA公钥加密种子。

D. 将加密数据以及种子的密文封装,并转为base64编码发送给客户端。

 

数据加密代码实例:

  // 加密数据
  public static String encryptContent(String content, String seed) throws Exception {
    Map<String, String> map = new HashMap<>();
    String key = Md5Utils.encrypt(seed + System.currentTimeMillis());
    // 内容AES加密
    String contentAES = AESUtils.encrypt(content, key);
    // 种子RSA加密
    String encryptSeed = RSAUtils.encrypt(key);
    map.put("key", encryptSeed);
    map.put("value", contentAES);
    System.out.println("==============map============");
    System.out.println(map);
    // 转为base64
    return Base64Utils.str2Base64(JSONObject.toJSONString(map));
  }

 

 

4. 客户端解密数据

客户端接收到数据后,将数据解密后即可。

 

数据解密流程:

A.  base64编码转换后,获取到封装的key,value数据。

B. 用RSA的私钥解密种子。

C.将种子用来解密加密数据,并最终获取到数据。

 

对应解密代码实例:

  // 客户端接收数据并解密
  public void decryptData(String str) {
    try {
      String content = Base64Utils.base642Str(str);
      JSONObject json = JSONObject.parseObject(content);
      String key = (String) json.get("key");
      String value = (String) json.get("value");
      String seed = RSAUtils.decrypt(key);
      String originData = AESUtils.decrypt(value, seed);
      System.out.println("============originData==========");
      System.out.println(originData);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

 

代码可以参考:git地址

 

参考文章:

如何保证API接口的安全性

签名参数sign生成说明

Java AES Encryption

Java AES encryption and decryption

 

三. 总结

 

本次加密传输,大体上解决了请求数据被篡改、请求数据被重放攻击、返回数据易被破解等问题。但是,由于本次的API加解密,涉及的知识点比较多,对其中的一些概念和用法还没理解透彻,因此整体上,接口的漏洞仍旧存在,功能有待完善。

 

 

 

 

 

 

 

 

 

 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值