mirror of
https://gitee.com/samwaf/SamWaf.git
synced 2026-09-19 09:32:29 +08:00
Merge pull request #793 from samwafgo/feat_request
feat:request protected
This commit is contained in:
@@ -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 前缀
|
||||
)
|
||||
|
||||
@@ -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(关闭)
|
||||
|
||||
@@ -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-Id(Nonce)
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user