(办公)接口签名的思考

1.什么是接口签名?

:接口开发是各系统之间对接的重要方式,其数据是通过开放的互联网传输,对数据的安全性要有一定要求。为了提高传输过程参数的防篡改性,签名sign的方式是目前比较常用的方式。

 重点:请求身份是否合法?请求参数是否被恶意篡改,请求是否唯一.

2.怎么提供一个安全性高的接口?

:

2.1. 请求身份:

    Appkey(公钥)开发者标识确定唯一,AppSecret密钥(用于接口加密,确保生成参数不被猜测)有个缺点密钥让人家知道还是完蛋了.

2.2. 接口加参数

接口加个参数timestamp时间戳,格式为yyyy-mm-dd HH:mm:ss,例如:2013-05-06 13:52:03(建议传入当前时间),防止同一时间内点击两次.

   接口加个参数Appkey(公钥).

  接口加个参数sign签名字段:签名sign具体算法为:根据传入参数名称(签名sign除外)将所有请求参数按照首字母先后顺序排序,md5(密钥+除密钥外排好序的参数串+密钥)后转换为大写字母,注意编码,统一为utf8。注意要有AppSecret密钥.

类似下面这个样子:

      http://xxxx?

method=xx

&appkey=xx

×tamp=2014-12-26 10:27:26

&format=json

&sign=生成的签名

以上两步,解决了防止防止篡改,参数正确,但是没有解决着重复请求参数伪造二次请求的隐患。也就是重放攻击。

2.3.timestamp+nonce方案

nonce指唯一的随机字符串,用来标识每个被签名的请求。通过为每个请求提供一个唯一的标识符,服务器能够防止请求被多次使用(记录所有用过的nonce以阻止它们被二次使用)。

然而,对服务器来说永久存储所有接收到的nonce的代价是非常大的。可以使用timestamp来优化nonce的存储。

假设允许客户端和服务端最多能存在6分钟的时间差,同时追踪记录在服务端的nonce集合。当有新的请求进入时,首先检查携带的timestamp是否在6分钟内,如超出时间范围,则拒绝,然后查询携带的nonce,如存在已有集合,则拒绝。否则,记录该nonce,并删除集合内时间戳大于6分钟的nonce(可以使用redisexpire,新增nonce的同时设置它的超时失效时间为6分钟)。

   另外除了公钥密钥,还可以用token身份验证。

   服务端验证账号密码,生成token,存储30分钟,token发给前端,前端每次请求带上这个token。但是仍然存在着安全隐患,token被劫持,伪造请求和篡改参数。

  解决方法:Token+(AppKey参数加密),即使Token被劫持,对方不知道AppKey和签名算法,就无法伪造请求和篡改参数。再结合上述的重发攻击解决方案,即使请求参数被劫持也无法伪造二次重复请求。

系统可以设定一些规则:

  1. 公钥密钥有自己的系统生成.
  2. 接口有效性6分钟.
  3. 接口调用频率:1毫秒以上.
  4. 数据参数安全,验证签名.
  5. 具体算法为:根据传入参数名称(签名sign除外)将所有请求参数按照首字母先后顺序排序,md5(密钥+除密钥外排好序的参数串+密钥)后转换为大写字母。

   还有就是排序参数,如果是只调用web接口不超过3,建议不要写字母排序方法,浪费时间.

下面提供md5utils:

使用: MD5Utils.MD5Encode(str,"utf8");


import java.security.MessageDigest;

public class MD5Utils {
    private static final String hexDigIts[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};

    /**
     * MD5加密
     *
     * @param origin      字符
     * @param charsetname 编码
     * @return
     */
    public static String MD5Encode(String origin, String charsetname) {
        String resultString = null;
        try {
            resultString = new String(origin);
            MessageDigest md = MessageDigest.getInstance("MD5");
            if (null == charsetname || "".equals(charsetname)) {
                resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
            } else {
                resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
            }
        } catch (Exception e) {
        }
        return resultString;
    }

    public static String byteArrayToHexString(byte b[]) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++) {
            resultSb.append(byteToHexString(b[i]));
        }
        return resultSb.toString();
    }

    public static String byteToHexString(byte b) {
        int n = b;
        if (n < 0) {
            n += 256;
        }
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigIts[d1] + hexDigIts[d2];
    }

}

另外相同的参数,相同的接口重复的调用,可以直接返回:

{

    "code": -1,

    "msg": "调用频率太过频繁"

}

 虽然有些攻击还是防不到,但是能让你装装逼,让客户看到哇,我这次选的系统接口,很专业。(确实,让我访问接口每访问一次都要加签名什么的,搞得我很难受。)

  内容借鉴:(简书作者:Joker_Coding,链接:https://www.jianshu.com/p/ad410836587a)

 

  

  

原文地址:https://www.cnblogs.com/historylyt/p/11119061.html