公共接口安全设计方案

写作缘由

当我们与其他系统进行数据同步时,此时,别人的系统会请求我们的系统。此时,最重要的一个问题肯定就是安全问题了。因为他们直接请求我们的接口,所以我们必须释放我们接口的权限。但是如果我们完全释放,什么都不做约定,我们的接口很容易被非法网路操作者利用,从而获取我们的信息。

我们面临的安全问题有以下三种:

  1. 请求来源(身份)是否合法?
  2. 请求参数被篡改?
  3. 请求的唯一性(不可复制)

公共接口安全设计:

无约定

客户端:传递参数 http://localhost:8000/api/dataSync/informer?beginTime=1623764900000
服务端:接收参数-------进行数据库查询-------返回数据

    public Result<Object> getLastInformer(RequestParam long beginTime) {
    
    
    //直接进行数据库查询
    ----------------------------------------
      getInformers(beginTime);
    }

如上,这种方式简单粗暴,通过调用getInformers方法即可获取人员信息了,但是 这样的方式会存在很严重的安全性问题,没有进行任何的验证,大家都可以通过这个方法获取到人员信息,导致人员信息泄露。
那么,如何验证调用者身份呢?如何防止参数被篡改呢?

约定

客户端:

1.给客户端分配 key 和 secret (如:key:keyone secret: 1!@521);
2.客户端请求头上拼接一个时间戳
3.使用MD5加密(secret+请求参数+时间戳) 生成sign,作为参数传递

例如:
Long beginTime(查询时间,必填,13位时间戳 ) : 例如:1624628174000 表示要查询信息的开始时间
Long timeStamp(当前时间,必填,13位时间戳) : 例如:1624628174000 充当时间戳作用
String key (键,必填,值固定(datacenter))
String sign (签名,必填) 值: MD5处理(1!@521+beginTime+timeStamp)注意:1.+号在这里起链接作用,实际传参并没有 2.MD5使用字符编码为utf-8,加密后转换为16进制(小写)。解密后字母分全大写或全小写,我这里使用的是小写。

处理后生成请求路径:
地址+请求参数+key+sign+时间戳

http://localhost:8000/api/dataSync/case?beginTime=1624628174000&key=datacenter&sign=6064679340d45cca00d146a45e62217a&timeStamp=1626183517000

服务端:

    public Result<Object> getLastInformer(DataSyncVO dataSyncVO) {
    
    
    //查询是否有对应的key,有的话返回对应的secret 
    //判断时间戳是否过期
    //检验sign是否正确
    //以上均正确:进行查询
    ----------------------------------------
      getInformers(dataSyncVO);
    }

时间戳作用:虽然我们在客户端和服务器端做了约定,只要secret不暴漏,正常情况下我们的接口是不会被恶意请求的,但是我们sign还是拼接在url路径上的,所以一旦他们得到了其中一个请求路径,他就可以利用这个路径的sign随意请求了。我们加了时间戳之后,规定好该sign失效时间(比如说5分钟内),那么就算他拿到了我们的sign,使用时间也就只有五分钟,可以减轻信息暴漏的程度。

时间戳可能产生的问题:

  1. 前后端时区不同,如果客户端和开发人员和你不在同一个时区,那么很可能造成时区不一致而导致你们的时间不一致,前后误差几个小时。(双方确定号时区,使用统一的时区)
  2. 还有一种小概率可能是服务请求时,请求发送时间过长,服务端配置的该时间戳有效时间果短,导致拒绝访问(延长有效时间)。
  3. 时间戳虽然重要,但是并不是必须的,如果在信息并不是十分绝密的情况下,不使用时间戳也是完全可以的。

key 和 secret
如果多个客户端都需要我们的数据时,我们可以针对不同的客户,分配不同的key和secret。注意:secret一定要保密!

服务端校验示例

	@Data
	public class DataSyncVO {
    
    
	    private String key;
	    private String sign;
	    private Long beginTime;
	    private Long timeStamp;
	}
	
    public boolean checkPermission(DataSyncVO dataSyncVO) {
    
    
        if (ObjectUtil.isNotNull(dataSyncVO)) {
    
    
            if (ObjectUtil.isNull(dataSyncVO.getBeginTime())) {
    
    
                throw new BadRequestException("查询条件beginTime不能为空");
            }
        } else {
    
    
            throw new BadRequestException("参数不能为空");
        }
        //检验key是否存在
        String secret = EncodeEnum.getEncodeEnum(dataSyncVO.getKey());
         if (StrUtil.isEmpty(secret)){
    
    
            throw new BadRequestException("您无权访问");
        }
        //检验时间戳是否过期
         LocalDateTime timeStamp = LocalDateTime.ofEpochSecond(dataSyncVO.getTimeStamp() / 1000, 0, ZoneOffset.ofHours(8));
        LocalDateTime timeNow = LocalDateTime.now();
        Duration duration = Duration.between(timeStamp, timeNow);
        //相差的分钟数
        long minutes = duration.toMinutes();
        System.out.println(minutes);
        if (minutes >= 10) {
    
    
            throw new BadRequestException("您无权访问");
        }
        //获取sign
        String sign = secret + dataSyncVO.getBeginTime() + dataSyncVO.getTimeStamp();
        //服务端MD5加密
        byte[] digest = null;
        try {
    
    
            MessageDigest md5 = MessageDigest.getInstance("md5");
            digest = md5.digest(sign.getBytes("utf-8"));
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
        String md5Str = new BigInteger(1, digest).toString(16);//转为16进制
        //sign对比
        if (md5Str.equals(dataSyncVO.getSign())) {
    
    
            return true;
        } else {
    
    
            throw new BadRequestException("您无权访问");
        }
    }

注意:

加密算法

加密算法分为可逆加密和不可逆加密。

可逆加密又分为对称性加密和非对称性加密。
可逆加密: 能获取加密前数据。
不可逆加密(摘要加密): 获取不到加密前数据,只能将原数据使用相同方式加密,然后进行对比。(用户密码) MD5、SHA-1、SHA-256、HMAC
对称性加密: 加密解密使用同一把钥匙 AES、DES
非对称性加密分为公钥和私钥。对应的公钥解对应的私钥,对应的私钥解对应的公钥 RSA、DSA

推荐博文

对称加密与非对称加密使用场景
api接口签名验证(MD5)

Guess you like

Origin blog.csdn.net/zhang19903848257/article/details/118728669