mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-19 08:19:15 +08:00
feat(waf): 增加全局设置 (#4088)
This commit is contained in:
parent
fe717d993b
commit
21f24f2e10
@ -166,3 +166,7 @@ CutWebsiteLogSuccess: "{{ .name }} website log cut successfully, backup path {{
|
|||||||
#toolbox
|
#toolbox
|
||||||
ErrNotExistUser: "The current user does not exist. Please modify and retry!"
|
ErrNotExistUser: "The current user does not exist. Please modify and retry!"
|
||||||
ErrBanAction: "Setting failed, the current {{ .name }} service is unavailable, please check and try again!"
|
ErrBanAction: "Setting failed, the current {{ .name }} service is unavailable, please check and try again!"
|
||||||
|
|
||||||
|
#waf
|
||||||
|
ErrScope: "Modification of this configuration is not supported"
|
||||||
|
ErrStateChange: "State modification failed"
|
@ -167,3 +167,7 @@ CutWebsiteLogSuccess: "{{ .name }} 網站日誌切割成功,備份路徑 {{ .p
|
|||||||
#toolbox
|
#toolbox
|
||||||
ErrNotExistUser: "當前使用者不存在,請修改後重試!"
|
ErrNotExistUser: "當前使用者不存在,請修改後重試!"
|
||||||
ErrBanAction: "設置失敗,當前 {{ .name }} 服務不可用,請檢查後重試!"
|
ErrBanAction: "設置失敗,當前 {{ .name }} 服務不可用,請檢查後重試!"
|
||||||
|
|
||||||
|
#waf
|
||||||
|
ErrScope: "不支援修改此配置"
|
||||||
|
ErrStateChange: "狀態修改失敗"
|
||||||
|
@ -166,3 +166,7 @@ CutWebsiteLogSuccess: "{{ .name }} 网站日志切割成功,备份路径 {{ .p
|
|||||||
#toolbox
|
#toolbox
|
||||||
ErrNotExistUser: "当前用户不存在,请修改后重试!"
|
ErrNotExistUser: "当前用户不存在,请修改后重试!"
|
||||||
ErrBanAction: "设置失败,当前 {{ .name }} 服务不可用,请检查后重试!"
|
ErrBanAction: "设置失败,当前 {{ .name }} 服务不可用,请检查后重试!"
|
||||||
|
|
||||||
|
#waf
|
||||||
|
ErrScope: "不支持修改此配置"
|
||||||
|
ErrStateChange: "状态修改失败"
|
56
frontend/src/components/config-card/index.vue
Normal file
56
frontend/src/components/config-card/index.vue
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<template>
|
||||||
|
<el-card class="config-card">
|
||||||
|
<div class="config-header">
|
||||||
|
<span>{{ header }}</span>
|
||||||
|
<slot name="header-r" />
|
||||||
|
</div>
|
||||||
|
<el-text type="info">{{ description }}</el-text>
|
||||||
|
<div class="config-content">
|
||||||
|
<slot name="content-r" />
|
||||||
|
</div>
|
||||||
|
<div class="config-form">
|
||||||
|
<slot name="content-form" />
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
defineOptions({ name: 'ConfigCard' });
|
||||||
|
defineProps({
|
||||||
|
header: String,
|
||||||
|
description: String,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.config-card {
|
||||||
|
cursor: pointer;
|
||||||
|
margin: 10px;
|
||||||
|
.config-header {
|
||||||
|
margin-bottom: 18px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
span {
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-content {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-form {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.config-card {
|
||||||
|
border: var(--panel-border) !important;
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid var(--el-color-primary) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -2157,7 +2157,7 @@ const message = {
|
|||||||
request: 'request',
|
request: 'request',
|
||||||
count4xx: '4xx quantity',
|
count4xx: '4xx quantity',
|
||||||
count5xx: '5xx quantity',
|
count5xx: '5xx quantity',
|
||||||
todayStatus: 'Today status',
|
todayStatus: 'Today Status',
|
||||||
reqMap: 'Request map (30 days)',
|
reqMap: 'Request map (30 days)',
|
||||||
resource: 'source',
|
resource: 'source',
|
||||||
count: 'Quantity',
|
count: 'Quantity',
|
||||||
@ -2167,6 +2167,45 @@ const message = {
|
|||||||
interceptCount: 'Interception number',
|
interceptCount: 'Interception number',
|
||||||
requestTrends: 'Request Trends (7 days)',
|
requestTrends: 'Request Trends (7 days)',
|
||||||
interceptTrends: 'Intercept Trends (7 days)',
|
interceptTrends: 'Intercept Trends (7 days)',
|
||||||
|
whiteList: 'whitelist',
|
||||||
|
blackList: 'blacklist',
|
||||||
|
ipBlackListHelper: 'IPs in the blacklist cannot access the website',
|
||||||
|
ipWhiteListHelper: 'IPs in the whitelist are not restricted by any rules',
|
||||||
|
uaBlackListHelper: 'Requests carrying User-Agent in the blacklist will be intercepted',
|
||||||
|
uaWhiteListHelper: 'Requests carrying User-Agent in the whitelist are not restricted by any rules',
|
||||||
|
urlBlackListHelper: 'Requests for URLs in the blacklist will be intercepted',
|
||||||
|
urlWhiteListHelper: 'Requests for URLs in the whitelist are not restricted by any rules',
|
||||||
|
ccHelper:
|
||||||
|
'If any website has been requested more than {1} times in {0} seconds, this IP will be blocked for {2} seconds',
|
||||||
|
blockTime: 'Block time',
|
||||||
|
attackHelper:
|
||||||
|
'The cumulative interception exceeds {1} times within {0} seconds, block this IP for {2} seconds',
|
||||||
|
notFoundHelper:
|
||||||
|
'The cumulative request returned 404 more than {1} times within {0} seconds, block this IP for {2} seconds',
|
||||||
|
frequencyLimit: 'frequency limit',
|
||||||
|
regionLimit: 'region limit',
|
||||||
|
defaultRule: 'Default rule',
|
||||||
|
accessFrequencyLmit: 'Access frequency limit',
|
||||||
|
attackLimit: 'Attack frequency limit',
|
||||||
|
notFoundLimit: '404 frequency limit',
|
||||||
|
urlLimit: 'URL frequency limit',
|
||||||
|
urlLimitHelper: 'Set access frequency for a single URL',
|
||||||
|
sqliDefense: 'SQL injection defense',
|
||||||
|
sqliHelper: 'Identify SQL injection in requests and intercept',
|
||||||
|
xssHelper: 'Identify XSS in the request and intercept it',
|
||||||
|
xssDefense: 'XSS Defense',
|
||||||
|
uaDefense: 'Malicious User-Agent Rule',
|
||||||
|
uaHelper: 'Contains common malicious crawler rules',
|
||||||
|
argsDefense: 'Malicious parameter rules',
|
||||||
|
argsHelper: 'Prohibit malicious parameters in requests',
|
||||||
|
cookieDefense: 'Malicious Cookie Rule',
|
||||||
|
cookieHelper: 'Prohibit malicious cookies from being carried in requests',
|
||||||
|
headerDefense: 'Malicious Header Rule',
|
||||||
|
headerHelper: 'Prohibit requests from containing malicious headers',
|
||||||
|
httpRule: 'HTTP request method rules',
|
||||||
|
httpHelper: 'Restrict the request method type of the website',
|
||||||
|
geoRule: 'Regional access restrictions',
|
||||||
|
geoHelper: 'Restrict access to your website from certain regions',
|
||||||
},
|
},
|
||||||
monitor: {
|
monitor: {
|
||||||
name: 'Website Monitoring',
|
name: 'Website Monitoring',
|
||||||
|
@ -2025,6 +2025,42 @@ const message = {
|
|||||||
interceptCount: '攔截數',
|
interceptCount: '攔截數',
|
||||||
requestTrends: '請求趨勢(7天)',
|
requestTrends: '請求趨勢(7天)',
|
||||||
interceptTrends: '攔截趨勢(7天)',
|
interceptTrends: '攔截趨勢(7天)',
|
||||||
|
whiteList: '白名單',
|
||||||
|
blackList: '黑名單',
|
||||||
|
ipBlackListHelper: '黑名單中的 IP 無法存取網站',
|
||||||
|
ipWhiteListHelper: '白名單中的 IP 不受任何規則限制',
|
||||||
|
uaBlackListHelper: '攜帶黑名單中的 User-Agent 的請求將被攔截',
|
||||||
|
uaWhiteListHelper: '攜帶白名單中的 User-Agent 的請求不受任何規則限制',
|
||||||
|
urlBlackListHelper: '請求黑名單中的 URL 將被攔截',
|
||||||
|
urlWhiteListHelper: '請求白名單中的 URL 請求不受任何規則限制',
|
||||||
|
ccHelper: '{0} 秒內累積請求任意網站超過 {1} 次,封鎖此 IP {2} 秒',
|
||||||
|
blockTime: '封鎖時間',
|
||||||
|
attackHelper: '{0} 秒內累計攔截超過 {1} 次,封鎖此 IP {2} 秒',
|
||||||
|
notFoundHelper: '{0} 秒內累計請求回傳 404 超過 {1} 次,封鎖此 IP {2} 秒',
|
||||||
|
frequencyLimit: '頻率限制',
|
||||||
|
regionLimit: '地區限制',
|
||||||
|
defaultRule: '預設規則',
|
||||||
|
accessFrequencyLmit: '存取頻率限制',
|
||||||
|
attackLimit: '攻擊頻率限制',
|
||||||
|
notFoundLimit: '404 頻率限制',
|
||||||
|
urlLimit: 'URL 頻率限制',
|
||||||
|
urlLimitHelper: '為單一 URL 設定存取頻率',
|
||||||
|
sqliDefense: 'SQL 注入防禦',
|
||||||
|
sqliHelper: '辨識請求中的 SQL 注入並攔截',
|
||||||
|
xssHelper: '辨識請求中的 XSS 並攔截',
|
||||||
|
xssDefense: 'XSS 防禦',
|
||||||
|
uaDefense: '惡意 User-Agent 規則',
|
||||||
|
uaHelper: '包含常見的惡意爬蟲規則',
|
||||||
|
argsDefense: '惡意參數規則',
|
||||||
|
argsHelper: '在禁止請求中攜帶惡意參數',
|
||||||
|
cookieDefense: '惡意 Cookie 規則',
|
||||||
|
cookieHelper: '禁止請求中攜帶惡意 Cookie',
|
||||||
|
headerDefense: '惡意 Header 規則',
|
||||||
|
headerHelper: '禁止請求中攜帶惡意 Header',
|
||||||
|
httpRule: 'HTTP 請求方法規則',
|
||||||
|
httpHelper: '限制網站的請求方法類型',
|
||||||
|
geoRule: '地區存取限制',
|
||||||
|
geoHelper: '限制某些地區造訪你的網站',
|
||||||
},
|
},
|
||||||
monitor: {
|
monitor: {
|
||||||
name: '網站監控',
|
name: '網站監控',
|
||||||
|
@ -2026,6 +2026,42 @@ const message = {
|
|||||||
interceptCount: '拦截数',
|
interceptCount: '拦截数',
|
||||||
requestTrends: '请求趋势(7日)',
|
requestTrends: '请求趋势(7日)',
|
||||||
interceptTrends: '拦截趋势(7日)',
|
interceptTrends: '拦截趋势(7日)',
|
||||||
|
whiteList: '白名单',
|
||||||
|
blackList: '黑名单',
|
||||||
|
ipBlackListHelper: '黑名单中的 IP 无法访问网站',
|
||||||
|
ipWhiteListHelper: '白名单中的 IP 不受任何规则限制',
|
||||||
|
uaBlackListHelper: '携带黑名单中的 User-Agent 的请求将被拦截',
|
||||||
|
uaWhiteListHelper: '携带白名单中的 User-Agent 的请求不受任何规则限制',
|
||||||
|
urlBlackListHelper: '请求黑名单中的 URL 将被拦截',
|
||||||
|
urlWhiteListHelper: '请求白名单中的 URL 请求不受任何规则限制',
|
||||||
|
ccHelper: '{0} 秒内累计请求任意网站超过 {1} 次,封锁此 IP {2} 秒',
|
||||||
|
blockTime: '封禁时间',
|
||||||
|
attackHelper: '{0} 秒内累计拦截超过 {1} 次,封锁此 IP {2} 秒',
|
||||||
|
notFoundHelper: '{0} 秒内累计请求返回 404 超过 {1} 次,封锁此 IP {2} 秒',
|
||||||
|
frequencyLimit: '频率限制',
|
||||||
|
regionLimit: '地区限制',
|
||||||
|
defaultRule: '默认规则',
|
||||||
|
accessFrequencyLmit: '访问频率限制',
|
||||||
|
attackLimit: '攻击频率限制',
|
||||||
|
notFoundLimit: '404 频率限制',
|
||||||
|
urlLimit: 'URL 频率限制',
|
||||||
|
urlLimitHelper: '为单个 URL 设置访问频率',
|
||||||
|
sqliDefense: 'SQL 注入防御',
|
||||||
|
sqliHelper: '识别请求中的 SQL 注入并拦截',
|
||||||
|
xssHelper: '识别请求中的 XSS 并拦截',
|
||||||
|
xssDefense: 'XSS 防御',
|
||||||
|
uaDefense: '恶意 User-Agent 规则',
|
||||||
|
uaHelper: '包含常见的恶意爬虫规则',
|
||||||
|
argsDefense: '恶意参数规则',
|
||||||
|
argsHelper: '禁止请求中携带恶意参数',
|
||||||
|
cookieDefense: '恶意 Cookie 规则',
|
||||||
|
cookieHelper: '禁止请求中携带恶意 Cookie',
|
||||||
|
headerDefense: '恶意 Header 规则',
|
||||||
|
headerHelper: '禁止请求中携带恶意 Header',
|
||||||
|
httpRule: 'HTTP 请求方法规则',
|
||||||
|
httpHelper: '限制网站的请求方法类型',
|
||||||
|
geoRule: '地区访问限制',
|
||||||
|
geoHelper: '限制某些地区访问你的网站',
|
||||||
},
|
},
|
||||||
monitor: {
|
monitor: {
|
||||||
name: '网站监控',
|
name: '网站监控',
|
||||||
|
@ -117,7 +117,7 @@
|
|||||||
"action": "deny",
|
"action": "deny",
|
||||||
"code": 403,
|
"code": 403,
|
||||||
"type": "fileExtCheck",
|
"type": "fileExtCheck",
|
||||||
"extList": [
|
"rules": [
|
||||||
"php",
|
"php",
|
||||||
"jsp",
|
"jsp",
|
||||||
"asp",
|
"asp",
|
||||||
|
@ -531,7 +531,7 @@ function _M.post_check()
|
|||||||
local match = ngx_re_match(m[0], 'Content-Disposition: form-data; (.+)filename="(.+)\\.(.*)"', 'ijo')
|
local match = ngx_re_match(m[0], 'Content-Disposition: form-data; (.+)filename="(.+)\\.(.*)"', 'ijo')
|
||||||
if match then
|
if match then
|
||||||
local extension = match[3]
|
local extension = match[3]
|
||||||
for _, ext in ipairs(rule.extList) do
|
for _, ext in ipairs(rule.rules) do
|
||||||
if extension == ext then
|
if extension == ext then
|
||||||
exec_action(rule)
|
exec_action(rule)
|
||||||
end
|
end
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
local geoip = require "geoip"
|
||||||
local sub_str = string.sub
|
local sub_str = string.sub
|
||||||
local pairs = pairs
|
local pairs = pairs
|
||||||
local insert_table = table.insert
|
local insert_table = table.insert
|
||||||
@ -6,6 +7,7 @@ local ipairs = ipairs
|
|||||||
local type = type
|
local type = type
|
||||||
local find_str = string.find
|
local find_str = string.find
|
||||||
local gmatch_str = string.gmatch
|
local gmatch_str = string.gmatch
|
||||||
|
local cjson = require "cjson"
|
||||||
|
|
||||||
local _M = {}
|
local _M = {}
|
||||||
|
|
||||||
@ -114,6 +116,32 @@ function _M.get_real_ip()
|
|||||||
return "unknown"
|
return "unknown"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function _M.get_geo_ip(ip)
|
||||||
|
if _M.is_intranet_address(ip) then
|
||||||
|
return {
|
||||||
|
country = { ["zh"] = "内网", ["en"] = "intranet" },
|
||||||
|
province = { ["zh"] = "内网", ["en"] = "intranet" },
|
||||||
|
city = { ["zh"] = "内网", ["en"] = "intranet" },
|
||||||
|
longitude = 0,
|
||||||
|
latitude = 0,
|
||||||
|
iso = "local"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
geoip.init()
|
||||||
|
local geo_res = geoip.lookup(ip)
|
||||||
|
local msg = "访问 IP " .. ip
|
||||||
|
if geo_res.country then
|
||||||
|
msg = msg .. " 国家 " .. cjson.encode(geo_res.country)
|
||||||
|
end
|
||||||
|
if geo_res.province then
|
||||||
|
msg = msg .. " 省份 " .. cjson.encode(geo_res.province)
|
||||||
|
end
|
||||||
|
ngx.log(ngx.ERR, msg)
|
||||||
|
return geo_res
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function _M.get_header(headerKey)
|
function _M.get_header(headerKey)
|
||||||
return ngx.req.get_headers(20000)[headerKey]
|
return ngx.req.get_headers(20000)[headerKey]
|
||||||
end
|
end
|
||||||
|
@ -215,6 +215,16 @@ if config.is_waf_on() then
|
|||||||
count_not_found()
|
count_not_found()
|
||||||
local is_attack = ngx.ctx.is_attack
|
local is_attack = ngx.ctx.is_attack
|
||||||
|
|
||||||
|
if not ngx.ctx.ip then
|
||||||
|
ngx.ctx.ip = utils.get_real_ip()
|
||||||
|
ngx.ctx.geoip = utils.get_geo_ip(ngx.ctx.ip)
|
||||||
|
local ua = utils.get_header("user-agent")
|
||||||
|
if not ua then
|
||||||
|
ua = ""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
local wafdb = utils.get_wafdb(config.waf_db_path)
|
local wafdb = utils.get_wafdb(config.waf_db_path)
|
||||||
if wafdb ~= nil then
|
if wafdb ~= nil then
|
||||||
count_req_status(wafdb,is_attack)
|
count_req_status(wafdb,is_attack)
|
||||||
|
@ -42,20 +42,7 @@ local function get_website_key()
|
|||||||
return s_name
|
return s_name
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_geo_ip(ip)
|
|
||||||
if utils.is_intranet_address(ip) then
|
|
||||||
return {
|
|
||||||
country = { ["zh"] = "内网", ["en"] = "intranet" },
|
|
||||||
province = { ["zh"] = "内网", ["en"] = "intranet" },
|
|
||||||
city = { ["zh"] = "内网", ["en"] = "intranet" },
|
|
||||||
longitude = 0,
|
|
||||||
latitude = 0,
|
|
||||||
iso = "local"
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return geoip.lookup(ip)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function init()
|
local function init()
|
||||||
local ip = utils.get_real_ip()
|
local ip = utils.get_real_ip()
|
||||||
@ -65,19 +52,8 @@ local function init()
|
|||||||
ua = ""
|
ua = ""
|
||||||
end
|
end
|
||||||
|
|
||||||
geoip.init()
|
|
||||||
|
|
||||||
ngx.ctx.ua = ua
|
ngx.ctx.ua = ua
|
||||||
ngx.ctx.geoip = get_geo_ip(ip)
|
ngx.ctx.geoip = utils.get_geo_ip(ip)
|
||||||
|
|
||||||
local msg = "访问 IP " .. ip
|
|
||||||
if ngx.ctx.geoip.country then
|
|
||||||
msg = msg .. " 国家 " .. cjson.encode(ngx.ctx.geoip.country)
|
|
||||||
end
|
|
||||||
if ngx.ctx.geoip.province then
|
|
||||||
msg = msg .. " 省份 " .. cjson.encode(ngx.ctx.geoip.province)
|
|
||||||
end
|
|
||||||
ngx.log(ngx.ERR, msg)
|
|
||||||
|
|
||||||
ngx.ctx.website_key = get_website_key()
|
ngx.ctx.website_key = get_website_key()
|
||||||
ngx.ctx.method = ngx.req.get_method()
|
ngx.ctx.method = ngx.req.get_method()
|
||||||
@ -144,8 +120,6 @@ local function waf_api()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
ngx.log(ngx.ERR,"access waf")
|
|
||||||
|
|
||||||
if config.is_waf_on() then
|
if config.is_waf_on() then
|
||||||
init()
|
init()
|
||||||
waf_api()
|
waf_api()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user