zoukankan      html  css  js  c++  java
  • (办公)接口签名的思考

    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)

     

      

      

  • 相关阅读:
    深入探究JVM之垃圾回收器
    深入探究JVM之对象创建及分配策略
    深入探究JVM之内存结构及字符串常量池
    【深度思考】如何优雅告知用户,网站正在升级维护?
    Redis系列(九):Redis的事务机制
    [C#.NET 拾遗补漏]07:迭代器和列举器
    [C#.NET 拾遗补漏]06:单例模式最佳实践
    深入理解 EF Core:使用查询过滤器实现数据软删除
    简化RESTful开发,Spring Data REST让你少掉发
    如何查看Docker容器环境变量,如何向容器传递环境变量
  • 原文地址:https://www.cnblogs.com/historylyt/p/11119061.html
Copyright © 2011-2022 走看看