开放平台设计

1 开放接口

  • appid和appSecret:为每个应用接入方分配,appid是唯一确定某个应用,appSecret是long-term key,故而为了安全需要可以销毁重新生成。双向认证这里介绍了long-term key是什么。
  • 时间戳
    客户端接口请求添加时间戳
//增加时间戳参数
        params.put("timestamp", DateUtils.formatDate(new Date()));

服务器校验时间戳的有效性,有效期为1分钟。这个1分钟是接口接口到服务器接收到请求的时间,

@Value("${open.sign.timeout:60}")
    private long signTimeout;

 private boolean checkTimestamp(long timestamp, boolean verifyTimestamp) {
        if (!verifyTimestamp) {
            return true;
        }
        Long ct = System.currentTimeMillis() / 1000;
        return ct < timestamp + signTimeout;
    }
  • 随机数
    随机数的目的是防止重放攻击,随机数与时间戳一般是一起使用的,API接口防止参数篡改和重放攻击,如果使用fiddler获取到报文,然后进行写个脚本进行重放攻击,60s足够压垮服务器了,故而再增加一次性的nonce,那么重放攻击就可以有效防范了。
    接口请求的随机数,例如下面的做法是通过uuid来产生的
    params.put("nonce".randomUUID().toString().replace("-", ""));
    
    这个是接口服务端的代码,从下图可以看到如果随机数在redis中存在,则提示异常,
    /**
      * 检查随机数
      * @param nonce
      */
     private void checkNonce(String nonce) {
         if (redisService.hasKey(nonce)) {
             throw new RuntimeException("随机数验证失败");
         } else {
             redisService.putString(nonce, "", signTimeout);
         }
     }
    
  • 签名
    这里参考了支付宝的签名策略,先对接口参数进行排序,然后再签名。签名后可以规避数据篡改的问题,你并不知道公私钥是什么
private static String createLinkString(Map<String, String> params) {

       List<String> keys = new ArrayList<String>(params.keySet());
       Collections.sort(keys);

       String prestr = "";

       for (int i = 0; i < keys.size(); i++) {
           String key = keys.get(i);
           String value = params.get(key);

           if (i == keys.size() - 1) {// 拼接时,不包括最后一个&字符
               prestr = prestr + key + "=" + value;
           } else {
               prestr = prestr + key + "=" + value + "&";
           }
       }

       logger.debug("签名数据:{}", prestr);
       return prestr;
   }

客户端使用私钥签名

public static String sign(String text, String signType, String key) {
       String mySign = null;
       if (SignType.MD5.equals(signType)) {
           mySign = DigestsUtil.md5Hex(text + key);
       } else if (SignType.RSA.equals(signType)) {
           mySign = RSASignature.signSHA1(text, key);
       } else if (SignType.RSA2.equals(signType)) {
           mySign = RSASignature.signSHA256(text, key);
       } else {
           logger.error("不支持的签名方法:{}", signType);
           throw new RuntimeException("签名方法不支持");
       }
       logger.debug("签名:{}", mySign);
       return mySign;
   }

服务器端用公钥验签

public static boolean verify(Map<String, String> params, String key) {
       String sign = null;
       if (params.get("sign") != null) {
           sign = params.get("sign");
           logger.debug("request sign:{}", sign);
       } else {
           throw new RuntimeException("签名不能为空");
       }

       String signType = getSignType(params);
       // 过滤
       Map<String, String> filterParams = paraFilter(params);
       // 排序
       String linkString = createLinkString(filterParams);

       if (SignType.RSA2.equals(signType)) {
           return RSASignature.verifySHA256(linkString, sign, key);
       } else if (SignType.RSA.equals(signType)) {
           return RSASignature.verifySHA1(linkString, sign, key);
       } else if (SignType.MD5.equals(signType)) {
           String mySign = sign(linkString, signType, key);
           return sign.equals(mySign);
       } else {
           logger.error("不支持的签名方法:{}", signType);
           throw new RuntimeException("签名方法不支持");
       }
   }
  • 令牌
    2 API网关

3 安全认证
Oauth2.0,参考springsecurity oauth2.0

4 https
DV EV OV证书,在服务端nginx中配置dv证书即可

5 开放平台
5.1 企查查
企查查开放平台接口示例,企查查的开放接口做的比较简单,它为企业用户提供了appId(它的key)和appSecret(下面的SecretKey),token生成方式相对固定,有效期是根据时间戳来保证了,如果在有效时间期内进行重放,影响会影响到它的调用次数,但是对于它这种按次收费的公司,这些调用次数跟他好像没有多大关系,如果这么去看待,这个设计确实有些不负责任。当然前提是你得有SecretKey。
我们公司曾经对接过企查查,也遇到过安全问题,不知道secretkey是怎么泄露的,倒是被错误的计费。SecretKey毕竟是long-term key,时间戳和key都是参数,应该花时间还是可以破解出来的,虽然我不是这方面的专家
1
5.2 柠檬云
获取平台token,通过appId和appSecret获取access_token,显然必须使用https,否则appSecret一下子就暴露了。access_token的有效期为2小时,在快过期再次获取access_token,这里使用的oauth2.0协议,刷新token并没有使用refresh_token,做了一定裁剪。

5.3 支付宝

5.4 微信

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

warrah

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

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

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

打赏作者

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

抵扣说明:

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

余额充值