diff --git a/internal/web/actions/default/servers/components/waf/policy.go b/internal/web/actions/default/servers/components/waf/policy.go index 2e7eacba..bc9ebc47 100644 --- a/internal/web/actions/default/servers/components/waf/policy.go +++ b/internal/web/actions/default/servers/components/waf/policy.go @@ -97,6 +97,7 @@ func (this *PolicyAction) RunGet(params struct { "blockOptions": firewallPolicy.BlockOptions, "pageOptions": firewallPolicy.PageOptions, "captchaOptions": firewallPolicy.CaptchaOptions, + "jsCookieOptions": firewallPolicy.JSCookieOptions, "useLocalFirewall": firewallPolicy.UseLocalFirewall, "synFlood": firewallPolicy.SYNFlood, "log": firewallPolicy.Log, diff --git a/internal/web/actions/default/servers/components/waf/update.go b/internal/web/actions/default/servers/components/waf/update.go index 51398f24..d3c1ced7 100644 --- a/internal/web/actions/default/servers/components/waf/update.go +++ b/internal/web/actions/default/servers/components/waf/update.go @@ -10,7 +10,6 @@ import ( "github.com/iwind/TeaGo/actions" "github.com/iwind/TeaGo/maps" "github.com/iwind/TeaGo/types" - "net/http" ) type UpdateAction struct { @@ -36,17 +35,17 @@ func (this *UpdateAction) RunGet(params struct { // block options if firewallPolicy.BlockOptions == nil { - firewallPolicy.BlockOptions = &firewallconfigs.HTTPFirewallBlockAction{ - StatusCode: http.StatusForbidden, - Body: "Blocked By WAF", - URL: "", - Timeout: 60, - } + firewallPolicy.BlockOptions = firewallconfigs.NewHTTPFirewallBlockAction() } // page options if firewallPolicy.PageOptions == nil { - firewallPolicy.PageOptions = firewallconfigs.DefaultHTTPFirewallPageAction() + firewallPolicy.PageOptions = firewallconfigs.NewHTTPFirewallPageAction() + } + + // jscookie options + if firewallPolicy.JSCookieOptions == nil { + firewallPolicy.JSCookieOptions = firewallconfigs.NewHTTPFirewallJavascriptCookieAction() } // mode @@ -79,6 +78,7 @@ func (this *UpdateAction) RunGet(params struct { "blockOptions": firewallPolicy.BlockOptions, "pageOptions": firewallPolicy.PageOptions, "captchaOptions": firewallPolicy.CaptchaOptions, + "jsCookieOptions": firewallPolicy.JSCookieOptions, "useLocalFirewall": firewallPolicy.UseLocalFirewall, "synFloodConfig": firewallPolicy.SYNFlood, "log": firewallPolicy.Log, @@ -110,21 +110,22 @@ func (this *UpdateAction) RunGet(params struct { } func (this *UpdateAction) RunPost(params struct { - FirewallPolicyId int64 - Name string - GroupCodes []string - BlockOptionsJSON []byte - PageOptionsJSON []byte - CaptchaOptionsJSON []byte - Description string - IsOn bool - Mode string - UseLocalFirewall bool - SynFloodJSON []byte - LogJSON []byte - MaxRequestBodySize int64 - DenyCountryHTML string - DenyProvinceHTML string + FirewallPolicyId int64 + Name string + GroupCodes []string + BlockOptionsJSON []byte + PageOptionsJSON []byte + CaptchaOptionsJSON []byte + JsCookieOptionsJSON []byte + Description string + IsOn bool + Mode string + UseLocalFirewall bool + SynFloodJSON []byte + LogJSON []byte + MaxRequestBodySize int64 + DenyCountryHTML string + DenyProvinceHTML string Must *actions.Must }) { @@ -136,7 +137,7 @@ func (this *UpdateAction) RunPost(params struct { Require("请输入策略名称") // 校验拦截选项JSON - var blockOptions = &firewallconfigs.HTTPFirewallBlockAction{} + var blockOptions = firewallconfigs.NewHTTPFirewallBlockAction() err := json.Unmarshal(params.BlockOptionsJSON, blockOptions) if err != nil { this.Fail("拦截动作参数校验失败:" + err.Error()) @@ -144,7 +145,7 @@ func (this *UpdateAction) RunPost(params struct { } // 校验显示页面选项JSON - var pageOptions = &firewallconfigs.HTTPFirewallPageAction{} + var pageOptions = firewallconfigs.NewHTTPFirewallPageAction() err = json.Unmarshal(params.PageOptionsJSON, pageOptions) if err != nil { this.Fail("校验显示页面动作配置失败:" + err.Error()) @@ -156,7 +157,7 @@ func (this *UpdateAction) RunPost(params struct { } // 校验验证码选项JSON - var captchaOptions = &firewallconfigs.HTTPFirewallCaptchaAction{} + var captchaOptions = firewallconfigs.NewHTTPFirewallCaptchaAction() err = json.Unmarshal(params.CaptchaOptionsJSON, captchaOptions) if err != nil { this.Fail("验证码动作参数校验失败:" + err.Error()) @@ -180,6 +181,16 @@ func (this *UpdateAction) RunPost(params struct { } } + // 校验JSCookie选项JSON + var jsCookieOptions = firewallconfigs.NewHTTPFirewallJavascriptCookieAction() + if len(params.JsCookieOptionsJSON) > 0 { + err = json.Unmarshal(params.JsCookieOptionsJSON, jsCookieOptions) + if err != nil { + this.Fail("JSCookie动作参数校验失败:" + err.Error()) + return + } + } + // 最大内容尺寸 if params.MaxRequestBodySize < 0 { params.MaxRequestBodySize = 0 @@ -194,6 +205,7 @@ func (this *UpdateAction) RunPost(params struct { BlockOptionsJSON: params.BlockOptionsJSON, PageOptionsJSON: params.PageOptionsJSON, CaptchaOptionsJSON: params.CaptchaOptionsJSON, + JsCookieOptionsJSON: params.JsCookieOptionsJSON, Mode: params.Mode, UseLocalFirewall: params.UseLocalFirewall, SynFloodJSON: params.SynFloodJSON, diff --git a/internal/web/actions/default/servers/server/settings/locations/waf/index.go b/internal/web/actions/default/servers/server/settings/locations/waf/index.go index d816e7ca..4c40de58 100644 --- a/internal/web/actions/default/servers/server/settings/locations/waf/index.go +++ b/internal/web/actions/default/servers/server/settings/locations/waf/index.go @@ -39,7 +39,7 @@ func (this *IndexAction) RunGet(params struct { } if firewallPolicy != nil { // captcha action - var captchaOptions = firewallconfigs.DefaultHTTPFirewallCaptchaAction() + var captchaOptions = firewallconfigs.NewHTTPFirewallCaptchaAction() if len(firewallPolicy.CaptchaOptionsJSON) > 0 { err = json.Unmarshal(firewallPolicy.CaptchaOptionsJSON, captchaOptions) if err != nil { diff --git a/internal/web/actions/default/servers/server/settings/waf/index.go b/internal/web/actions/default/servers/server/settings/waf/index.go index 0d710f2a..791285ed 100644 --- a/internal/web/actions/default/servers/server/settings/waf/index.go +++ b/internal/web/actions/default/servers/server/settings/waf/index.go @@ -52,7 +52,7 @@ func (this *IndexAction) RunGet(params struct { } if firewallPolicy != nil { // captcha action - var captchaOptions = firewallconfigs.DefaultHTTPFirewallCaptchaAction() + var captchaOptions = firewallconfigs.NewHTTPFirewallCaptchaAction() if len(firewallPolicy.CaptchaOptionsJSON) > 0 { err = json.Unmarshal(firewallPolicy.CaptchaOptionsJSON, captchaOptions) if err != nil { diff --git a/web/public/js/components/iplist/ip-list-table.js b/web/public/js/components/iplist/ip-list-table.js index 29a831e5..a1f361ee 100644 --- a/web/public/js/components/iplist/ip-list-table.js +++ b/web/public/js/components/iplist/ip-list-table.js @@ -175,8 +175,8 @@ Vue.component("ip-list-table", { - [服务:{{item.policy.server.name}}] - [服务:{{item.policy.server.name}}] + [网站:{{item.policy.server.name}}] + [网站:{{item.policy.server.name}}] [策略:{{item.policy.name}}] diff --git a/web/public/js/components/server/http-firewall-block-options-viewer.js b/web/public/js/components/server/http-firewall-block-options-viewer.js index b128da6a..37b69056 100644 --- a/web/public/js/components/server/http-firewall-block-options-viewer.js +++ b/web/public/js/components/server/http-firewall-block-options-viewer.js @@ -9,6 +9,7 @@ Vue.component("http-firewall-block-options-viewer", { 默认设置
状态码:{{options.statusCode}} / 提示内容:[{{options.body.length}}字符][无] / 超时时间:{{options.timeout}}秒 / 最大封禁时长:{{options.timeoutMax}}秒 + / 尝试全局封禁
` diff --git a/web/public/js/components/server/http-firewall-block-options.js b/web/public/js/components/server/http-firewall-block-options.js index 7d3b0538..e270b8e0 100644 --- a/web/public/js/components/server/http-firewall-block-options.js +++ b/web/public/js/components/server/http-firewall-block-options.js @@ -2,7 +2,7 @@ Vue.component("http-firewall-block-options", { props: ["v-block-options"], data: function () { return { - blockOptions: this.vBlockOptions, + options: this.vBlockOptions, statusCode: this.vBlockOptions.statusCode, timeout: this.vBlockOptions.timeout, timeoutMax: this.vBlockOptions.timeoutMax, @@ -13,25 +13,25 @@ Vue.component("http-firewall-block-options", { statusCode: function (v) { let statusCode = parseInt(v) if (isNaN(statusCode)) { - this.blockOptions.statusCode = 403 + this.options.statusCode = 403 } else { - this.blockOptions.statusCode = statusCode + this.options.statusCode = statusCode } }, timeout: function (v) { let timeout = parseInt(v) if (isNaN(timeout)) { - this.blockOptions.timeout = 0 + this.options.timeout = 0 } else { - this.blockOptions.timeout = timeout + this.options.timeout = timeout } }, timeoutMax: function (v) { let timeoutMax = parseInt(v) if (isNaN(timeoutMax)) { - this.blockOptions.timeoutMax = 0 + this.options.timeoutMax = 0 } else { - this.blockOptions.timeoutMax = timeoutMax + this.options.timeoutMax = timeoutMax } } }, @@ -41,9 +41,10 @@ Vue.component("http-firewall-block-options", { } }, template: `
- - 状态码:{{statusCode}} / 提示内容:[{{blockOptions.body.length}}字符][无] / 封禁时长:{{timeout}}秒 + + 状态码:{{statusCode}} / 提示内容:[{{options.body.length}}字符][无] / 封禁时长:{{timeout}}秒 / 最大封禁时长:{{timeoutMax}}秒 + / 尝试全局封禁 @@ -55,7 +56,7 @@ Vue.component("http-firewall-block-options", { @@ -78,6 +79,13 @@ Vue.component("http-firewall-block-options", {

如果最大封禁时长大于封禁时长({{timeout}}秒),那么表示每次封禁的时候,将会在这两个时长数字之间随机选取一个数字作为最终的封禁时长。

+ + + +
提示内容 - +
失败全局封禁 + +

选中后,表示允许系统尝试全局封禁某个IP,以提升封禁性能。

+
` diff --git a/web/public/js/components/server/http-firewall-captcha-options.js b/web/public/js/components/server/http-firewall-captcha-options.js index 7412889e..85e5c668 100644 --- a/web/public/js/components/server/http-firewall-captcha-options.js +++ b/web/public/js/components/server/http-firewall-captcha-options.js @@ -119,7 +119,7 @@ Vue.component("http-firewall-captcha-options", { summaryList.push("失败拦截" + this.options.failBlockTimeout + "秒") } if (this.options.failBlockScopeAll) { - summaryList.push("全局封禁") + summaryList.push("尝试全局封禁") } let that = this @@ -199,7 +199,7 @@ Vue.component("http-firewall-captcha-options", { 失败全局封禁 -

是否在失败时全局封禁,默认为只封禁对单个网站的访问。

+

选中后,表示允许系统尝试全局封禁某个IP,以提升封禁性能。

diff --git a/web/public/js/components/server/http-firewall-js-cookie-options-viewer.js b/web/public/js/components/server/http-firewall-js-cookie-options-viewer.js new file mode 100644 index 00000000..facef805 --- /dev/null +++ b/web/public/js/components/server/http-firewall-js-cookie-options-viewer.js @@ -0,0 +1,47 @@ +Vue.component("http-firewall-js-cookie-options-viewer", { + props: ["v-js-cookie-options"], + mounted: function () { + this.updateSummary() + }, + data: function () { + let options = this.vJsCookieOptions + if (options == null) { + options = { + life: 0, + maxFails: 0, + failBlockTimeout: 0, + failBlockScopeAll: false, + scope: "" + } + } + return { + options: options, + summary: "" + } + }, + methods: { + updateSummary: function () { + let summaryList = [] + if (this.options.life > 0) { + summaryList.push("有效时间" + this.options.life + "秒") + } + if (this.options.maxFails > 0) { + summaryList.push("最多失败" + this.options.maxFails + "次") + } + if (this.options.failBlockTimeout > 0) { + summaryList.push("失败拦截" + this.options.failBlockTimeout + "秒") + } + if (this.options.failBlockScopeAll) { + summaryList.push("尝试全局封禁") + } + + if (summaryList.length == 0) { + this.summary = "默认配置" + } else { + this.summary = summaryList.join(" / ") + } + } + }, + template: `
{{summary}}
+` +}) \ No newline at end of file diff --git a/web/public/js/components/server/http-firewall-js-cookie-options.js b/web/public/js/components/server/http-firewall-js-cookie-options.js new file mode 100644 index 00000000..88ae23a2 --- /dev/null +++ b/web/public/js/components/server/http-firewall-js-cookie-options.js @@ -0,0 +1,130 @@ +Vue.component("http-firewall-js-cookie-options", { + props: ["v-js-cookie-options"], + mounted: function () { + this.updateSummary() + }, + data: function () { + let options = this.vJsCookieOptions + if (options == null) { + options = { + life: 0, + maxFails: 0, + failBlockTimeout: 0, + failBlockScopeAll: false, + scope: "service" + } + } + + return { + options: options, + isEditing: false, + summary: "" + } + }, + watch: { + "options.life": function (v) { + let i = parseInt(v, 10) + if (isNaN(i)) { + i = 0 + } + this.options.life = i + this.updateSummary() + }, + "options.maxFails": function (v) { + let i = parseInt(v, 10) + if (isNaN(i)) { + i = 0 + } + this.options.maxFails = i + this.updateSummary() + }, + "options.failBlockTimeout": function (v) { + let i = parseInt(v, 10) + if (isNaN(i)) { + i = 0 + } + this.options.failBlockTimeout = i + this.updateSummary() + }, + "options.failBlockScopeAll": function (v) { + this.updateSummary() + } + }, + methods: { + edit: function () { + this.isEditing = !this.isEditing + }, + updateSummary: function () { + let summaryList = [] + if (this.options.life > 0) { + summaryList.push("有效时间" + this.options.life + "秒") + } + if (this.options.maxFails > 0) { + summaryList.push("最多失败" + this.options.maxFails + "次") + } + if (this.options.failBlockTimeout > 0) { + summaryList.push("失败拦截" + this.options.failBlockTimeout + "秒") + } + if (this.options.failBlockScopeAll) { + summaryList.push("尝试全局封禁") + } + + if (summaryList.length == 0) { + this.summary = "默认配置" + } else { + this.summary = summaryList.join(" / ") + } + }, + confirm: function () { + this.isEditing = false + } + }, + template: `
+ + {{summary}} +
+ + + + + + + + + + + + + + + + + + + +
有效时间 +
+ + +
+

验证通过后在这个时间内不再验证,默认3600秒。

+
最多失败次数 +
+ + +
+

建议填入一个不小于5的数字,以减少误判几率。允许用户失败尝试的最多次数,超过这个次数将被自动加入黑名单。如果为空或者为0,表示不限制。

+
失败拦截时间 +
+ + +
+

在达到最多失败次数(大于0)时,自动拦截的时长;如果为0表示不自动拦截。

+
失败全局封禁 + +

选中后,表示允许系统尝试全局封禁某个IP,以提升封禁性能。

+
+
+
+` +}) \ No newline at end of file diff --git a/web/views/@default/servers/components/waf/policy.html b/web/views/@default/servers/components/waf/policy.html index 39e01b06..c7084966 100644 --- a/web/views/@default/servers/components/waf/policy.html +++ b/web/views/@default/servers/components/waf/policy.html @@ -48,6 +48,12 @@ + + JSCookie动作配置 + + + + 使用系统防火墙 diff --git a/web/views/@default/servers/components/waf/update.html b/web/views/@default/servers/components/waf/update.html index efcedcab..666bb914 100644 --- a/web/views/@default/servers/components/waf/update.html +++ b/web/views/@default/servers/components/waf/update.html @@ -54,6 +54,12 @@ + + JSCookie动作配置 + + + +