Files
SamWaf/model/hosts.go
T
xingxing bec1bacacd 特性:添加IsEnableResponseBuffering字段及相关迁移 (#953)
* 特性:添加IsEnableResponseBuffering字段及相关迁移

引入了IsEnableResponseBuffering来管理响应缓冲行为。
- 添加了从disable_response_buffering到is_enable_response_buffering的迁移转换。
- 更新了WafHostAddReq和WafHostEditReq,以包含新字段。
- 在WafEngine中实现了基于新配置处理响应缓冲的逻辑。

* 特性:更新主机表迁移,以添加is_enable_response_buffering字段

- 将已弃用的disable_response_buffering字段替换为is_enable_response_buffering。
- 更新了迁移逻辑,以确保对新字段的正确处理和为其设置默认值。
- 删除了与旧字段相关的遗留迁移步骤。
2026-08-18 08:35:34 +08:00

579 lines
29 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package model
import (
"SamWaf/model/baseorm"
"encoding/json"
)
type Hosts struct {
baseorm.BaseOrm
Code string `gorm:"size:64" json:"code"` //唯一码
Host string `gorm:"size:255" json:"host"` //域名
Port int `json:"port"` //端口
Ssl int `json:"ssl"` //是否是ssl
GUARD_STATUS int `json:"guard_status"` //防御状态 1 是开启防御 0 是防御关闭
REMOTE_SYSTEM string `gorm:"size:50" json:"remote_system"` //是宝塔 phpstudy等
REMOTE_APP string `gorm:"size:100" json:"remote_app"` //是什么类型的应用
Remote_host string `gorm:"size:255" json:"remote_host"` //远端域名
Remote_port int `json:"remote_port"` //远端端口
Remote_ip string `gorm:"size:64" json:"remote_ip"` //远端指定IP
Certfile string `gorm:"type:text" json:"certfile"` //证书文件
Keyfile string `gorm:"type:text" json:"keyfile"` //密钥文件
Nickname string `gorm:"size:200" json:"nickname"` //网站昵称
REMARKS string `gorm:"size:500" json:"remarks"` //备注
GLOBAL_HOST int `json:"global_host"` //默认全局 1 全局 0非全局
DEFENSE_JSON string `gorm:"type:text" json:"defense_json"` //自身防御 json
START_STATUS int `json:"start_status"` //启动状态 如果是0 启动 ; 如果是1 不启动
EXCLUDE_URL_LOG string `gorm:"type:text" json:"exclude_url_log"` //排除的url开头的数据 换行隔开
IsEnableLoadBalance int `json:"is_enable_load_balance"` //是否激活负载 1 激活 非1 没有激活
LoadBalanceStage int `json:"load_balance_stage"` //负载策略
UnrestrictedPort int `json:"unrestricted_port"` //不限来源匹配端口 0 限制 1,不限制
BindSslId string `gorm:"size:64" json:"bind_ssl_id"` //绑定SSL的ID
AutoJumpHTTPS int `json:"auto_jump_https"` //是否自动跳转https 0 不自动 1 强制80跳转https
BindMoreHost string `gorm:"type:text" json:"bind_more_host"` //绑定多域名
IsTransBackDomain int `json:"is_trans_back_domain"` //是否传递后端域名到后端服务器侧
BindMorePort string `gorm:"size:255" json:"bind_more_port"` //是否绑定多个端口
IsEnableHttpAuthBase int `json:"is_enable_http_auth_base"` //是否 HTTPAuthBase 1 激活 非1 没有激活
HttpAuthBaseType string `gorm:"size:50" json:"http_auth_base_type"` //认证类型 authorization(默认Basic Auth) custom(自定义页面)
HttpAuthPathPrefix string `gorm:"size:255" json:"http_auth_path_prefix"` //HTTP认证路径前缀,用于隐藏系统特征,默认为随机生成
ResponseTimeOut int `json:"response_time_out"` //响应超时时间 默认60秒,为0则无限等待
HealthyJSON string `gorm:"type:text" json:"healthy_json"` //后端健康度检测 json
InsecureSkipVerify int `json:"insecure_skip_verify"` //是否开启后端https证书有效性验证 默认 0 是校验 1 是不校验
CaptchaJSON string `gorm:"type:text" json:"captcha_json"` //验证码配置 json
AntiLeechJSON string `gorm:"type:text" json:"anti_leech_json"` //防盗链配置 json
CacheJSON string `gorm:"type:text" json:"cache_json"` //缓存配置 json
StaticSiteJSON string `gorm:"type:text" json:"static_site_json"` //静态站点配置 json
TransportJSON string `gorm:"type:text" json:"transport_json"` //传输配置 json
DefaultEncoding string `gorm:"size:20" json:"default_encoding"` //默认编码 utf-8 或者 gbk auto字符串自动选择
LogOnlyMode int `json:"log_only_mode"` //仅记录模式 1开启 0关闭
CustomHeadersJSON string `gorm:"type:text" json:"custom_headers_json"` //自定义头信息配置 json
CustomResponseHeadersJSON string `gorm:"type:text" json:"custom_response_headers_json"` //自定义响应头信息配置 json
ResponseCompressJSON string `gorm:"type:text" json:"response_compress_json"` //响应压缩配置 json(Gzip/Brotli/Zstd)
CookieSecurityJSON string `gorm:"type:text" json:"cookie_security_json"` //Cookie安全保护配置 json(HttpOnly/Secure/SameSite)
CsrfJSON string `gorm:"type:text" json:"csrf_json"` //CSRF防护配置 json(Origin/Referer 强校验)
TamperJSON string `gorm:"type:text" json:"tamper_json"` //网页防篡改配置 json(响应基线比对)
UploadSecurityJSON string `gorm:"type:text" json:"upload_security_json"` //文件上传内容检测配置 json(扩展名/Webshell/类型/大小)
IPMode string `gorm:"size:20" json:"ip_mode"` //IP提取模式: "nic" 网卡模式 或 "proxy" 代理模式
DisableHTTP2 int `json:"disable_http2"` //对外HTTP/2开关 0启用(默认/现状) 1关闭(该站点ALPN只提供http/1.1,兼容安卓等原生WebSocket客户端)
IsEnableResponseBuffering int `json:"is_enable_response_buffering"` //响应缓冲 1开启(默认) 0关闭(类似 nginx proxy_buffering off,边收边推,利于流式/SSE/大文件)
// 真实客户端 IP 提取加固(向后兼容:IPSourceMode 为空时行为与旧版完全一致——取 X-Forwarded-For 最左第一个)
IPSourceMode string `gorm:"size:20" json:"ip_source_mode"` //真实IP来源模式: ""(兼容,取最左) | nic | header | xff_depth | cdn_preset
IPTrustDepth int `json:"ip_trust_depth"` //xff_depth 模式:从右往左取第 N 个非可信 hop(默认1)
IPRealHeader string `gorm:"size:64" json:"ip_real_header"` //header/cdn_preset 模式指定的真实IP头,如 CF-Connecting-IP
IPTrustProxies string `gorm:"type:text" json:"ip_trust_proxies"` //可信代理网段(CIDR/IP,逗号分隔),用于 xff_depth 跳过可信 hop
CDNProvider string `gorm:"size:32" json:"cdn_provider"` //cdn_preset 模式选择的 CDN 厂商: cloudflare|fastly|cloudfront|edgeone|aliyun|akamai
AccessJSON string `gorm:"type:text" json:"access_json"` //统一访问认证(Access模式)站点级配置 json(三态开关/路径白名单)
}
type HostsDefense struct {
DEFENSE_BOT int `json:"bot"` //防御-虚假BOT
DEFENSE_SQLI int `json:"sqli"` //防御-Sql注入
DEFENSE_XSS int `json:"xss"` //防御-xss攻击
DEFENSE_SCAN int `json:"scan"` //防御-scan工具扫描
DEFENSE_RCE int `json:"rce"` //防御-scan工具扫描
DEFENSE_SENSITIVE int `json:"sensitive"` //敏感词检测
DEFENSE_DIR_TRAVERSAL int `json:"traversal"` //目录穿越检测
DEFENSE_OWASP_SET int `json:"owaspset"` //OWASP集检测
DEFENSE_AI int `json:"ai"` //AI智能检测(默认关闭,需先上传模型包并开启全局AI开关)
}
// HealthyConfig 健康度检测
type HealthyConfig struct {
IsEnableHealthy int `json:"is_enable_healthy"` // 是否开启健康检查
FailCount int `json:"fail_count"` // 连续失败次数
SuccessCount int `json:"success_count"` // 连续成功次数
ResponseTime int `json:"response_time"` // 响应时间(秒)
CheckMethod string `json:"check_method"` // 检查方法 GET/HEAD
CheckPath string `json:"check_path"` // 检查路径
ExpectedCodes string `json:"expected_codes"` // 预期状态码
LastErrorReason string `json:"last_error_reason"` // 最后一次错误原因
}
// CaptchaConfig 验证码配置
type CaptchaConfig struct {
IsEnableCaptcha int `json:"is_enable_captcha"` // 是否开启验证码 1开启 0关闭
ExcludeURLs string `json:"exclude_urls"` // 排除验证码的URL列表
ExpireTime int `json:"expire_time"` // 验证通过后的有效期(小时)
IPMode string `json:"ip_mode"` // IP提取模式: "nic" 网卡模式 或 "proxy" 代理模式
EngineType string `json:"engine_type"` // 验证码引擎类型: 传统方式 "traditional",capJS工作量证明 "capJs"
PathPrefix string `json:"path_prefix"` // 验证码路径前缀,用于隐藏系统特征,默认为随机生成
CapJsConfig struct {
ChallengeCount int `json:"challengeCount,omitempty"` // Number of challenges to generate (default: 50)
ChallengeSize int `json:"challengeSize,omitempty"` // Size of each challenge in bytes (default: 32)
ChallengeDifficulty int `json:"challengeDifficulty,omitempty"` // Difficulty level (default: 4)
ExpiresMs int `json:"expiresMs,omitempty"` // Expiration time in milliseconds (default: 600000)
InfoTitle struct {
En string `json:"en,omitempty"` // English title
Zh string `json:"zh,omitempty"` // Chinese title
} `json:"infoTitle,omitempty"` // Multi-language info title
InfoText struct {
En string `json:"en,omitempty"` // English text
Zh string `json:"zh,omitempty"` // Chinese text
} `json:"infoText,omitempty"` // Multi-language info text
} `json:"cap_js_config"`
}
// ParseCaptchaConfig 解析验证码配置
func ParseCaptchaConfig(captchaJSON string) CaptchaConfig {
var config CaptchaConfig
// 设置默认值
config.IsEnableCaptcha = 0
config.ExcludeURLs = ""
config.ExpireTime = 24
config.IPMode = "nic" // 默认使用网卡模式
config.EngineType = "traditional" // 默认使用传统方式
// 初始化CapJsConfig默认值
config.CapJsConfig.ChallengeCount = 50 // 默认生成50个挑战
config.CapJsConfig.ChallengeSize = 32 // 默认每个挑战32字节
config.CapJsConfig.ChallengeDifficulty = 4 // 默认难度级别4
config.CapJsConfig.ExpiresMs = 600000 // 默认过期时间600秒(10分钟)
// 初始化InfoTitle默认值
config.CapJsConfig.InfoTitle.Zh = "安全验证"
config.CapJsConfig.InfoTitle.En = "Security Verification"
// 初始化InfoText默认值
config.CapJsConfig.InfoText.Zh = "为了确保您的访问安全,请完成以下验证"
config.CapJsConfig.InfoText.En = "To ensure the security of your access, please complete the following verification"
// 如果JSON不为空,则解析覆盖默认值
if captchaJSON != "" {
err := json.Unmarshal([]byte(captchaJSON), &config)
if err != nil {
// 解析失败时使用默认值,可以记录日志
return config
}
}
return config
}
// AntiLeechConfig 防盗链配置
type AntiLeechConfig struct {
IsEnableAntiLeech int `json:"is_enable_anti_leech"` // 是否开启防盗链 1开启 0关闭
FileTypes string `json:"file_types"` // 需要防盗链的文件类型,例如: gif|jpg|jpeg|png|bmp|swf
ValidReferers string `json:"valid_referers"` // 允许的引用来源列表,使用分号(;)分隔
Action string `json:"action"` // 对于非法引用的处理方式: redirect(重定向) 或 block(直接阻止)
RedirectURL string `json:"redirect_url"` // 重定向URL,当Action为redirect时使用
}
// CacheConfig 缓存配置
type CacheConfig struct {
IsEnableCache int `json:"is_enable_cache"` // 是否开启缓存 1开启 0关闭
CacheLocation string `json:"cache_location"` // 缓存位置: "memory"内存 或 "file"文件 或 "all"内存和文件
CacheDir string `json:"cache_dir"` // 缓存目录,当location为file时使用
MaxFileSizeMB float64 `json:"max_file_size_mb"` // 最大缓存文件大小(MB) 0 是不限制
MaxMemorySizeMB float64 `json:"max_memory_size_mb"` // 最大内存缓存大小(MB),当location为memory时使用 0 是不限制
}
// StaticSecurityHeader 静态站点安全响应头项
type StaticSecurityHeader struct {
HeaderName string `json:"header_name"` // 响应头名称
HeaderValue string `json:"header_value"` // 响应头值,留空则使用系统默认值
}
// StaticSiteConfig 静态站点配置
type StaticSiteConfig struct {
IsEnableStaticSite int `json:"is_enable_static_site"` // 是否开启静态站点 1开启 0关闭
StaticSitePath string `json:"static_site_path"` // 静态站点路径
StaticSitePrefix string `json:"static_site_prefix"` // 静态站点URL前缀,默认为"/"
SensitivePaths string `json:"sensitive_paths"` // 敏感路径列表,逗号分隔
SensitiveExtensions string `json:"sensitive_extensions"` // 敏感文件扩展名,逗号分隔
AllowedExtensions string `json:"allowed_extensions"` // 允许的文件扩展名白名单,逗号分隔
SensitivePatterns string `json:"sensitive_patterns"` // 敏感文件名模式(正则表达式),逗号分隔
// 安全响应头列表,数组为空则全部使用系统默认值;
// 某项 header_value 为空则该项也使用系统默认值
SecurityHeaders []StaticSecurityHeader `json:"security_headers"`
SpaFallback int `json:"-"` // 运行时标志:由路径规则注入,不写入 host JSON
}
// ResponseCompressConfig 反代响应压缩(类似 nginx gzip / brotli / zstd)
type ResponseCompressConfig struct {
IsEnable int `json:"is_enable"` // 1 开启 0 关闭
Prefer string `json:"prefer"` // br_first | gzip_only | br_only | zstd_only
MinLength int `json:"min_length"` // 最小压缩字节数,0 表示用默认
IncludeTypes string `json:"include_types"` // 分号分隔 MIME 前缀或完整类型,空则用内置默认
IncludeExtensions string `json:"include_extensions"` // 分号分隔,如 .js;.css,与类型取并集
ExcludeExtensions string `json:"exclude_extensions"` // 分号或换行分隔后缀
ExcludePaths string `json:"exclude_paths"` // 换行或分号,URL 前缀匹配
CompressWhenStaticAssist int `json:"compress_when_static_assist"` // 1 时对静态协助响应也读体压缩
}
// CookieSecurityConfig Cookie 安全保护(应答方向给后端下发的 Set-Cookie 补齐安全属性)
// 设计原则:缺失才补——仅在对应属性缺失时追加,绝不覆盖应用已设的值,保留原 cookie 全部内容。
type CookieSecurityConfig struct {
IsEnable int `json:"is_enable"` // 1 开启 0 关闭(默认0,老站点不受影响)
HttpOnly int `json:"http_only"` // 1 缺失时补 HttpOnly / 0 不动(默认1)
Secure int `json:"secure"` // 0 不动 / 1 强制补 / 2 仅 HTTPS 自动补(默认2)
SameSite string `json:"same_site"` // "" 不动 / Lax / Strict / None(默认Lax)
ExcludeCookies string `json:"exclude_cookies"` // 排除的 cookie 名,逗号分隔(如三方/SSO cookie 原样放过)
}
// ParseCookieSecurityConfig 解析 Cookie 安全保护配置;空 JSON 给安全默认值(但默认关闭)
func ParseCookieSecurityConfig(jsonStr string) CookieSecurityConfig {
c := CookieSecurityConfig{
IsEnable: 0,
HttpOnly: 1,
Secure: 2,
SameSite: "Lax",
}
if jsonStr == "" {
return c
}
if err := json.Unmarshal([]byte(jsonStr), &c); err != nil {
return CookieSecurityConfig{IsEnable: 0, HttpOnly: 1, Secure: 2, SameSite: "Lax"}
}
return c
}
// CsrfConfig CSRF 跨站请求伪造防护配置(Origin/Referer 强校验)
type CsrfConfig struct {
IsEnable int `json:"is_enable"` // 1 开启 0 关闭(默认0,老站点不受影响)
ProtectMethods string `json:"protect_methods"` // 需保护的方法,逗号分隔(默认 "POST,PUT,DELETE,PATCH";GET/HEAD/OPTIONS 等安全方法不校验)
AllowedOrigins string `json:"allowed_origins"` // 额外允许的来源(host 或 scheme://host),换行分隔;本站域名 + BindMoreHost 自动允许
AllowEmptyRef int `json:"allow_empty_ref"` // 无 Origin 且无 Referer 时:1 放行(默认) / 0 拦截
ExcludePaths string `json:"exclude_paths"` // 排除的路径前缀,换行分隔(webhook/回调/Token鉴权API)
}
// ParseCsrfConfig 解析 CSRF 防护配置;空 JSON 给安全默认值(但默认关闭)
func ParseCsrfConfig(jsonStr string) CsrfConfig {
c := CsrfConfig{
IsEnable: 0,
ProtectMethods: "POST,PUT,DELETE,PATCH",
AllowEmptyRef: 1,
}
if jsonStr == "" {
return c
}
if err := json.Unmarshal([]byte(jsonStr), &c); err != nil {
return CsrfConfig{IsEnable: 0, ProtectMethods: "POST,PUT,DELETE,PATCH", AllowEmptyRef: 1}
}
if c.ProtectMethods == "" {
c.ProtectMethods = "POST,PUT,DELETE,PATCH"
}
return c
}
// TamperConfig 网页防篡改配置(反代响应基线比对)
type TamperConfig struct {
IsEnable int `json:"is_enable"` // 1 开启 0 关闭(默认0,老站点不受影响)
Action string `json:"action"` // "replace"(比对+命中回吐正确副本+告警,默认) / "alert"(仅告警,仍放行后端页,监控档)
MaxSizeKB int `json:"max_size_kb"` // 基线最大字节(KB),默认1024(1MB),超限不学习/不保护
}
// ParseTamperConfig 解析网页防篡改配置;空 JSON 给安全默认值(但默认关闭)
func ParseTamperConfig(jsonStr string) TamperConfig {
c := TamperConfig{
IsEnable: 0,
Action: "replace",
MaxSizeKB: 1024,
}
if jsonStr == "" {
return c
}
if err := json.Unmarshal([]byte(jsonStr), &c); err != nil {
return TamperConfig{IsEnable: 0, Action: "replace", MaxSizeKB: 1024}
}
if c.Action == "" {
c.Action = "replace"
}
if c.MaxSizeKB <= 0 {
c.MaxSizeKB = 1024
}
return c
}
// UploadSecurityConfig 文件上传内容检测配置(multipart 上传的扩展名/Webshell/类型/大小四维检测)
type UploadSecurityConfig struct {
IsEnable int `json:"is_enable"` // 1 开启 0 关闭(默认0,老站点不受影响)
CheckExt int `json:"check_ext"` // 1 启用扩展名黑名单检测
ExtBlacklist string `json:"ext_blacklist"` // 危险扩展名黑名单,逗号分隔;空用默认
CheckContent int `json:"check_content"` // 1 启用 Webshell 内容特征检测
CheckMagic int `json:"check_magic"` // 1 启用“声明类型与真实内容不符”检测
CheckSize int `json:"check_size"` // 1 启用单文件大小上限检测
MaxSizeKB int `json:"max_size_kb"` // 单文件大小上限KB=检测缓冲上限,默认10240(10MB)
OverLimitAction string `json:"over_limit_action"` // 请求体超过检测上限时:block(默认,fail-closed防绕过)/pass(放行不检测)
IncludePaths string `json:"include_paths"` // 只检测这些路径前缀,换行分隔;空=所有路径
ExcludePaths string `json:"exclude_paths"` // 跳过这些路径前缀,换行分隔;优先于 include
}
// DefaultUploadExtBlacklist 默认危险扩展名黑名单
const DefaultUploadExtBlacklist = "php,php2,php3,php4,php5,php7,pht,phtml,phar,jsp,jspx,jspa,jsw,jsv,jspf,asp,aspx,asa,asax,ascx,ashx,asmx,cer,cdx,exe,dll,sh,bat,cmd,com,cgi,pl,py,jar,war"
// ParseUploadSecurityConfig 解析文件上传检测配置;空 JSON 给默认值(默认关闭、超限拦、10MB)
func ParseUploadSecurityConfig(jsonStr string) UploadSecurityConfig {
c := UploadSecurityConfig{
IsEnable: 0,
OverLimitAction: "block",
MaxSizeKB: 10240,
}
if jsonStr == "" {
return c
}
if err := json.Unmarshal([]byte(jsonStr), &c); err != nil {
return UploadSecurityConfig{IsEnable: 0, OverLimitAction: "block", MaxSizeKB: 10240}
}
if c.OverLimitAction == "" {
c.OverLimitAction = "block"
}
if c.MaxSizeKB <= 0 {
c.MaxSizeKB = 10240
}
return c
}
// 站点级 Access 三态。判定实现只有一处,在 wafenginecore/accessgate.IsAccessEnabled。
const (
AccessModeInherit = 0 // 继承全局总开关(默认)
AccessModeForceOn = 1 // 强制开启:全局关也要认证(单站点试点、只保护后台)
AccessModeForceOff = 2 // 强制关闭:全局开也放行(对外公开的站点)
)
// HostAccessConfig 是统一访问认证的站点级配置。
//
// 全局配置在 model.AccessConfig(单行表),这里只放「这个站点要不要参与、有哪些例外」。
// 三态的存在是为了让全局开关真正可用:没有 ForceOff,用户就不敢开全局;
// 没有 ForceOn,用户想只保护一个后台站点就得先开全局再逐个关掉其余站点。
type HostAccessConfig struct {
Mode int `json:"mode"` //0继承全局(默认) 1强制开启 2强制关闭
ExcludePaths string `json:"exclude_paths"` //本站免认证路径前缀,换行分隔
RequireOtp int `json:"require_otp"` //0继承全局 1本站强制 2本站豁免
UnauthAction string `json:"unauth_action"` //""继承全局 auto|redirect|401
AllowIPGroupCode string `json:"allow_ip_group_code"` //本站额外的免认证 IP 组
}
// ParseAccessConfig 解析站点级 Access 配置。
//
// 空字符串与解析失败都返回 Mode=0(继承全局)。这一点是升级兼容的关键:
// 存量站点的 access_json 列是 NULL/"",必须落在「继承」而不是「强制开」,
// 否则用户升级到新版本的瞬间全站要求登录。
func ParseAccessConfig(jsonStr string) HostAccessConfig {
c := HostAccessConfig{Mode: AccessModeInherit}
if jsonStr == "" {
return c
}
if err := json.Unmarshal([]byte(jsonStr), &c); err != nil {
return HostAccessConfig{Mode: AccessModeInherit}
}
if c.Mode < AccessModeInherit || c.Mode > AccessModeForceOff {
c.Mode = AccessModeInherit
}
switch c.UnauthAction {
case "", AccessUnauthAuto, AccessUnauthRedirect, AccessUnauth401:
default:
c.UnauthAction = ""
}
return c
}
// TransportConfig 传输配置
type TransportConfig struct {
MaxIdleConns int `json:"max_idle_conns"` // 最大空闲连接数
MaxIdleConnsPerHost int `json:"max_idle_conns_per_host"` // 每个主机的最大空闲连接数
MaxConnsPerHost int `json:"max_conns_per_host"` // 每个主机的最大连接数
IdleConnTimeout int `json:"idle_conn_timeout"` // 空闲连接超时时间(秒)
TLSHandshakeTimeout int `json:"tls_handshake_timeout"` // TLS握手超时时间(秒)
ExpectContinueTimeout int `json:"expect_continue_timeout"` // Expect Continue超时时间(秒)
}
// CustomHeaderItem 自定义头信息项
type CustomHeaderItem struct {
HeaderName string `json:"header_name"` // 头信息名称
HeaderValue string `json:"header_value"` // 头信息值,支持内置变量
}
// CustomHeadersConfig 自定义头信息配置(用于请求头)
type CustomHeadersConfig struct {
IsEnableCustomHeaders int `json:"is_enable_custom_headers"` // 是否开启自定义头信息 1开启 0关闭
Headers []CustomHeaderItem `json:"headers"` // 自定义头信息列表
}
// CustomResponseHeaderRule 自定义响应头规则(类似 nginx location 块)
// MatchType 支持: global(全局) / prefix(路径前缀) / suffix(文件后缀) / exact(精确路径) / regex(正则)
// MergeMode 支持: merge(与全局规则合并,同名以本规则为准) / override(仅使用本规则,忽略全局)
type CustomResponseHeaderRule struct {
RuleName string `json:"rule_name"` // 规则名称,方便识别
MatchType string `json:"match_type"` // global / prefix / suffix / exact / regex
MatchValue string `json:"match_value"` // 匹配值;suffix 用分号分隔,如 ".mp4;.mp3;.webm"
Headers []CustomHeaderItem `json:"headers"` // 该规则的响应头列表
MergeMode string `json:"merge_mode"` // merge(默认) / override
}
// CustomResponseHeadersConfig 自定义响应头配置(V2 支持多规则路径匹配)
type CustomResponseHeadersConfig struct {
IsEnableCustomHeaders int `json:"is_enable_custom_headers"` // 是否开启 1开启 0关闭
Rules []CustomResponseHeaderRule `json:"rules"` // 规则列表(V2)
Headers []CustomHeaderItem `json:"headers,omitempty"` // 兼容旧版扁平列表
}
// defaultResponseCompressMimeTypes 与 nginx gzip_types 常见默认类似
var defaultResponseCompressMimeTypes = []string{
"text/html",
"text/plain",
"text/css",
"text/javascript",
"text/xml",
"application/json",
"application/javascript",
"application/x-javascript",
"application/xml",
"application/rss+xml",
"application/atom+xml",
"image/svg+xml",
}
// ParseResponseCompressConfig 解析响应压缩配置
func ParseResponseCompressConfig(jsonStr string) ResponseCompressConfig {
var c ResponseCompressConfig
c.IsEnable = 0
c.Prefer = "zstd_first"
c.MinLength = 256
c.CompressWhenStaticAssist = 0
if jsonStr == "" {
return c
}
if err := json.Unmarshal([]byte(jsonStr), &c); err != nil {
return ResponseCompressConfig{
IsEnable: 0, Prefer: "zstd_first", MinLength: 256, CompressWhenStaticAssist: 0,
}
}
if c.Prefer == "" {
c.Prefer = "zstd_first"
}
if c.MinLength <= 0 {
c.MinLength = 256
}
return c
}
// DefaultResponseCompressMimeTypes 返回内置默认 MIME 列表(供引擎匹配)
func DefaultResponseCompressMimeTypes() []string {
return append([]string(nil), defaultResponseCompressMimeTypes...)
}
// ParseTransportConfig 解析传输配置
func ParseTransportConfig(transportJSON string) TransportConfig {
var config TransportConfig
// 设置默认值
config.MaxIdleConns = 0
config.MaxIdleConnsPerHost = 0
config.MaxConnsPerHost = 0
config.IdleConnTimeout = 0
config.TLSHandshakeTimeout = 0
config.ExpectContinueTimeout = 0
// 如果JSON不为空,则解析覆盖默认值
if transportJSON != "" {
err := json.Unmarshal([]byte(transportJSON), &config)
if err != nil {
// 解析失败时使用默认值,可以记录日志
return config
}
}
return config
}
// ParseHostsDefense 解析防御配置
func ParseHostsDefense(defenseJSON string) HostsDefense {
var defense HostsDefense
// 设置默认值
defense.DEFENSE_BOT = 1
defense.DEFENSE_SQLI = 1
defense.DEFENSE_XSS = 1
defense.DEFENSE_SCAN = 1
defense.DEFENSE_RCE = 1
defense.DEFENSE_SENSITIVE = 1
defense.DEFENSE_DIR_TRAVERSAL = 1
defense.DEFENSE_OWASP_SET = 0
defense.DEFENSE_AI = 0
// 如果JSON不为空,则解析覆盖默认值
if defenseJSON != "" {
err := json.Unmarshal([]byte(defenseJSON), &defense)
if err != nil {
// 解析失败时使用默认值,可以记录日志
return defense
}
}
return defense
}
// ParseCustomHeadersConfig 解析自定义头信息配置
func ParseCustomHeadersConfig(customHeadersJSON string) CustomHeadersConfig {
var config CustomHeadersConfig
// 设置默认值
config.IsEnableCustomHeaders = 0
config.Headers = []CustomHeaderItem{}
// 如果JSON不为空,则解析覆盖默认值
if customHeadersJSON != "" {
err := json.Unmarshal([]byte(customHeadersJSON), &config)
if err != nil {
// 解析失败时使用默认值,可以记录日志
return config
}
}
return config
}
// ParseCustomResponseHeadersConfig 解析自定义响应头信息配置(支持 V2 多规则格式和旧版扁平格式)
// 旧格式(只有 headers 字段)会自动转换为一条 global 规则,保持向后兼容。
func ParseCustomResponseHeadersConfig(customResponseHeadersJSON string) CustomResponseHeadersConfig {
var config CustomResponseHeadersConfig
config.IsEnableCustomHeaders = 0
config.Rules = []CustomResponseHeaderRule{}
if customResponseHeadersJSON == "" {
return config
}
if err := json.Unmarshal([]byte(customResponseHeadersJSON), &config); err != nil {
return config
}
// 向后兼容:若 rules 为空但存在旧版 headers 字段,转换为一条 global 规则
if len(config.Rules) == 0 && len(config.Headers) > 0 {
config.Rules = []CustomResponseHeaderRule{
{
RuleName: "全局默认",
MatchType: "global",
MatchValue: "",
MergeMode: "merge",
Headers: config.Headers,
},
}
config.Headers = nil
}
// 为每条规则设置默认值
for i := range config.Rules {
if config.Rules[i].MatchType == "" {
config.Rules[i].MatchType = "global"
}
if config.Rules[i].MergeMode == "" {
config.Rules[i].MergeMode = "merge"
}
if config.Rules[i].Headers == nil {
config.Rules[i].Headers = []CustomHeaderItem{}
}
}
return config
}
// GetClientIPByMode 根据IP模式获取客户端IP
// ipMode: "nic" 网卡模式使用 NetSrcIp,"proxy" 代理模式使用 SRC_IP
// netSrcIp: 从网卡获取的IP (r.RemoteAddr)
// srcIP: 从代理头获取的IP (X-Forwarded-For等)
func GetClientIPByMode(ipMode string, netSrcIp string, srcIP string) string {
if ipMode == "proxy" {
return srcIP
}
// 默认使用网卡模式
return netSrcIp
}