【安全】接口参数加密的两种方式

636 阅读2分钟

引言

在不同的系统之间一般是通过API接口的方式来进行交互,服务提供方需要进行身份的验证确保客户端的可靠性。

常用的加密方式

  1. 微信支付的签名算法
  2. AES对称加密算法

微信支付签名算法

微信支付文档: pay.weixin.qq.com/wiki/doc/ap…

主要的步骤是参数名排序后拼接成字符串,对参数计算md5,与入参一起传递。

优劣

优点: 计算后的MD5没法解密,安全系数高

缺点:对于存在嵌套的入参不太友好

例: 对于这个json组装后的结果为:array=bar=2,baz=3,foo=1

"array": [
		{"foo": 1},
		{"bar": 2},
		{"baz": 3}
	],

Go代码实现如下

微信签名算法找了一下没有递归版本,自己实现了一下


// ParamsMd5 参数加密
func ParamsMd5(data interface{}, secret string) (string, error) {
   h := md5.New()
   params, err := joinParams(data)
   if err != nil {
      return "", err
   }
   h.Write([]byte(params + secret))
   return hex.EncodeToString(h.Sum(nil)), nil
}

func joinParams(data interface{}) (string, error) {
   var buf bytes.Buffer
   switch v := data.(type) {
   case map[string]interface{}:
      keys := make([]string, 0, len(v))
      for k := range v {
         if k == "sign" {
            continue
         }
         keys = append(keys, k)
      }
      sort.Strings(keys)

      for _, k := range keys {
         if v[k] == nil {
            continue
         }
         if buf.Len() > 0 {
            buf.WriteByte('&')
         }
         buf.WriteString(k)
         buf.WriteByte('=')
         vv, err := interface2string(v[k])
         if err != nil {
            return "", err
         }
         buf.WriteString(vv)
      }
   }
   return buf.String(), nil
}

func interface2string(data interface{}) (string, error) {
   switch vv := data.(type) {
   case nil:
      return "", errors.New("key值为nil")
   case string:
      return vv, nil
   case float64:
      return fmt.Sprintf("%v", vv), nil
   case int:
      return strconv.FormatInt(int64(vv), 10), nil
   case bool:
      return strconv.FormatBool(vv), nil
   case map[string]interface{}:
      return joinParams(vv)
   case []interface{}:
      list := make([]string, 0, len(vv))
      for _, vvv := range vv {
         tmp, err := interface2string(vvv)
         if err != nil {
            return "", err
         }
         list = append(list, tmp)
      }
      sort.Strings(list)
      return strings.Join(list, ","), nil
   default:
      return "", errors.New(fmt.Sprintf("数据类型有误: %T", vv))
   }
}

AES对称加密

AES对称加密后不需要再传递参数,只需要传递加密后的字符串,服务端解密后可以得到对应的入参。在网易云音乐有使用aes加密,可以防一波新手爬虫玩家。

  • 这个算法安全系数高,AES对称加密是通过秘钥和偏移量一起实现的,想暴力破解难度很大。
  • 实现简单,客户端用json直接加密,服务端用密文直接解密(一般会加密后做base64处理)

对比我更加推荐使用AES对称加密来作为加密算法

网上有很多AES加密算法的实现,不展示demo了。

一般会使用CBC加密模式、用pkcs7padding填充,数据块用128位,验证加密是否正确:tool.chacuo.net/cryptaes

总结

微信加密算法对嵌套入参支持不好,更加推荐使用AES加密算法