api接口的安全性(实现)

152 阅读1分钟

一、原理

本篇为实现,可先阅读:保证api接口安全性的方式

二、实现

定义

const (
   Newline       = "\n"
   Json          = "application/json"
   ContextType   = "Content-type"
   Nonce         = "c-sign-nonce"
   Version       = "c-sign-version"
   Timestamp     = "c-sign-timestamp"
   Authorization = "authorization"
)

type Auth struct {
   Nonce         string
   Version       string
   Timestamp     string
   Authorization string
}

验证请求及签名是否合法(服务提供方使用)

func CheckHttpRequestAuth(auth *Auth, path string, body []byte, appKey string, appSecret string) bool {
   h := md5.New()
   h.Write(body)
   b := h.Sum(nil)
   base64Md5Str := base64.StdEncoding.EncodeToString(b)

   // 1.timestamp验证 todo (防止恶意攻击)
   // 2.nonce验证 todo
   // 3.sign验证
   sign := "c" + appKey + singature(auth.Timestamp, auth.Nonce, base64Md5Str, path, appSecret)
   if sign == auth.Authorization {
      return true
   }

   return false
}

获取鉴权header(请求方使用)

func GetRequestHeader(path string, body []byte, appKey string, appSecret string) map[string]string {
   header := make(map[string]string, 0)

   h := md5.New()
   h.Write(body)
   b := h.Sum(nil)
   base64Md5Str := base64.StdEncoding.EncodeToString(b)
   now := time.Now().UTC().Unix()
   timeStr := strconv.FormatInt(now, 10)

   nonce := _uuid.Rand().Hex()

   header[ContextType] = Json
   header[Nonce] = nonce
   header[Version] = "1.0"
   header[Timestamp] = timeStr
   header[Authorization] = "c" + appKey + singature(timeStr, nonce, base64Md5Str, path, appSecret)

   return header
}

签名方法(根据业务进行调整)

func singature(timeStr string, nonce string, md5Str string, path string, appSecret string) string {
   b := bytes.Buffer{}

   b.WriteString(Json)
   b.WriteString(Newline)

   b.WriteString(nonce)
   b.WriteString(Newline)

   b.WriteString(md5Str)
   b.WriteString(Newline)

   b.WriteString(timeStr)
   b.WriteString(Newline)

   b.WriteString(path)

   mac := hmac.New(sha1.New, []byte(appSecret))
   mac.Write([]byte(b.String()))

   return base64.StdEncoding.EncodeToString(mac.Sum(nil))
}

测试

const (
   appKey = "EO8bvxGl"
   appSecret = "215bc9d7e1ab16c663289d40cea8164b9b00e307"
)


func Test_GetRequestHeader(t *testing.T) {
   path := "/api/v1/test"
   body := []byte("{"a":"a", "b":1}")
   headers := GetRequestHeader(path, body, appKey, appSecret)
   for k, item := range headers {
      // c-sign-timestamp:  1674119032
      // c-sign-nonce:  0e30eb38-d63a-4f45-bace-b98d30f52040
      // Authorization:  cEO8bvxGlogcvH5eS4ABeFQAbKf08mMgZ1GE=
      fmt.Println(k + ": ", item)
   }
}

func TestCheckHttpRequestAuth(t *testing.T) {
   auth := &Auth{
      Nonce: "0e30eb38-d63a-4f45-bace-b98d30f52040",
      Version: "1.0",
      Timestamp: "1674119032",
      Authorization: "cEO8bvxGlogcvH5eS4ABeFQAbKf08mMgZ1GE=",
   }

   path := "/api/v1/test"
   body := []byte("{"a":"a", "b":1}")
   got := CheckHttpRequestAuth(auth, path, body, appKey, appSecret)
   fmt.Println("got:", got) // true
}