!20 feat:attack log only mode

Merge pull request !20 from samwaf/feat_only_record
This commit is contained in:
samwaf
2025-09-10 03:29:30 +00:00
committed by Gitee
8 changed files with 46 additions and 12 deletions

View File

@@ -46,6 +46,7 @@ type WebLog struct {
BackendCheckCost int64 `json:"backend_check_cost"` // 后端处理耗时(ms)
ResHeader string `json:"res_header"` // 返回header情况
BodyHash string `json:"body_hash"` // body hash值
LogOnlyMode int `json:"log_only_mode"` //是否只记录日志 1 是 0 不是
}
// 在 GORM 的 Model 方法中定义复合索引

View File

@@ -41,6 +41,7 @@ type Hosts struct {
CacheJSON string `json:"cache_json"` //缓存配置 json
StaticSiteJSON string `json:"static_site_json"` //静态站点配置 json
DefaultEncoding string `json:"default_encoding"` //默认编码 utf-8 或者 gbk auto字符串自动选择
LogOnlyMode int `json:"log_only_mode"` //仅记录模式 1开启 0关闭
}
type HostsDefense struct {

View File

@@ -22,11 +22,11 @@ type WafAttackLogSearch struct {
UnixAddTimeBegin string `json:"unix_add_time_begin" form:"unix_add_time_begin"` //开始时间
UnixAddTimeEnd string `json:"unix_add_time_end" form:"unix_add_time_end"` //结束时间
Method string `json:"method" form:"method"` //访问方法
SortBy string `json:"sort_by" form:"sort_by"` //排序字段
SortDescending string `json:"sort_descending" form:"sort_descending"` //排序方式
FilterBy string `json:"filter_by" form:"filter_by"` //筛选字段
FilterValue string `json:"filter_value" form:"filter_value"` //筛选值
LogOnlyMode string `json:"log_only_mode" form:"log_only_mode"` //日志模式
SortBy string `json:"sort_by" form:"sort_by"` //排序字段
SortDescending string `json:"sort_descending" form:"sort_descending"` //排序方式
FilterBy string `json:"filter_by" form:"filter_by"` //筛选字段
FilterValue string `json:"filter_value" form:"filter_value"` //筛选值
request.PageInfo
}

View File

@@ -35,6 +35,7 @@ type WafHostAddReq struct {
StaticSiteJSON string `json:"static_site_json"` //静态站点配置 json
CacheJSON string `json:"cache_json"` //缓存配置 json
DefaultEncoding string `json:"default_encoding"` //默认编码 utf-8 或者 gbk auto字符串自动选择
LogOnlyMode int `json:"log_only_mode"` //是否只记录日志 1 是 0 不是
}
type WafHostDelReq struct {
@@ -78,8 +79,8 @@ type WafHostEditReq struct {
CacheJSON string `json:"cache_json"` //缓存配置 json
StaticSiteJSON string `json:"static_site_json"` //静态站点配置 json
DefaultEncoding string `json:"default_encoding"` //默认编码 utf-8 或者 gbk auto字符串自动选择
LogOnlyMode int `json:"log_only_mode"` //是否只记录日志 1 是 0 不是
}
type WafHostGuardStatusReq struct {
CODE string `json:"code"`
GUARD_STATUS int `json:"guard_status"` //防御状态 1 是开启防御 0 是防御关闭

View File

@@ -66,6 +66,7 @@ func (receiver *WafHostService) AddApi(wafHostAddReq request.WafHostAddReq) (str
CacheJSON: wafHostAddReq.CacheJSON,
StaticSiteJSON: wafHostAddReq.StaticSiteJSON,
DefaultEncoding: wafHostAddReq.DefaultEncoding,
LogOnlyMode: wafHostAddReq.LogOnlyMode,
}
global.GWAF_LOCAL_DB.Create(wafHost)
return wafHost.Code, nil
@@ -122,6 +123,7 @@ func (receiver *WafHostService) ModifyApi(wafHostEditReq request.WafHostEditReq)
"CacheJSON": wafHostEditReq.CacheJSON,
"StaticSiteJSON": wafHostEditReq.StaticSiteJSON,
"DefaultEncoding": wafHostEditReq.DefaultEncoding,
"LogOnlyMode": wafHostEditReq.LogOnlyMode,
}
err := global.GWAF_LOCAL_DB.Debug().Model(model.Hosts{}).Where("CODE=?", wafHostEditReq.CODE).Updates(hostMap).Error

View File

@@ -87,6 +87,12 @@ func (receiver *WafLogService) GetListApi(req request.WafAttackLogSearch) ([]inn
}
whereField = whereField + " method=? "
}
if len(req.LogOnlyMode) > 0 {
if len(whereField) > 0 {
whereField = whereField + " and "
}
whereField = whereField + " log_only_mode=? "
}
for _, by := range splitFilterBys {
if len(by) > 0 {
@@ -147,6 +153,9 @@ func (receiver *WafLogService) GetListApi(req request.WafAttackLogSearch) ([]inn
if len(req.Method) > 0 {
whereValues = append(whereValues, req.Method)
}
if len(req.LogOnlyMode) > 0 {
whereValues = append(whereValues, req.LogOnlyMode)
}
for _, val := range splitFilterValues {
if len(val) > 0 {
whereValues = append(whereValues, "%"+val+"%")

View File

@@ -229,6 +229,13 @@ func pathCoreSql(db *gorm.DB) {
zlog.Info("db", "init letsencrypt CA server success")
}
}
// 2025-09-10 host的log_only_mode 初始化 默认是0 不启用
err = db.Exec("UPDATE hosts SET log_only_mode=? WHERE log_only_mode IS NULL", 0).Error
if err != nil {
panic("failed to hosts :log_only_mode " + err.Error())
} else {
zlog.Info("db", "hosts :log_only_mode init successfully")
}
// 记录结束时间并计算耗时
duration := time.Since(startTime)
zlog.Info("create core default value completely", "duration", duration.String())

View File

@@ -351,9 +351,16 @@ func (waf *WafEngine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
handleBlock := func(checkFunc func(*http.Request, *innerbean.WebLog, url.Values, *wafenginmodel.HostSafe, *wafenginmodel.HostSafe) detection.Result) bool {
detectionResult := checkFunc(r, &weblogbean, formValues, hostTarget, waf.HostTarget[waf.HostCode[global.GWAF_GLOBAL_HOST_CODE]])
if detectionResult.IsBlock {
decrementMonitor(hostCode)
EchoErrorInfo(w, r, weblogbean, detectionResult.Title, detectionResult.Content, hostTarget, waf.HostTarget[waf.HostCode[global.GWAF_GLOBAL_HOST_CODE]], true)
return true
if hostTarget.Host.LogOnlyMode == 1 {
// 仅记录模式:记录攻击日志但不阻断请求
weblogbean.LogOnlyMode = 1
weblogbean.RULE = detectionResult.Title
return false
} else {
decrementMonitor(hostCode)
EchoErrorInfo(w, r, weblogbean, detectionResult.Title, detectionResult.Content, hostTarget, waf.HostTarget[waf.HostCode[global.GWAF_GLOBAL_HOST_CODE]], true)
return true
}
}
return false
}
@@ -949,7 +956,6 @@ func (waf *WafEngine) modifyResponse() func(*http.Response) error {
//处理敏感词
if waf.CheckResponseSensitive() {
//敏感词检测
matchBodyResult := waf.SensitiveManager.MultiPatternSearch([]rune(string(orgContentBytes)), false)
if len(matchBodyResult) > 0 {
sensitive := matchBodyResult[0].CustomData.(model.Sensitive)
@@ -957,9 +963,16 @@ func (waf *WafEngine) modifyResponse() func(*http.Response) error {
if sensitive.CheckDirection != "in" {
weblogfrist.RISK_LEVEL = 1
if sensitive.Action == "deny" {
EchoResponseErrorInfo(resp, *weblogfrist, "敏感词检测:"+string(matchBodyResult[0].Word), "敏感词内容", waf.HostTarget[host], waf.HostTarget[waf.HostCode[global.GWAF_GLOBAL_HOST_CODE]], true)
return nil
if waf.HostTarget[host].Host.LogOnlyMode == 1 {
// 仅记录模式:记录攻击日志但不阻断请求
weblogfrist.LogOnlyMode = 1
weblogfrist.GUEST_IDENTIFICATION = "触发敏感词"
weblogfrist.RULE = "敏感词检测:" + string(matchBodyResult[0].Word)
} else {
EchoResponseErrorInfo(resp, *weblogfrist, "敏感词检测:"+string(matchBodyResult[0].Word), "敏感词内容", waf.HostTarget[host], waf.HostTarget[waf.HostCode[global.GWAF_GLOBAL_HOST_CODE]], true)
return nil
}
} else {
words := processSensitiveWords(matchBodyResult, "in")
weblogfrist.GUEST_IDENTIFICATION = "触发敏感词"