Merge pull request #793 from samwafgo/feat_request

feat:request protected
This commit is contained in:
samwafgo
2026-05-07 08:44:56 +08:00
committed by GitHub
4 changed files with 80 additions and 4 deletions
+1
View File
@@ -13,4 +13,5 @@ const (
CACHE_WEBFILE = "CACHE_WEBFILE"
CACHE_FILE_INFO = "CACHE_FILE_INFO" //文件信息
CACHE_IP_FAILURE_PRE = "CACHE_IP_FAILURE_PRE" //IP失败记录前缀
CACHE_REPLAY_NONCE = "CACHE_REPLAY_NONCE_" // 防重放 nonce 前缀
)
+1
View File
@@ -26,6 +26,7 @@ var (
// 指纹认证相关配置
GCONFIG_ENABLE_DEVICE_FINGERPRINT int64 = 1 // 是否启用设备指纹认证 1启用 0禁用
GCONFIG_ENABLE_STRICT_IP_BINDING int64 = 1 // 是否启用严格IP绑定 1启用 0禁用
GCONFIG_ENABLE_REPLAY_PROTECT int64 = 1 // 防重放攻击开关 1启用 0禁用
GCONFIG_RECORD_ENABLE_OWASP int64 = 0 //启动OWASP数据检测
GCONFIG_OWASP_MODE string = "DetectionOnly" //OWASP 检测引擎工作模式: On(拦截) / DetectionOnly(观察/仅记录) / Off(关闭)
+74
View File
@@ -0,0 +1,74 @@
package middleware
import (
"SamWaf/enums"
"SamWaf/global"
"SamWaf/model/common/response"
"strconv"
"time"
"github.com/gin-gonic/gin"
)
const (
replayTimeHeader = "X-Request-Time"
replayNonceHeader = "X-Request-Id"
replayTimeWindow = 5 * time.Minute
replayNonceTTL = 10 * time.Minute
)
func ReplayProtect() gin.HandlerFunc {
return func(c *gin.Context) {
if global.GCONFIG_ENABLE_REPLAY_PROTECT == 0 {
c.Next()
return
}
// 开放平台 API Key 请求跳过(Auth 中间件已在前面设置此标记)
if v, exists := c.Get("is_openapi"); exists && v == true {
c.Next()
return
}
// WebSocket 升级跳过(Token 鉴权已足够)
if c.GetHeader("Upgrade") == "websocket" {
c.Next()
return
}
// 校验 X-Request-Time
tsStr := c.GetHeader(replayTimeHeader)
if tsStr == "" {
response.FailWithMessage("请求缺少时间标头", c)
c.Abort()
return
}
ts, err := strconv.ParseInt(tsStr, 10, 64)
if err != nil {
response.FailWithMessage("请求时间格式错误", c)
c.Abort()
return
}
diff := time.Now().Sub(time.Unix(ts, 0))
if diff < -replayTimeWindow || diff > replayTimeWindow {
response.FailWithMessage("请求已过期,请重试", c)
c.Abort()
return
}
// 校验 X-Request-IdNonce
nonce := c.GetHeader(replayNonceHeader)
if nonce == "" || len(nonce) < 16 || len(nonce) > 128 {
response.FailWithMessage("请求标识无效", c)
c.Abort()
return
}
cacheKey := enums.CACHE_REPLAY_NONCE + nonce
if global.GCACHE_WAFCACHE.IsKeyExist(cacheKey) {
response.FailWithMessage("重复请求,已拒绝", c)
c.Abort()
return
}
global.GCACHE_WAFCACHE.SetWithTTl(cacheKey, true, replayNonceTTL)
c.Next()
}
}
+4 -4
View File
@@ -93,12 +93,12 @@ func (h *securityPathHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
func (web *WafWebManager) initRouter(r *gin.Engine) {
PublicRouterGroup := r.Group("")
PublicRouterGroup.Use(middleware.SecApi(), middleware.IPWhitelist())
PublicRouterGroup.Use(middleware.SecApi(), middleware.IPWhitelist(), middleware.ReplayProtect())
router.PublicApiGroupApp.InitLoginRouter(PublicRouterGroup)
router.PublicApiGroupApp.InitCenterRouter(PublicRouterGroup) //注册中心接收接口
RouterGroup := r.Group("")
RouterGroup.Use(middleware.Auth(), middleware.OpenApiLogMiddleware(), middleware.CenterApi(), middleware.SecApi(), middleware.GinGlobalExceptionMiddleWare(), middleware.IPWhitelist()) //TODO 中心管控 特定
RouterGroup.Use(middleware.Auth(), middleware.ReplayProtect(), middleware.OpenApiLogMiddleware(), middleware.CenterApi(), middleware.SecApi(), middleware.GinGlobalExceptionMiddleWare(), middleware.IPWhitelist()) //TODO 中心管控 特定
{
router.ApiGroupApp.InitHostRouter(RouterGroup)
router.ApiGroupApp.InitLogRouter(RouterGroup)
@@ -153,7 +153,7 @@ func (web *WafWebManager) initRouter(r *gin.Engine) {
// 仅允许后台 Token 登录访问,拒绝 API Key 访问(安全敏感接口)
TokenOnlyRouterGroup := r.Group("")
TokenOnlyRouterGroup.Use(middleware.TokenOnlyAuth(), middleware.CenterApi(), middleware.SecApi(), middleware.GinGlobalExceptionMiddleWare(), middleware.IPWhitelist())
TokenOnlyRouterGroup.Use(middleware.TokenOnlyAuth(), middleware.ReplayProtect(), middleware.CenterApi(), middleware.SecApi(), middleware.GinGlobalExceptionMiddleWare(), middleware.IPWhitelist())
{
// 开放平台管理接口
router.ApiGroupApp.InitOPlatformKeyRouter(TokenOnlyRouterGroup)
@@ -208,7 +208,7 @@ func (web *WafWebManager) cors() gin.HandlerFunc {
// 将该域添加到allow-origin中
c.Header("Access-Control-Allow-Origin", origin) //
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization,X-Token,Remote-Waf-User-Id,OPEN-X-Token,X-Login-Type,X-Mobile-Token,X-API-Key")
c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization,X-Token,Remote-Waf-User-Id,OPEN-X-Token,X-Login-Type,X-Mobile-Token,X-API-Key,X-Request-Time,X-Request-Id")
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
//允许客户端传递校验信息比如 cookie
c.Header("Access-Control-Allow-Credentials", "true")