Files
zmkgC/third/securityRequest.go

115 lines
3.2 KiB
Go
Raw Permalink Normal View History

2025-07-07 20:11:59 +08:00
// 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
}