接口验签规则

一、验签的背景

在网络发展快速的过程中,总是会忽略接口数据安全问题,进行验签则能够在一定程度上能够防刷,数据篡改。

二、什么是加签验签

加签验签,

发送消息方,对消息加签名;

接受消息方,验证签名是否正确。

发送消息方:

1、根据消息内容形成摘要

2、根据摘要形成签名字段

3、发送消息

接受消息方:

1、接受消息

2、根据消息内容形成摘要

3、根据摘要去验证签名是否正确

三、实物电商验签规则

3.1 请求头 Header 增加参数

3.1.1 Expires:时间戳 单位 毫秒
3.1.2 X-Request-Id:(前端生成的随机数<数字加字母的组合>)
3.1.3 Signature:摘要 生成
  • signstr: 请求参数ASCALL表排序,再按照该顺序拼接成一个字符串
  • X-Request-Id:请求id
  • Expires:时间戳

公式:Signature = signstr + requestId + time

注意:

时间校准,空值的key 不参与ASCALL表排序

参考:

接口验签规则_第1张图片

可以参考下面的值来测试生成的签名是否正确

  1. Accept: application/json, text/plain, */*
  2. Accept-Encoding: gzip, deflate
  3. Accept-Language: en_US
  4. Authorization: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiIxNTk5NjM2NTUyOEAxNjMuY29tIiwic2NvcGUiOlsiYWxsIl0sImlkIjozNTU5LCJleHAiOjE2Njg1ODkxMjUsImF1dGhvcml0aWVzIjpbIuWJjeWPsOS8muWRmCJdLCJqdGkiOiIyZDAxMWVhOS02N2RjLTRmZmQtOTAwMS1jYTMwNTU1MzM0NzkiLCJjbGllbnRfaWQiOiJmcm9udC1hcHAifQ.AkKh_rTiIn1tckM-hvbM5o9lKEESd9TFz19W8xKDVcVisgwZ6tUTYcROB3JUdijGq-_7VnEnFjmjY3qXYeOHngo_ctDgw6KQqkDghSHGUDohI2SLXiTuHDZtp6H_f1wnTXYnHWqox7hwiNIWYbckkh4sRw6jkNDQAf6KfxccJ0Y
  5. Connection: keep-alive
  6. Cookie: _ga=GA1.1.500562097.1650948294; _ga_TZED0ZY3LF=GS1.1.1667983869.442.1.1667984325.0.0.0
  7. Expires: 1667984325369
  8. Host: h5.newsitunemall.com
  9. Referer: http://h5.newsitunemall.com/mine
  10. Signature: 1c356d047bcb10de8c1700ab3f3f25ec
  11. Source: h5
  12. User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36
  13. version: 1.0.82
  14. X-Request-Id: acc9d18b85159844ea89e758747ecfa3

3.2 时间校准逻辑

3.2.1 请求被动触发

接口验签规则_第2张图片

接口验签规则_第3张图片

具体接口:

接口:home/timestamp
方式:GET
返回:
{
    "code": 200,
    "message": "operation success",
    "data": 1668653868836,
    "timestamp": 1668653868836,
    "success": true
}
3.2.2 首页 主动触发

首页被用户点击的时候,主动请求一下接口,校准时间戳

3.2.3 前端验签规则:

接口验签规则_第4张图片

接口验签规则_第5张图片

接口验签规则_第6张图片

3.2.4 后端解签代码
public void checkSign(String sign, Map requestParam,String timestamp, String requestId, URI uri){
        if (StrUtil.isBlank(sign) || StrUtil.isBlank(timestamp) || StrUtil.isBlank(requestId)) {
            LOGGER.error("illegal request  sign:{} timestamp:{}  requestId:{}",sign,timestamp,requestId);
            throw new ApiException("illegal request,param is null!");
        }

        long time;
        try {
            time = Long.parseLong(timestamp);
        } catch (Exception e) {
            LOGGER.error("illegal request  timestamp不合法,timestamp:" + timestamp);
            throw new ApiException("timestamp illegal");
        }
        //验证时间戳是否过期
        long currentTime = System.currentTimeMillis();
        if (time > currentTime + timeOver || time < currentTime - timeOver) {
            LOGGER.error("illegal request  timestamp expires now:{} timestamp:{}",currentTime,time);
            throw new ApiException("please refresh");
        }

        if(redisTemplate.hasKey(requestId)){
            LOGGER.error("illegal request  requestId exist:{}",requestId);
            throw new ApiException("illegal request,requestId exist:"+requestId);
        }else{
            redisTemplate.opsForValue().set(requestId, requestId,timeOver, TimeUnit.MILLISECONDS);
        }
        String paramAscII = MapUtil.sortJoin(requestParam, "&", "=", true, requestId, timestamp);

        String md5 = new Digester(DigestAlgorithm.MD5).digestHex(paramAscII);
        if (!md5.equals(sign)) {
            LOGGER.error("illegal request,check sign fail! paramAscII:{} sourceSign:{}  sysSign:{}",paramAscII,sign,md5);
            throw new ApiException("illegal request,check sign fail");
        }
    }

你可能感兴趣的:(解决方案,后端,spring,boot,接口加签验签)