18 August 2014
说一下关于接口安全的设计机制。

HMAC-SHA1(基于SHA1哈希算法的消息验证代码) 是一种键控哈希算法。 此 HMAC 进程将密钥与消息数据混合,使用哈希函数对混合结果进行哈希计算,将所得哈希值与该密钥混合,然后再次应用哈希函数。 输出的哈希值长度为 160 位。

虽然安全哈希算法(Secure Hash Algorithm,简称SHA1)是一种不可逆的加密算法,但是由于同样的内容计算之后结果是相同的,且不会重复,所以通过暴力计算,也是能够还原数据。所以HMAC-SHA1就在SHA1的基础上,增加一个密钥。如此一来,只要密钥不被泄漏,就无法破解信息内容。

在接口验证过程中,将要发送的数据参数,再加上要发送时刻的时间片和密钥,通过HMAC-SHA1一并进行计算,请求的时候将计算得到的签名作为参数发送给服务器。服务器也要根据本地保存的密钥再计算一次,与客户端提供的签名进行对比。相同则为授权成功。

通过HMAC-SHA1做加密处理,可以防止请求参数被恶意修改。如果参数被修改,签名也会随之变化,所以单纯的修改参数将会导致服务器授权验证失败。再传入的参数之中再加入时间片信息,如果和服务器时间相差过大,该请求也会被抛弃。

基于beego框架实现接口验证,使用它提供的过滤器就能实现。过滤器函数如下所示:

beego.InsertFilter(pattern string, postion int, filter FilterFunc)

三个参数:

  • 路由规则,可以根据一定的规则进行路由,如果你全匹配可以用*
  • postion 执行 Filter 的地方,四个固定参数如下,分别表示不同的执行过程
    • BeforeRouter 寻找路由之前
    • BeforeExec 找到路由之后,开始执行相应的 Controller 之前
    • AfterExec 执行完 Controller 逻辑之后执行的过滤器
    • FinishRouter 执行完逻辑之后执行的过滤器
  • filter filter 函数type FilterFunc func(*context.Context)

路由规则用来匹配过滤器。过滤的位置有4个。我们这里是要校验请求参数,那么调用得靠前一些,能够减少后面不必要的计算。所以用BeforeRouter较好。校验函数如下:

func FilterOauth(ctx *context.Context) {
	timestamp, err := strconv.ParseInt(ctx.Input.Query("timestamp"), 10, 64)
	if err != nil {
		ctx.Abort(http.StatusUnauthorized, "")
	}
	timestamp_t := time.Unix(timestamp, 0)
	now_t := time.Now()
	if now_t.Sub(timestamp_t).Minutes() > 10 {
		fmt.Println(timestamp_t, "Duration is too long")
		ctx.Abort(http.StatusUnauthorized, "")
	}

	size := ctx.Input.Query("size")
	if size == "" {
		ctx.Abort(http.StatusUnauthorized, "")
	}

	sign := ctx.Input.Query("sign")
	if sign == "" {
		ctx.Abort(http.StatusUnauthorized, "")
	}

	if CheckMAC(size+timestamp_t.String(), sign, "seckey") {
		fmt.Println("Verify error")
		ctx.Abort(http.StatusUnauthorized, "")
	}
}

校验是根据传入的参数sizetimestape进行,还需要传入sign签名用于比对。过滤器函数传入了上下文对象*context.Context。如果传入的时间片和系统时间相差超过10分钟,会被认为是过期请求。

校验函数用了Golang的crypto/hmaccrypto/sha1包:

func CheckMAC(message, sign, key string) bool {
	mac := hmac.New(sha1.New, []byte(key))

	mac.Write([]byte(message))
	return hex.EncodeToString(mac.Sum(nil)) == sign
}

加密的结果是[]byte类型,还需要转换成可读的16进制编码,通过包encoding/hex即可实现。

接口加密还可以使用HTTPS加密的传输方式,这个我还不懂,以后明白了再写。


参考文献

原文链接:接口安全机制,转载请注明来源!

EOF