mirror of
https://github.com/TeaOSLab/EdgeNode.git
synced 2025-11-22 22:40:30 +08:00
WAF策略中增加验证码相关定制设置
This commit is contained in:
@@ -194,7 +194,7 @@ func (this *HTTPRequest) checkWAFRequest(firewallPolicy *firewallconfigs.HTTPFir
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 规则测试
|
// 规则测试
|
||||||
w := sharedWAFManager.FindWAF(firewallPolicy.Id)
|
w := waf.SharedWAFManager.FindWAF(firewallPolicy.Id)
|
||||||
if w == nil {
|
if w == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -261,7 +261,7 @@ func (this *HTTPRequest) checkWAFResponse(firewallPolicy *firewallconfigs.HTTPFi
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w := sharedWAFManager.FindWAF(firewallPolicy.Id)
|
w := waf.SharedWAFManager.FindWAF(firewallPolicy.Id)
|
||||||
if w == nil {
|
if w == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeNode/internal/stats"
|
"github.com/TeaOSLab/EdgeNode/internal/stats"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/trackers"
|
"github.com/TeaOSLab/EdgeNode/internal/trackers"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/utils"
|
"github.com/TeaOSLab/EdgeNode/internal/utils"
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/waf"
|
||||||
"github.com/andybalholm/brotli"
|
"github.com/andybalholm/brotli"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/lists"
|
"github.com/iwind/TeaGo/lists"
|
||||||
@@ -865,7 +866,7 @@ func (this *Node) onReload(config *nodeconfigs.NodeConfig) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WAF策略
|
// WAF策略
|
||||||
sharedWAFManager.UpdatePolicies(config.FindAllFirewallPolicies())
|
waf.SharedWAFManager.UpdatePolicies(config.FindAllFirewallPolicies())
|
||||||
iplibrary.SharedActionManager.UpdateActions(config.FirewallActions)
|
iplibrary.SharedActionManager.UpdateActions(config.FirewallActions)
|
||||||
|
|
||||||
// 统计指标
|
// 统计指标
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type AllowAction struct {
|
type AllowAction struct {
|
||||||
|
BaseAction
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *AllowAction) Init(waf *WAF) error {
|
func (this *AllowAction) Init(waf *WAF) error {
|
||||||
|
|||||||
@@ -7,6 +7,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type BaseAction struct {
|
type BaseAction struct {
|
||||||
|
currentActionId int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActionId 读取ActionId
|
||||||
|
func (this *BaseAction) ActionId() int64 {
|
||||||
|
return this.currentActionId
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetActionId 设置Id
|
||||||
|
func (this *BaseAction) SetActionId(actionId int64) {
|
||||||
|
this.currentActionId = actionId
|
||||||
}
|
}
|
||||||
|
|
||||||
// CloseConn 关闭连接
|
// CloseConn 关闭连接
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ var urlPrefixReg = regexp.MustCompile("^(?i)(http|https)://")
|
|||||||
var httpClient = utils.SharedHttpClient(5 * time.Second)
|
var httpClient = utils.SharedHttpClient(5 * time.Second)
|
||||||
|
|
||||||
type BlockAction struct {
|
type BlockAction struct {
|
||||||
|
BaseAction
|
||||||
|
|
||||||
StatusCode int `yaml:"statusCode" json:"statusCode"`
|
StatusCode int `yaml:"statusCode" json:"statusCode"`
|
||||||
Body string `yaml:"body" json:"body"` // supports HTML
|
Body string `yaml:"body" json:"body"` // supports HTML
|
||||||
URL string `yaml:"url" json:"url"`
|
URL string `yaml:"url" json:"url"`
|
||||||
|
|||||||
@@ -18,16 +18,71 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type CaptchaAction struct {
|
type CaptchaAction struct {
|
||||||
|
BaseAction
|
||||||
|
|
||||||
Life int32 `yaml:"life" json:"life"`
|
Life int32 `yaml:"life" json:"life"`
|
||||||
MaxFails int `yaml:"maxFails" json:"maxFails"` // 最大失败次数
|
MaxFails int `yaml:"maxFails" json:"maxFails"` // 最大失败次数
|
||||||
FailBlockTimeout int `yaml:"failBlockTimeout" json:"failBlockTimeout"` // 失败拦截时间
|
FailBlockTimeout int `yaml:"failBlockTimeout" json:"failBlockTimeout"` // 失败拦截时间
|
||||||
|
FailBlockScopeAll bool `yaml:"failBlockScopeAll" json:"failBlockScopeAll"` // 是否全局有效
|
||||||
|
|
||||||
Language string `yaml:"language" json:"language"` // 语言,zh-CN, en-US ...
|
CountLetters int8 `yaml:"countLetters" json:"countLetters"`
|
||||||
|
|
||||||
|
UIIsOn bool `yaml:"uiIsOn" json:"uiIsOn"` // 是否使用自定义UI
|
||||||
|
UITitle string `yaml:"uiTitle" json:"uiTitle"` // 消息标题
|
||||||
|
UIPrompt string `yaml:"uiPrompt" json:"uiPrompt"` // 消息提示
|
||||||
|
UIButtonTitle string `yaml:"uiButtonTitle" json:"uiButtonTitle"` // 按钮标题
|
||||||
|
UIShowRequestId bool `yaml:"uiShowRequestId" json:"uiShowRequestId"` // 是否显示请求ID
|
||||||
|
UICss string `yaml:"uiCss" json:"uiCss"` // CSS样式
|
||||||
|
UIFooter string `yaml:"uiFooter" json:"uiFooter"` // 页脚
|
||||||
|
UIBody string `yaml:"uiBody" json:"uiBody"` // 内容轮廓
|
||||||
|
|
||||||
|
Lang string `yaml:"lang" json:"lang"` // 语言,zh-CN, en-US ...
|
||||||
AddToWhiteList bool `yaml:"addToWhiteList" json:"addToWhiteList"` // 是否加入到白名单
|
AddToWhiteList bool `yaml:"addToWhiteList" json:"addToWhiteList"` // 是否加入到白名单
|
||||||
Scope string `yaml:"scope" json:"scope"`
|
Scope string `yaml:"scope" json:"scope"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *CaptchaAction) Init(waf *WAF) error {
|
func (this *CaptchaAction) Init(waf *WAF) error {
|
||||||
|
if waf.DefaultCaptchaAction != nil {
|
||||||
|
if this.Life <= 0 {
|
||||||
|
this.Life = waf.DefaultCaptchaAction.Life
|
||||||
|
}
|
||||||
|
if this.MaxFails <= 0 {
|
||||||
|
this.MaxFails = waf.DefaultCaptchaAction.MaxFails
|
||||||
|
}
|
||||||
|
if this.FailBlockTimeout <= 0 {
|
||||||
|
this.FailBlockTimeout = waf.DefaultCaptchaAction.FailBlockTimeout
|
||||||
|
}
|
||||||
|
this.FailBlockScopeAll = waf.DefaultCaptchaAction.FailBlockScopeAll
|
||||||
|
|
||||||
|
if this.CountLetters <= 0 {
|
||||||
|
this.CountLetters = waf.DefaultCaptchaAction.CountLetters
|
||||||
|
}
|
||||||
|
|
||||||
|
this.UIIsOn = waf.DefaultCaptchaAction.UIIsOn
|
||||||
|
if len(this.UITitle) == 0 {
|
||||||
|
this.UITitle = waf.DefaultCaptchaAction.UITitle
|
||||||
|
}
|
||||||
|
if len(this.UIPrompt) == 0 {
|
||||||
|
this.UIPrompt = waf.DefaultCaptchaAction.UIPrompt
|
||||||
|
}
|
||||||
|
if len(this.UIButtonTitle) == 0 {
|
||||||
|
this.UIButtonTitle = waf.DefaultCaptchaAction.UIButtonTitle
|
||||||
|
}
|
||||||
|
this.UIShowRequestId = waf.DefaultCaptchaAction.UIShowRequestId
|
||||||
|
if len(this.UICss) == 0 {
|
||||||
|
this.UICss = waf.DefaultCaptchaAction.UICss
|
||||||
|
}
|
||||||
|
if len(this.UIFooter) == 0 {
|
||||||
|
this.UIFooter = waf.DefaultCaptchaAction.UIFooter
|
||||||
|
}
|
||||||
|
if len(this.UIBody) == 0 {
|
||||||
|
this.UIBody = waf.DefaultCaptchaAction.UIBody
|
||||||
|
}
|
||||||
|
if len(this.Lang) == 0 {
|
||||||
|
this.Lang = waf.DefaultCaptchaAction.Lang
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +104,7 @@ func (this *CaptchaAction) Perform(waf *WAF, group *RuleGroup, set *RuleSet, req
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
refURL := request.WAFRaw().URL.String()
|
var refURL = request.WAFRaw().URL.String()
|
||||||
|
|
||||||
// 覆盖配置
|
// 覆盖配置
|
||||||
if strings.HasPrefix(refURL, CaptchaPath) {
|
if strings.HasPrefix(refURL, CaptchaPath) {
|
||||||
@@ -63,10 +118,8 @@ func (this *CaptchaAction) Perform(waf *WAF, group *RuleGroup, set *RuleSet, req
|
|||||||
}
|
}
|
||||||
|
|
||||||
var captchaConfig = maps.Map{
|
var captchaConfig = maps.Map{
|
||||||
"action": this,
|
"actionId": this.ActionId(),
|
||||||
"timestamp": time.Now().Unix(),
|
"timestamp": time.Now().Unix(),
|
||||||
"maxFails": this.MaxFails,
|
|
||||||
"failBlockTimeout": this.FailBlockTimeout,
|
|
||||||
"url": refURL,
|
"url": refURL,
|
||||||
"policyId": waf.Id,
|
"policyId": waf.Id,
|
||||||
"groupId": group.Id,
|
"groupId": group.Id,
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type GoGroupAction struct {
|
type GoGroupAction struct {
|
||||||
|
BaseAction
|
||||||
|
|
||||||
GroupId string `yaml:"groupId" json:"groupId"`
|
GroupId string `yaml:"groupId" json:"groupId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type GoSetAction struct {
|
type GoSetAction struct {
|
||||||
|
BaseAction
|
||||||
|
|
||||||
GroupId string `yaml:"groupId" json:"groupId"`
|
GroupId string `yaml:"groupId" json:"groupId"`
|
||||||
SetId string `yaml:"setId" json:"setId"`
|
SetId string `yaml:"setId" json:"setId"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,12 @@ type ActionInterface interface {
|
|||||||
// Init 初始化
|
// Init 初始化
|
||||||
Init(waf *WAF) error
|
Init(waf *WAF) error
|
||||||
|
|
||||||
|
// ActionId 读取ActionId
|
||||||
|
ActionId() int64
|
||||||
|
|
||||||
|
// SetActionId 设置ID
|
||||||
|
SetActionId(id int64)
|
||||||
|
|
||||||
// Code 代号
|
// Code 代号
|
||||||
Code() string
|
Code() string
|
||||||
|
|
||||||
@@ -20,6 +26,6 @@ type ActionInterface interface {
|
|||||||
// WillChange determine if the action will change the request
|
// WillChange determine if the action will change the request
|
||||||
WillChange() bool
|
WillChange() bool
|
||||||
|
|
||||||
// Perform perform the action
|
// Perform the action
|
||||||
Perform(waf *WAF, group *RuleGroup, set *RuleSet, request requests.Request, writer http.ResponseWriter) (allow bool)
|
Perform(waf *WAF, group *RuleGroup, set *RuleSet, request requests.Request, writer http.ResponseWriter) (allow bool)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type LogAction struct {
|
type LogAction struct {
|
||||||
|
BaseAction
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *LogAction) Init(waf *WAF) error {
|
func (this *LogAction) Init(waf *WAF) error {
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type NotifyAction struct {
|
type NotifyAction struct {
|
||||||
|
BaseAction
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *NotifyAction) Init(waf *WAF) error {
|
func (this *NotifyAction) Init(waf *WAF) error {
|
||||||
@@ -69,7 +70,7 @@ func (this *NotifyAction) WillChange() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform perform the action
|
// Perform the action
|
||||||
func (this *NotifyAction) Perform(waf *WAF, group *RuleGroup, set *RuleSet, request requests.Request, writer http.ResponseWriter) (allow bool) {
|
func (this *NotifyAction) Perform(waf *WAF, group *RuleGroup, set *RuleSet, request requests.Request, writer http.ResponseWriter) (allow bool) {
|
||||||
select {
|
select {
|
||||||
case notifyChan <- ¬ifyTask{
|
case notifyChan <- ¬ifyTask{
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type TagAction struct {
|
type TagAction struct {
|
||||||
|
BaseAction
|
||||||
|
|
||||||
Tags []string `yaml:"tags" json:"tags"`
|
Tags []string `yaml:"tags" json:"tags"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,15 +5,19 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var seedActionId int64 = 1
|
||||||
|
|
||||||
func FindActionInstance(action ActionString, options maps.Map) ActionInterface {
|
func FindActionInstance(action ActionString, options maps.Map) ActionInterface {
|
||||||
for _, def := range AllActions {
|
for _, def := range AllActions {
|
||||||
if def.Code == action {
|
if def.Code == action {
|
||||||
if def.Type != nil {
|
if def.Type != nil {
|
||||||
// create new instance
|
// create new instance
|
||||||
ptrValue := reflect.New(def.Type)
|
var ptrValue = reflect.New(def.Type)
|
||||||
instance := ptrValue.Interface().(ActionInterface)
|
var instance = ptrValue.Interface().(ActionInterface)
|
||||||
|
instance.SetActionId(atomic.AddInt64(&seedActionId, 1))
|
||||||
|
|
||||||
if len(options) > 0 {
|
if len(options) > 0 {
|
||||||
optionsJSON, err := json.Marshal(options)
|
optionsJSON, err := json.Marshal(options)
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/ttlcache"
|
"github.com/TeaOSLab/EdgeNode/internal/ttlcache"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/utils"
|
"github.com/TeaOSLab/EdgeNode/internal/utils"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/utils/jsonutils"
|
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/waf/requests"
|
"github.com/TeaOSLab/EdgeNode/internal/waf/requests"
|
||||||
"github.com/dchest/captcha"
|
"github.com/dchest/captcha"
|
||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
@@ -26,8 +25,8 @@ func NewCaptchaValidator() *CaptchaValidator {
|
|||||||
return &CaptchaValidator{}
|
return &CaptchaValidator{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *CaptchaValidator) Run(request requests.Request, writer http.ResponseWriter) {
|
func (this *CaptchaValidator) Run(req requests.Request, writer http.ResponseWriter) {
|
||||||
var info = request.WAFRaw().URL.Query().Get("info")
|
var info = req.WAFRaw().URL.Query().Get("info")
|
||||||
if len(info) == 0 {
|
if len(info) == 0 {
|
||||||
writer.WriteHeader(http.StatusBadRequest)
|
writer.WriteHeader(http.StatusBadRequest)
|
||||||
_, _ = writer.Write([]byte("invalid request"))
|
_, _ = writer.Write([]byte("invalid request"))
|
||||||
@@ -41,35 +40,48 @@ func (this *CaptchaValidator) Run(request requests.Request, writer http.Response
|
|||||||
|
|
||||||
var timestamp = m.GetInt64("timestamp")
|
var timestamp = m.GetInt64("timestamp")
|
||||||
if timestamp < time.Now().Unix()-600 { // 10分钟之后信息过期
|
if timestamp < time.Now().Unix()-600 { // 10分钟之后信息过期
|
||||||
http.Redirect(writer, request.WAFRaw(), m.GetString("url"), http.StatusTemporaryRedirect)
|
http.Redirect(writer, req.WAFRaw(), m.GetString("url"), http.StatusTemporaryRedirect)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var actionConfig = &CaptchaAction{}
|
|
||||||
err = jsonutils.MapToObject(m.GetMap("action"), actionConfig)
|
|
||||||
if err != nil {
|
|
||||||
http.Redirect(writer, request.WAFRaw(), m.GetString("url"), http.StatusTemporaryRedirect)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var actionId = m.GetInt64("actionId")
|
||||||
var setId = m.GetInt64("setId")
|
var setId = m.GetInt64("setId")
|
||||||
var originURL = m.GetString("url")
|
var originURL = m.GetString("url")
|
||||||
var maxFails = m.GetInt("maxFails")
|
|
||||||
var failBlockTimeout = m.GetInt("failBlockTimeout")
|
|
||||||
var policyId = m.GetInt64("policyId")
|
var policyId = m.GetInt64("policyId")
|
||||||
var groupId = m.GetInt64("groupId")
|
var groupId = m.GetInt64("groupId")
|
||||||
if request.WAFRaw().Method == http.MethodPost && len(request.WAFRaw().FormValue("GOEDGE_WAF_CAPTCHA_ID")) > 0 {
|
|
||||||
this.validate(actionConfig, maxFails, failBlockTimeout, policyId, groupId, setId, originURL, request, writer)
|
var waf = SharedWAFManager.FindWAF(policyId)
|
||||||
|
if waf == nil {
|
||||||
|
http.Redirect(writer, req.WAFRaw(), originURL, http.StatusTemporaryRedirect)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var actionConfig = waf.FindAction(actionId)
|
||||||
|
if actionConfig == nil {
|
||||||
|
http.Redirect(writer, req.WAFRaw(), originURL, http.StatusTemporaryRedirect)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
captchaActionConfig, ok := actionConfig.(*CaptchaAction)
|
||||||
|
if !ok {
|
||||||
|
http.Redirect(writer, req.WAFRaw(), originURL, http.StatusTemporaryRedirect)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.WAFRaw().Method == http.MethodPost && len(req.WAFRaw().FormValue("GOEDGE_WAF_CAPTCHA_ID")) > 0 {
|
||||||
|
this.validate(captchaActionConfig, policyId, groupId, setId, originURL, req, writer)
|
||||||
} else {
|
} else {
|
||||||
// 增加计数
|
// 增加计数
|
||||||
this.IncreaseFails(request, maxFails, failBlockTimeout, policyId, groupId, setId)
|
this.IncreaseFails(req, captchaActionConfig, policyId, groupId, setId)
|
||||||
this.show(actionConfig, request, writer)
|
this.show(captchaActionConfig, req, writer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *CaptchaValidator) show(actionConfig *CaptchaAction, request requests.Request, writer http.ResponseWriter) {
|
func (this *CaptchaValidator) show(actionConfig *CaptchaAction, req requests.Request, writer http.ResponseWriter) {
|
||||||
// show captcha
|
// show captcha
|
||||||
var captchaId = captcha.NewLen(6)
|
var countLetters = 6
|
||||||
|
if actionConfig.CountLetters > 0 && actionConfig.CountLetters <= 10 {
|
||||||
|
countLetters = int(actionConfig.CountLetters)
|
||||||
|
}
|
||||||
|
var captchaId = captcha.NewLen(countLetters)
|
||||||
var buf = bytes.NewBuffer([]byte{})
|
var buf = bytes.NewBuffer([]byte{})
|
||||||
err := captcha.WriteImage(buf, captchaId, 200, 100)
|
err := captcha.WriteImage(buf, captchaId, 200, 100)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -77,9 +89,9 @@ func (this *CaptchaValidator) show(actionConfig *CaptchaAction, request requests
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var lang = actionConfig.Language
|
var lang = actionConfig.Lang
|
||||||
if len(lang) == 0 {
|
if len(lang) == 0 {
|
||||||
acceptLanguage := request.WAFRaw().Header.Get("Accept-Language")
|
var acceptLanguage = req.WAFRaw().Header.Get("Accept-Language")
|
||||||
if len(acceptLanguage) > 0 {
|
if len(acceptLanguage) > 0 {
|
||||||
langIndex := strings.Index(acceptLanguage, ",")
|
langIndex := strings.Index(acceptLanguage, ",")
|
||||||
if langIndex > 0 {
|
if langIndex > 0 {
|
||||||
@@ -114,12 +126,62 @@ func (this *CaptchaValidator) show(actionConfig *CaptchaAction, request requests
|
|||||||
msgRequestId = "Request ID"
|
msgRequestId = "Request ID"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var msgCss = ""
|
||||||
|
var requestIdBox = `<address>` + msgRequestId + `: ` + req.Format("${requestId}") + `</address>`
|
||||||
|
var msgFooter = ""
|
||||||
|
var body = `<form method="POST">
|
||||||
|
<input type="hidden" name="GOEDGE_WAF_CAPTCHA_ID" value="` + captchaId + `"/>
|
||||||
|
<div class="ui-image">
|
||||||
|
<img src="data:image/png;base64, ` + base64.StdEncoding.EncodeToString(buf.Bytes()) + `"/>` + `
|
||||||
|
</div>
|
||||||
|
<div class="ui-input">
|
||||||
|
<p>` + msgPrompt + `</p>
|
||||||
|
<input type="text" name="GOEDGE_WAF_CAPTCHA_CODE" id="GOEDGE_WAF_CAPTCHA_CODE" maxlength="6" autocomplete="off" z-index="1" class="input"/>
|
||||||
|
</div>
|
||||||
|
<div class="ui-button">
|
||||||
|
<button type="submit" style="line-height:24px;margin-top:10px">` + msgButtonTitle + `</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
` + requestIdBox + `
|
||||||
|
` + msgFooter + ``
|
||||||
|
|
||||||
|
// 默认设置
|
||||||
|
if actionConfig.UIIsOn {
|
||||||
|
if len(actionConfig.UITitle) > 0 {
|
||||||
|
msgTitle = actionConfig.UITitle
|
||||||
|
}
|
||||||
|
if len(actionConfig.UIPrompt) > 0 {
|
||||||
|
msgPrompt = actionConfig.UIPrompt
|
||||||
|
}
|
||||||
|
if len(actionConfig.UIButtonTitle) > 0 {
|
||||||
|
msgButtonTitle = actionConfig.UIButtonTitle
|
||||||
|
}
|
||||||
|
if len(actionConfig.UICss) > 0 {
|
||||||
|
msgCss = actionConfig.UICss
|
||||||
|
}
|
||||||
|
if !actionConfig.UIShowRequestId {
|
||||||
|
requestIdBox = ""
|
||||||
|
}
|
||||||
|
if len(actionConfig.UIFooter) > 0 {
|
||||||
|
msgFooter = actionConfig.UIFooter
|
||||||
|
}
|
||||||
|
if len(actionConfig.UIBody) > 0 {
|
||||||
|
var index = strings.Index(actionConfig.UIBody, "${body}")
|
||||||
|
if index < 0 {
|
||||||
|
body = actionConfig.UIBody + body
|
||||||
|
} else {
|
||||||
|
body = actionConfig.UIBody[:index] + body + actionConfig.UIBody[index+7:] // 7是"${body}"的长度
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
_, _ = writer.Write([]byte(`<!DOCTYPE html>
|
_, _ = writer.Write([]byte(`<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>` + msgTitle + `</title>
|
<title>` + msgTitle + `</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
|
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
if (window.addEventListener != null) {
|
if (window.addEventListener != null) {
|
||||||
window.addEventListener("load", function () {
|
window.addEventListener("load", function () {
|
||||||
@@ -131,32 +193,22 @@ func (this *CaptchaValidator) show(actionConfig *CaptchaAction, request requests
|
|||||||
form { width: 20em; margin: 0 auto; text-align: center; }
|
form { width: 20em; margin: 0 auto; text-align: center; }
|
||||||
.input { font-size:16px;line-height:24px; letter-spacing: 15px; padding-left: 10px; width: 140px; }
|
.input { font-size:16px;line-height:24px; letter-spacing: 15px; padding-left: 10px; width: 140px; }
|
||||||
address { margin-top: 1em; padding-top: 0.5em; border-top: 1px #ccc solid; text-align: center; }
|
address { margin-top: 1em; padding-top: 0.5em; border-top: 1px #ccc solid; text-align: center; }
|
||||||
|
` + msgCss + `
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>` + body + `
|
||||||
<form method="POST">
|
|
||||||
<input type="hidden" name="GOEDGE_WAF_CAPTCHA_ID" value="` + captchaId + `"/>
|
|
||||||
<img src="data:image/png;base64, ` + base64.StdEncoding.EncodeToString(buf.Bytes()) + `"/>` + `
|
|
||||||
<div>
|
|
||||||
<p>` + msgPrompt + `</p>
|
|
||||||
<input type="text" name="GOEDGE_WAF_CAPTCHA_CODE" id="GOEDGE_WAF_CAPTCHA_CODE" maxlength="6" autocomplete="off" z-index="1" class="input"/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<button type="submit" style="line-height:24px;margin-top:10px">` + msgButtonTitle + `</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<address>` + msgRequestId + `: ` + request.Format("${requestId}") + `</address>
|
|
||||||
</body>
|
</body>
|
||||||
</html>`))
|
</html>`))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *CaptchaValidator) validate(actionConfig *CaptchaAction, maxFails int, failBlockTimeout int, policyId int64, groupId int64, setId int64, originURL string, request requests.Request, writer http.ResponseWriter) (allow bool) {
|
func (this *CaptchaValidator) validate(actionConfig *CaptchaAction, policyId int64, groupId int64, setId int64, originURL string, req requests.Request, writer http.ResponseWriter) (allow bool) {
|
||||||
var captchaId = request.WAFRaw().FormValue("GOEDGE_WAF_CAPTCHA_ID")
|
|
||||||
|
var captchaId = req.WAFRaw().FormValue("GOEDGE_WAF_CAPTCHA_ID")
|
||||||
if len(captchaId) > 0 {
|
if len(captchaId) > 0 {
|
||||||
var captchaCode = request.WAFRaw().FormValue("GOEDGE_WAF_CAPTCHA_CODE")
|
var captchaCode = req.WAFRaw().FormValue("GOEDGE_WAF_CAPTCHA_CODE")
|
||||||
if captcha.VerifyString(captchaId, captchaCode) {
|
if captcha.VerifyString(captchaId, captchaCode) {
|
||||||
// 清除计数
|
// 清除计数
|
||||||
ttlcache.SharedCache.Delete("CAPTCHA:FAILS:" + request.WAFRemoteIP())
|
ttlcache.SharedCache.Delete(this.cacheKey(req))
|
||||||
|
|
||||||
var life = CaptchaSeconds
|
var life = CaptchaSeconds
|
||||||
if actionConfig.Life > 0 {
|
if actionConfig.Life > 0 {
|
||||||
@@ -164,18 +216,18 @@ func (this *CaptchaValidator) validate(actionConfig *CaptchaAction, maxFails int
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 加入到白名单
|
// 加入到白名单
|
||||||
SharedIPWhiteList.RecordIP("set:"+strconv.FormatInt(setId, 10), actionConfig.Scope, request.WAFServerId(), request.WAFRemoteIP(), time.Now().Unix()+int64(life), policyId, false, groupId, setId, "")
|
SharedIPWhiteList.RecordIP("set:"+strconv.FormatInt(setId, 10), actionConfig.Scope, req.WAFServerId(), req.WAFRemoteIP(), time.Now().Unix()+int64(life), policyId, false, groupId, setId, "")
|
||||||
|
|
||||||
http.Redirect(writer, request.WAFRaw(), originURL, http.StatusSeeOther)
|
http.Redirect(writer, req.WAFRaw(), originURL, http.StatusSeeOther)
|
||||||
|
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
// 增加计数
|
// 增加计数
|
||||||
if !this.IncreaseFails(request, maxFails, failBlockTimeout, policyId, groupId, setId) {
|
if !this.IncreaseFails(req, actionConfig, policyId, groupId, setId) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
http.Redirect(writer, request.WAFRaw(), request.WAFRaw().URL.String(), http.StatusSeeOther)
|
http.Redirect(writer, req.WAFRaw(), req.WAFRaw().URL.String(), http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,17 +235,28 @@ func (this *CaptchaValidator) validate(actionConfig *CaptchaAction, maxFails int
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IncreaseFails 增加失败次数,以便后续操作
|
// IncreaseFails 增加失败次数,以便后续操作
|
||||||
func (this *CaptchaValidator) IncreaseFails(request requests.Request, maxFails int, failBlockTimeout int, policyId int64, groupId int64, setId int64) (goNext bool) {
|
func (this *CaptchaValidator) IncreaseFails(req requests.Request, actionConfig *CaptchaAction, policyId int64, groupId int64, setId int64) (goNext bool) {
|
||||||
|
var maxFails = actionConfig.MaxFails
|
||||||
|
var failBlockTimeout = actionConfig.FailBlockTimeout
|
||||||
if maxFails > 0 && failBlockTimeout > 0 {
|
if maxFails > 0 && failBlockTimeout > 0 {
|
||||||
// 加上展示的计数
|
// 加上展示的计数
|
||||||
maxFails *= 2
|
maxFails *= 2
|
||||||
|
|
||||||
var countFails = ttlcache.SharedCache.IncreaseInt64("CAPTCHA:FAILS:"+request.WAFRemoteIP(), 1, time.Now().Unix()+300, true)
|
var countFails = ttlcache.SharedCache.IncreaseInt64(this.cacheKey(req), 1, time.Now().Unix()+300, true)
|
||||||
if int(countFails) >= maxFails {
|
if int(countFails) >= maxFails {
|
||||||
var useLocalFirewall = false
|
var useLocalFirewall = false
|
||||||
SharedIPBlackList.RecordIP(IPTypeAll, firewallconfigs.FirewallScopeService, request.WAFServerId(), request.WAFRemoteIP(), time.Now().Unix()+int64(failBlockTimeout), policyId, useLocalFirewall, groupId, setId, "CAPTCHA验证连续失败")
|
|
||||||
|
if actionConfig.FailBlockScopeAll {
|
||||||
|
useLocalFirewall = true
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedIPBlackList.RecordIP(IPTypeAll, firewallconfigs.FirewallScopeService, req.WAFServerId(), req.WAFRemoteIP(), time.Now().Unix()+int64(failBlockTimeout), policyId, useLocalFirewall, groupId, setId, "CAPTCHA验证连续失败")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *CaptchaValidator) cacheKey(req requests.Request) string {
|
||||||
|
return "CAPTCHA:FAILS:" + req.WAFRemoteIP() + ":" + types.String(req.WAFServerId())
|
||||||
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ func (this *RuleSet) Init(waf *WAF) error {
|
|||||||
// action instances
|
// action instances
|
||||||
this.actionInstances = []ActionInterface{}
|
this.actionInstances = []ActionInterface{}
|
||||||
for _, action := range this.Actions {
|
for _, action := range this.Actions {
|
||||||
instance := FindActionInstance(action.Code, action.Options)
|
var instance = FindActionInstance(action.Code, action.Options)
|
||||||
if instance == nil {
|
if instance == nil {
|
||||||
remotelogs.Error("WAF_RULE_SET", "can not find instance for action '"+action.Code+"'")
|
remotelogs.Error("WAF_RULE_SET", "can not find instance for action '"+action.Code+"'")
|
||||||
continue
|
continue
|
||||||
@@ -79,6 +79,7 @@ func (this *RuleSet) Init(waf *WAF) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.actionInstances = append(this.actionInstances, instance)
|
this.actionInstances = append(this.actionInstances, instance)
|
||||||
|
waf.AddAction(instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort actions
|
// sort actions
|
||||||
|
|||||||
@@ -27,11 +27,13 @@ type WAF struct {
|
|||||||
SYNFlood *firewallconfigs.SYNFloodConfig `yaml:"synFlood" json:"synFlood"`
|
SYNFlood *firewallconfigs.SYNFloodConfig `yaml:"synFlood" json:"synFlood"`
|
||||||
|
|
||||||
DefaultBlockAction *BlockAction
|
DefaultBlockAction *BlockAction
|
||||||
|
DefaultCaptchaAction *CaptchaAction
|
||||||
|
|
||||||
hasInboundRules bool
|
hasInboundRules bool
|
||||||
hasOutboundRules bool
|
hasOutboundRules bool
|
||||||
|
|
||||||
checkpointsMap map[string]checkpoints.CheckpointInterface // prefix => checkpoint
|
checkpointsMap map[string]checkpoints.CheckpointInterface // prefix => checkpoint
|
||||||
|
actionMap map[int64]ActionInterface // actionId => ActionInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWAF() *WAF {
|
func NewWAF() *WAF {
|
||||||
@@ -74,6 +76,9 @@ func (this *WAF) Init() (resultErrors []error) {
|
|||||||
this.checkpointsMap[def.Prefix] = instance
|
this.checkpointsMap[def.Prefix] = instance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// action map
|
||||||
|
this.actionMap = map[int64]ActionInterface{}
|
||||||
|
|
||||||
// rules
|
// rules
|
||||||
this.hasInboundRules = len(this.Inbound) > 0
|
this.hasInboundRules = len(this.Inbound) > 0
|
||||||
this.hasOutboundRules = len(this.Outbound) > 0
|
this.hasOutboundRules = len(this.Outbound) > 0
|
||||||
@@ -324,8 +329,16 @@ func (this *WAF) ContainsGroupCode(code string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *WAF) AddAction(action ActionInterface) {
|
||||||
|
this.actionMap[action.ActionId()] = action
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *WAF) FindAction(actionId int64) ActionInterface {
|
||||||
|
return this.actionMap[actionId]
|
||||||
|
}
|
||||||
|
|
||||||
func (this *WAF) Copy() *WAF {
|
func (this *WAF) Copy() *WAF {
|
||||||
waf := &WAF{
|
var waf = &WAF{
|
||||||
Id: this.Id,
|
Id: this.Id,
|
||||||
IsOn: this.IsOn,
|
IsOn: this.IsOn,
|
||||||
Name: this.Name,
|
Name: this.Name,
|
||||||
|
|||||||
@@ -1,26 +1,25 @@
|
|||||||
package nodes
|
package waf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/errors"
|
"github.com/TeaOSLab/EdgeNode/internal/errors"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/waf"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var sharedWAFManager = NewWAFManager()
|
var SharedWAFManager = NewWAFManager()
|
||||||
|
|
||||||
// WAFManager WAF管理器
|
// WAFManager WAF管理器
|
||||||
type WAFManager struct {
|
type WAFManager struct {
|
||||||
mapping map[int64]*waf.WAF // policyId => WAF
|
mapping map[int64]*WAF // policyId => WAF
|
||||||
locker sync.RWMutex
|
locker sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWAFManager 获取新对象
|
// NewWAFManager 获取新对象
|
||||||
func NewWAFManager() *WAFManager {
|
func NewWAFManager() *WAFManager {
|
||||||
return &WAFManager{
|
return &WAFManager{
|
||||||
mapping: map[int64]*waf.WAF{},
|
mapping: map[int64]*WAF{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,9 +28,9 @@ func (this *WAFManager) UpdatePolicies(policies []*firewallconfigs.HTTPFirewallP
|
|||||||
this.locker.Lock()
|
this.locker.Lock()
|
||||||
defer this.locker.Unlock()
|
defer this.locker.Unlock()
|
||||||
|
|
||||||
m := map[int64]*waf.WAF{}
|
m := map[int64]*WAF{}
|
||||||
for _, p := range policies {
|
for _, p := range policies {
|
||||||
w, err := this.convertWAF(p)
|
w, err := this.ConvertWAF(p)
|
||||||
if w != nil {
|
if w != nil {
|
||||||
m[p.Id] = w
|
m[p.Id] = w
|
||||||
}
|
}
|
||||||
@@ -44,22 +43,22 @@ func (this *WAFManager) UpdatePolicies(policies []*firewallconfigs.HTTPFirewallP
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FindWAF 查找WAF
|
// FindWAF 查找WAF
|
||||||
func (this *WAFManager) FindWAF(policyId int64) *waf.WAF {
|
func (this *WAFManager) FindWAF(policyId int64) *WAF {
|
||||||
this.locker.RLock()
|
this.locker.RLock()
|
||||||
w, _ := this.mapping[policyId]
|
w, _ := this.mapping[policyId]
|
||||||
this.locker.RUnlock()
|
this.locker.RUnlock()
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将Policy转换为WAF
|
// ConvertWAF 将Policy转换为WAF
|
||||||
func (this *WAFManager) convertWAF(policy *firewallconfigs.HTTPFirewallPolicy) (*waf.WAF, error) {
|
func (this *WAFManager) ConvertWAF(policy *firewallconfigs.HTTPFirewallPolicy) (*WAF, error) {
|
||||||
if policy == nil {
|
if policy == nil {
|
||||||
return nil, errors.New("policy should not be nil")
|
return nil, errors.New("policy should not be nil")
|
||||||
}
|
}
|
||||||
if len(policy.Mode) == 0 {
|
if len(policy.Mode) == 0 {
|
||||||
policy.Mode = firewallconfigs.FirewallModeDefend
|
policy.Mode = firewallconfigs.FirewallModeDefend
|
||||||
}
|
}
|
||||||
w := &waf.WAF{
|
var w = &WAF{
|
||||||
Id: policy.Id,
|
Id: policy.Id,
|
||||||
IsOn: policy.IsOn,
|
IsOn: policy.IsOn,
|
||||||
Name: policy.Name,
|
Name: policy.Name,
|
||||||
@@ -71,7 +70,7 @@ func (this *WAFManager) convertWAF(policy *firewallconfigs.HTTPFirewallPolicy) (
|
|||||||
// inbound
|
// inbound
|
||||||
if policy.Inbound != nil && policy.Inbound.IsOn {
|
if policy.Inbound != nil && policy.Inbound.IsOn {
|
||||||
for _, group := range policy.Inbound.Groups {
|
for _, group := range policy.Inbound.Groups {
|
||||||
g := &waf.RuleGroup{
|
g := &RuleGroup{
|
||||||
Id: group.Id,
|
Id: group.Id,
|
||||||
IsOn: group.IsOn,
|
IsOn: group.IsOn,
|
||||||
Name: group.Name,
|
Name: group.Name,
|
||||||
@@ -82,7 +81,7 @@ func (this *WAFManager) convertWAF(policy *firewallconfigs.HTTPFirewallPolicy) (
|
|||||||
|
|
||||||
// rule sets
|
// rule sets
|
||||||
for _, set := range group.Sets {
|
for _, set := range group.Sets {
|
||||||
s := &waf.RuleSet{
|
s := &RuleSet{
|
||||||
Id: set.Id,
|
Id: set.Id,
|
||||||
Code: set.Code,
|
Code: set.Code,
|
||||||
IsOn: set.IsOn,
|
IsOn: set.IsOn,
|
||||||
@@ -97,10 +96,10 @@ func (this *WAFManager) convertWAF(policy *firewallconfigs.HTTPFirewallPolicy) (
|
|||||||
|
|
||||||
// rules
|
// rules
|
||||||
for _, rule := range set.Rules {
|
for _, rule := range set.Rules {
|
||||||
r := &waf.Rule{
|
r := &Rule{
|
||||||
Description: rule.Description,
|
Description: rule.Description,
|
||||||
Param: rule.Param,
|
Param: rule.Param,
|
||||||
ParamFilters: []*waf.ParamFilter{},
|
ParamFilters: []*ParamFilter{},
|
||||||
Operator: rule.Operator,
|
Operator: rule.Operator,
|
||||||
Value: rule.Value,
|
Value: rule.Value,
|
||||||
IsCaseInsensitive: rule.IsCaseInsensitive,
|
IsCaseInsensitive: rule.IsCaseInsensitive,
|
||||||
@@ -108,7 +107,7 @@ func (this *WAFManager) convertWAF(policy *firewallconfigs.HTTPFirewallPolicy) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, paramFilter := range rule.ParamFilters {
|
for _, paramFilter := range rule.ParamFilters {
|
||||||
r.ParamFilters = append(r.ParamFilters, &waf.ParamFilter{
|
r.ParamFilters = append(r.ParamFilters, &ParamFilter{
|
||||||
Code: paramFilter.Code,
|
Code: paramFilter.Code,
|
||||||
Options: paramFilter.Options,
|
Options: paramFilter.Options,
|
||||||
})
|
})
|
||||||
@@ -127,7 +126,7 @@ func (this *WAFManager) convertWAF(policy *firewallconfigs.HTTPFirewallPolicy) (
|
|||||||
// outbound
|
// outbound
|
||||||
if policy.Outbound != nil && policy.Outbound.IsOn {
|
if policy.Outbound != nil && policy.Outbound.IsOn {
|
||||||
for _, group := range policy.Outbound.Groups {
|
for _, group := range policy.Outbound.Groups {
|
||||||
g := &waf.RuleGroup{
|
g := &RuleGroup{
|
||||||
Id: group.Id,
|
Id: group.Id,
|
||||||
IsOn: group.IsOn,
|
IsOn: group.IsOn,
|
||||||
Name: group.Name,
|
Name: group.Name,
|
||||||
@@ -138,7 +137,7 @@ func (this *WAFManager) convertWAF(policy *firewallconfigs.HTTPFirewallPolicy) (
|
|||||||
|
|
||||||
// rule sets
|
// rule sets
|
||||||
for _, set := range group.Sets {
|
for _, set := range group.Sets {
|
||||||
s := &waf.RuleSet{
|
s := &RuleSet{
|
||||||
Id: set.Id,
|
Id: set.Id,
|
||||||
Code: set.Code,
|
Code: set.Code,
|
||||||
IsOn: set.IsOn,
|
IsOn: set.IsOn,
|
||||||
@@ -154,7 +153,7 @@ func (this *WAFManager) convertWAF(policy *firewallconfigs.HTTPFirewallPolicy) (
|
|||||||
|
|
||||||
// rules
|
// rules
|
||||||
for _, rule := range set.Rules {
|
for _, rule := range set.Rules {
|
||||||
r := &waf.Rule{
|
r := &Rule{
|
||||||
Description: rule.Description,
|
Description: rule.Description,
|
||||||
Param: rule.Param,
|
Param: rule.Param,
|
||||||
Operator: rule.Operator,
|
Operator: rule.Operator,
|
||||||
@@ -172,9 +171,9 @@ func (this *WAFManager) convertWAF(policy *firewallconfigs.HTTPFirewallPolicy) (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// action
|
// block action
|
||||||
if policy.BlockOptions != nil {
|
if policy.BlockOptions != nil {
|
||||||
w.DefaultBlockAction = &waf.BlockAction{
|
w.DefaultBlockAction = &BlockAction{
|
||||||
StatusCode: policy.BlockOptions.StatusCode,
|
StatusCode: policy.BlockOptions.StatusCode,
|
||||||
Body: policy.BlockOptions.Body,
|
Body: policy.BlockOptions.Body,
|
||||||
URL: policy.BlockOptions.URL,
|
URL: policy.BlockOptions.URL,
|
||||||
@@ -182,6 +181,26 @@ func (this *WAFManager) convertWAF(policy *firewallconfigs.HTTPFirewallPolicy) (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// captcha action
|
||||||
|
if policy.CaptchaOptions != nil {
|
||||||
|
w.DefaultCaptchaAction = &CaptchaAction{
|
||||||
|
Life: policy.CaptchaOptions.Life,
|
||||||
|
MaxFails: policy.CaptchaOptions.MaxFails,
|
||||||
|
FailBlockTimeout: policy.CaptchaOptions.FailBlockTimeout,
|
||||||
|
FailBlockScopeAll: policy.CaptchaOptions.FailBlockScopeAll,
|
||||||
|
CountLetters: policy.CaptchaOptions.CountLetters,
|
||||||
|
UIIsOn: policy.CaptchaOptions.UIIsOn,
|
||||||
|
UITitle: policy.CaptchaOptions.UITitle,
|
||||||
|
UIPrompt: policy.CaptchaOptions.UIPrompt,
|
||||||
|
UIButtonTitle: policy.CaptchaOptions.UIButtonTitle,
|
||||||
|
UIShowRequestId: policy.CaptchaOptions.UIShowRequestId,
|
||||||
|
UICss: policy.CaptchaOptions.UICss,
|
||||||
|
UIFooter: policy.CaptchaOptions.UIFooter,
|
||||||
|
UIBody: policy.CaptchaOptions.UIBody,
|
||||||
|
Lang: policy.CaptchaOptions.Lang,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
errorList := w.Init()
|
errorList := w.Init()
|
||||||
if len(errorList) > 0 {
|
if len(errorList) > 0 {
|
||||||
return w, errorList[0]
|
return w, errorList[0]
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
package nodes
|
package waf_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/waf"
|
||||||
"github.com/iwind/TeaGo/logs"
|
"github.com/iwind/TeaGo/logs"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@@ -35,7 +36,7 @@ func TestWAFManager_convert(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
w, err := sharedWAFManager.convertWAF(p)
|
w, err := waf.SharedWAFManager.ConvertWAF(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user