如何设计安全可靠的开放接口---还有哪些安全保护措施

【如何设计安全可靠的开放接口】系列

1. 如何设计安全可靠的开放接口—之Token
2. 如何设计安全可靠的开放接口—之AppId、AppSecret
3. 如何设计安全可靠的开放接口—之签名(sign)
4. 如何设计安全可靠的开放接口【番外篇】—关于MD5应用的介绍
5. 如何设计安全可靠的开放接口—还有哪些安全保护措施
6. 如何设计安全可靠的开放接口—对请求参加密保护
7. 如何设计安全可靠的开放接口【番外篇】— 对称加密算法

前言

上一篇我们通过签名机制完成了身份确认,数据防篡改这两项非常重要的工作,不过如果仅仅如此是不能满足一个安全可靠的接口要求的,本节我们接着来看看,还有哪些是我们还需要补充的。

timestamp

前面在接口设计中,我们使用到了timestamp,这个参数主要可以用来防止同一个请求参数被无限期的使用。

稍微修改一下原服务端校验逻辑,增加了5分钟有效期的校验逻辑。

private static void serverVerify(String requestParam) throws Exception {
    APIRequestEntity apiRequestEntity = JSONObject.parseObject(requestParam, APIRequestEntity.class);
    Header header = apiRequestEntity.getHeader();
    UserEntity userEntity = JSONObject.parseObject(JSONObject.toJSONString(apiRequestEntity.getBody()), UserEntity.class);
    // 首先,拿到参数后同样进行签名
    String sign = getSHA256Str(JSONObject.toJSONString(userEntity));
    if (!sign.equals(header.getSign())) {
        throw new Exception("数据签名错误!");
    }
    // 从header中获取相关信息,其中appSecret需要自己根据传过来的appId来获取
    String appId = header.getAppId();
    String appSecret = getAppSecret(appId);
    String nonce = header.getNonce();
    String timestamp = header.getTimestamp();
    
    // 请求时间有效期校验
    long now = LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    if ((now - Long.parseLong(timestamp)) / 1000 / 60 >= 5) {
        throw new Exception("请求过期!");
    }
    
    cache.put(appId + "_" + nonce, "1");
    // 按照同样的方式生成appSign,然后使用公钥进行验签
    Map<String, String> data = Maps.newHashMap();
    data.put("appId", appId);
    data.put("nonce", nonce);
    data.put("sign", sign);
    data.put("timestamp", timestamp);
    Set<String> keySet = data.keySet();
    String[] keyArray = keySet.toArray(new String[0]);
    Arrays.sort(keyArray);
    StringBuilder sb = new StringBuilder();
    for (String k : keyArray) {
        if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名
            sb.append(k).append("=").append(data.get(k).trim()).append("&");
    }
    sb.append("appSecret=").append(appSecret);
    if (!rsaVerifySignature(sb.toString(), appKeyPair.get(appId).get("publicKey"), header.getAppSign())) {
        throw new Exception("验签错误!");
    }
    System.out.println();
    System.out.println("【提供方】验证通过!");
}

nonce

nonce值是一个由接口请求方生成的随机数,在有需要的场景中,可以用它来实现请求一次性有效,也就是说同样的请求参数只能使用一次,这样可以避免接口重放攻击。

具体实现方式:接口请求方每次请求都会随机生成一个不重复的nonce值,接口提供方可以使用一个存储容器(为了方便演示,我使用的是guava提供的本地缓存,生产环境中可以使用redis这样的分布式存储方式),每次先在容器中看看是否存在接口请求方发来的nonce值,如果不存在则表明是第一次请求,则放行,并且把当前nonce值保存到容器中,这样,如果下次再使用同样的nonce来请求则容器中一定存在,那么就可以判定是无效请求了。

这里可以设置缓存的失效时间为5分钟,因为前面有效期已经做了5分钟的控制。


static Cache<String, String> cache = CacheBuilder.newBuilder()
        .expireAfterWrite(5, TimeUnit.MINUTES)
        .build();

private static void serverVerify(String requestParam) throws Exception {
    APIRequestEntity apiRequestEntity = JSONObject.parseObject(requestParam, APIRequestEntity.class);
    Header header = apiRequestEntity.getHeader();
    UserEntity userEntity = JSONObject.parseObject(JSONObject.toJSONString(apiRequestEntity.getBody()), UserEntity.class);
    // 首先,拿到参数后同样进行签名
    String sign = getSHA256Str(JSONObject.toJSONString(userEntity));
    if (!sign.equals(header.getSign())) {
        throw new Exception("数据签名错误!");
    }
    // 从header中获取相关信息,其中appSecret需要自己根据传过来的appId来获取
    String appId = header.getAppId();
    String appSecret = getAppSecret(appId);
    String nonce = header.getNonce();
    String timestamp = header.getTimestamp();
    // 请求时间有效期校验
    long now = LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    if ((now - Long.parseLong(timestamp)) / 1000 / 60 >= 5) {
        throw new Exception("请求过期!");
    }
    // nonce有效性判断
    String str = cache.getIfPresent(appId + "_" + nonce);
    if (Objects.nonNull(str)) {
        throw new Exception("请求失效!");
    }
    cache.put(appId + "_" + nonce, "1");
    // 按照同样的方式生成appSign,然后使用公钥进行验签
    Map<String, String> data = Maps.newHashMap();
    data.put("appId", appId);
    data.put("nonce", nonce);
    data.put("sign", sign);
    data.put("timestamp", timestamp);
    Set<String> keySet = data.keySet();
    String[] keyArray = keySet.toArray(new String[0]);
    Arrays.sort(keyArray);
    StringBuilder sb = new StringBuilder();
    for (String k : keyArray) {
        if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名
            sb.append(k).append("=").append(data.get(k).trim()).append("&");
    }
    sb.append("appSecret=").append(appSecret);
    if (!rsaVerifySignature(sb.toString(), appKeyPair.get(appId).get("publicKey"), header.getAppSign())) {
        throw new Exception("验签错误!");
    }
    System.out.println();
    System.out.println("【提供方】验证通过!");
}

白名单机制

使用白名单机制可以进一步加强接口的安全性,一旦服务与服务交互可以使用,接口提供方可以限制只有白名单内的IP才能访问,这样接口请求方只要把其出口IP提供出来即可。

黑名单机制

与之对应的黑名单机制,则是应用在服务端与客户端的交互,由于客户端IP都是不固定的,所以无法使用白名单机制,不过我们依然可以使用黑名单拦截一些已经被识别为非法请求的IP。

限流、熔断、降级

最后限流、熔断、降级这些应该都是接口设计的标准规范,所以开放接口在设计时就更应该要考虑清楚,尤其是限流,接口提供方在对外提供时就应该与请求方约定清楚。

其他合法性校验

最后,哪些字段必填,哪些字段非必填,字段类型、长度、格式,基本业务校验也都应该确认清楚。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: T-Box是一种汽车电子产品,它包括了一种开放的开发平台,称为OpenCPU,用于实现T-Box与外部MCU的通讯协议。OpenCPU提供了一组API,文件系统和一些基础库,可用于开发基于T-Box的各种应用程序。 具体来说,T-Box的OpenCPU与MCU之间的通信协议可以采用UART(通用异步收发传输)或CAN(控制器局域网)协议。用UART协议,可以通过串行接口将数据从MCU发送到T-Box,或从T-Box发送到MCU。使用CAN协议,可以在MCU和T-Box之间建立一个专用的CAN总线,以进行高速和可靠的数据通信。 无论采用哪种协议,都需要定义特定的通信协议来控制数据的传输和接收。在通信协议中,需要定义数据格式、数据包结构、命令和响应码等。这些协议需要确保数据传输的稳定性、可靠性和安全性。因此,通信协议的设计和实现是T-Box和MCU之间通信的关键。 总之,T-Box的OpenCPU提供了一种灵活而可扩展的开发平台,可以很容易地实现T-Box与外部MCU之间的通信协议。通过良好的通信协议设计和实现,可以实现T-Box和汽车电子系统之间的高速和可靠的数据交换。 ### 回答2: T-Box是指车载终端,它是一种集车载电子设备并通过无线网络与外部通信互联的综合式设备。其中,OpenCPU是一种通用的开放式软件结构,它可以提供应用程序接口(API),便于开发人员进行软件开发工作。而MCU是单片机的缩写,是一种没有操作系统的微控制器,可以用来操作简单的小型设备。 在T-Box和MCU之间通讯协议方面,可以采用常用的串口通信方式,即通过串口将T-Box和MCU进行连接。在这种模式下,T-Box可以通过OpenCPU提供的API调用MCU设备中的底层驱动程序,从而实现与MCU的数据交互和控制操作。另外,还可以采用CAN总线、TCP/IP等通信方式进行通讯。 为确保通讯协议的正常运行,需要T-Box和MCU在数据传输和控制过程中共同遵循一些规则和协议,例如采用特定的通讯协议格式、数据帧结构、数据传输速度等。在实际应用中,还必须考虑设备的稳定性、安全性等因素,以确保通信的安全可靠性。 综上所述,T-Box和MCU之间的通讯协议需要结合具体应用特点进行优化和设计,以提高通讯效率和实现可靠的数据传输和控制操作。 ### 回答3: t-box和mcu之间通讯协议一般是使用CAN总线或者UART串口进行数据传输。opencpu则是一个基于嵌入式操作系统的软件开发平台,在t-box中充当着数据处理和应用层开发的桥梁。 在实际应用中,t-box会将获取到的车辆及其周边环境信息通过CAN总线或者UART串口发送给mcu进行处理,然后再根据处理结果进行自身行为的调整或行为数据的存储和上传。opencpu在其中的角色是对传输的数据进行拆分、封装和解析,以及实现与其他设备之间的通讯和协议处理。 通讯协议的设计则需要根据实际应用场景和要求进行定制。例如,在多车联网环境下,需要对数据内容、传输速率、数据质量、差错处理等方面进行详细规定,以保证各个t-box之间顺畅传输并可靠实现数据间互通。此外,为了提高通讯效率和稳定性,还需要对通讯协议进行优化,并针对不同通讯方式进行适当的调整。 通过这些措施,可以实现t-box与mcu之间的高效通讯和数据共享,从而更好地支持车辆智能化和自动化发展的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码拉松

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值