1
0
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:
zhengkunwang 2024-03-06 18:16:08 +08:00 committed by GitHub
parent fe717d993b
commit 21f24f2e10
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 224 additions and 33 deletions

View File

@ -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"

View File

@ -167,3 +167,7 @@ CutWebsiteLogSuccess: "{{ .name }} 網站日誌切割成功,備份路徑 {{ .p
#toolbox #toolbox
ErrNotExistUser: "當前使用者不存在,請修改後重試!" ErrNotExistUser: "當前使用者不存在,請修改後重試!"
ErrBanAction: "設置失敗,當前 {{ .name }} 服務不可用,請檢查後重試!" ErrBanAction: "設置失敗,當前 {{ .name }} 服務不可用,請檢查後重試!"
#waf
ErrScope: "不支援修改此配置"
ErrStateChange: "狀態修改失敗"

View File

@ -166,3 +166,7 @@ CutWebsiteLogSuccess: "{{ .name }} 网站日志切割成功,备份路径 {{ .p
#toolbox #toolbox
ErrNotExistUser: "当前用户不存在,请修改后重试!" ErrNotExistUser: "当前用户不存在,请修改后重试!"
ErrBanAction: "设置失败,当前 {{ .name }} 服务不可用,请检查后重试!" ErrBanAction: "设置失败,当前 {{ .name }} 服务不可用,请检查后重试!"
#waf
ErrScope: "不支持修改此配置"
ErrStateChange: "状态修改失败"

View 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>

View File

@ -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',

View File

@ -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: '網站監控',

View File

@ -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: '网站监控',

View File

@ -117,7 +117,7 @@
"action": "deny", "action": "deny",
"code": 403, "code": 403,
"type": "fileExtCheck", "type": "fileExtCheck",
"extList": [ "rules": [
"php", "php",
"jsp", "jsp",
"asp", "asp",

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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()