115 lines
3.2 KiB
Go
115 lines
3.2 KiB
Go
// Package utility 安全请求,思路来源https://blog.csdn.net/David_jiahuan/article/details/106391956
|
||
// @Author 铁憨憨[cory] 2024/9/11 9:38:00
|
||
package utility
|
||
|
||
import (
|
||
"crypto/md5"
|
||
"crypto/sha256"
|
||
"encoding/hex"
|
||
"github.com/gogf/gf/v2/frame/g"
|
||
"github.com/gogf/gf/v2/net/ghttp"
|
||
"github.com/gogf/gf/v2/os/gctx"
|
||
"github.com/gogf/gf/v2/util/gconv"
|
||
"math/big"
|
||
"strconv"
|
||
"time"
|
||
)
|
||
|
||
// 签名验证中间件
|
||
func SignatureMiddleware(r *ghttp.Request) {
|
||
if r.URL.Path == "/zm/api/wxApplet/wxApplet/appPort/releaseAppVersion" {
|
||
r.Middleware.Next()
|
||
return
|
||
}
|
||
// 获取请求中的参数
|
||
signature := gconv.String(r.Header.Get("sign"))
|
||
timestamp := gconv.Int64(r.Header.Get("timestamp"))
|
||
nonce := gconv.String(r.Header.Get("nonce"))
|
||
if signature == "" || timestamp == 0 || nonce == "" {
|
||
r.Response.WriteJson(g.Map{"error": "无效验证"})
|
||
r.ExitAll()
|
||
return
|
||
}
|
||
//验证时间戳
|
||
if !validateTimestamp(timestamp) {
|
||
r.Response.WriteJson(g.Map{"error": "请求过期"})
|
||
r.ExitAll()
|
||
return
|
||
}
|
||
// 验证 nonce 防止重放攻击
|
||
if !validateNonce(nonce) {
|
||
r.Response.WriteJson(g.Map{"error": "无效请求:检测到重放"})
|
||
r.ExitAll()
|
||
return
|
||
}
|
||
serverSignature := generateServerSignature(strconv.FormatInt(timestamp, 10), nonce)
|
||
// 验证签名
|
||
if signature != serverSignature {
|
||
r.Response.WriteJson(g.Map{"error": "签名错误"})
|
||
r.ExitAll()
|
||
return
|
||
}
|
||
//签名验证通过
|
||
r.Middleware.Next()
|
||
}
|
||
|
||
func validateTimestamp(unixTimestamp int64) bool {
|
||
// 获取当前时间
|
||
now := time.Now().UnixMilli()
|
||
result := subtractBigFromInt64(now, unixTimestamp)
|
||
// 将整数 1500 转换为 *big.Int 类型
|
||
big1500 := big.NewInt(30000)
|
||
// 验证时间差是否在 1500 毫秒内
|
||
if result.Cmp(big1500) == -1 && result.Cmp(big.NewInt(0)) >= 0 {
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
|
||
func subtractBigFromInt64(currentMillis int64, unixTimestamp int64) *big.Int {
|
||
// 将两个 int64 类型的值转换为 *big.Int 类型
|
||
bigCurrent := big.NewInt(currentMillis)
|
||
bigUnixTimestamp := big.NewInt(unixTimestamp)
|
||
// 计算差值
|
||
result := big.NewInt(0).Sub(bigCurrent, bigUnixTimestamp)
|
||
// 求差值的绝对值
|
||
return result.Abs(result)
|
||
}
|
||
|
||
// 验证 nonce
|
||
func validateNonce(nonce string) bool {
|
||
nonceKey := "reset" + nonce
|
||
// 使用 Redis 来存储 nonce,防止重放
|
||
redisClient := g.Redis()
|
||
ctx := gctx.New()
|
||
exists, err := redisClient.Exists(ctx, nonceKey)
|
||
if err != nil {
|
||
return false
|
||
}
|
||
if exists > 0 {
|
||
return false // nonce 已经存在,说明是重放请求
|
||
}
|
||
// nonce 不存在,存储到 Redis 并设置60秒过期时间
|
||
err = redisClient.SetEX(ctx, nonceKey, nonce, 60)
|
||
if err != nil {
|
||
return false
|
||
} else {
|
||
return true
|
||
}
|
||
}
|
||
|
||
// 生成服务端签名
|
||
func generateServerSignature(timestamp, nonce string) string {
|
||
sum := md5.Sum([]byte("coyrOrtiehanhan1223202409111457"))
|
||
md5Sum := hex.EncodeToString(sum[:])
|
||
// 拼接时间戳、nonce 和 secretKey
|
||
signStr := md5Sum + timestamp + nonce
|
||
// 对拼接后的字符串进行 MD5 加密
|
||
md5Hash := md5.Sum([]byte(signStr))
|
||
md5Hex := hex.EncodeToString(md5Hash[:])
|
||
// 对 MD5 结果进行 SHA-256 加密
|
||
sha256Hash := sha256.Sum256([]byte(md5Hex))
|
||
sha256Hex := hex.EncodeToString(sha256Hash[:])
|
||
return sha256Hex
|
||
}
|