普通视图

发现新文章,点击刷新页面。
昨天以前首页

规则制定者、遵守者和修改者

2025年4月24日 11:01

在我的视角里,就算是携宠旅行,在公共场合(例如长途大巴内、民宿餐厅等),应该将狗牵绳并随时照看好宠物,避免给他人添麻烦,就比如吠叫、奔跑等等。

当然,这个内心的规则并不适合所有人,所以规则在这个时候就等于不存在。如果大部分的人都认为「只要我掏了钱就应该享受服务」,那么让宠物在公共场合自由活动也是原本旅游契约里默认的条款——即携宠旅行,就是让人和狗都要感到快乐。

于是,我们就在这样的闹腾中度过了15个小时的车程。几近崩溃的同时又开始自查和怀疑自己——这个所谓的规则,我们明知道是自己内心的标准,那用来规范他人显然不合理。那是否意味着,其实大部分人采用的平均标准,就是那些在公共场合为了自己狗儿子开心而放任撒欢,且认为这就是「给了钱就应该享受的服务」?这个空间的规则就被调整到了大家都必须要被迫拉至一些傻逼主人以及其傻逼狗的道德、认知下限。

显然,这是公共规则的常态:当超过一半的人对某一个规则进行破坏时,原本的规则将会被拉入群体里的道德和认知水平下限,以至于另一部分人也开始不遵守规则。

同样,给狗牵绳或许也并不是一个法律规则,所以这个规则很有可能也仅仅是我个人标准,但不牵绳的狗打扰了别人,这件事与公共场合的规则是违背的。


我所住的小区有一个中央广场,广场的周围是供人休息的桌椅,再由花坛包围这个中央广场。而这些桌椅会变成小区里甚至是外来小区人员的「娱乐场所」,从早到晚都会有人在此打牌赌博。所以久而久之,原本需要绕行至此的路径,被越来越多人从花坛里走出了一条属于他们的捷径。

小区物管为了整治这个现象,先后试过安装标语牌、栅栏、种植更难移动的灌木,但显然这个花坛的规则已经完全被「娱乐场所」的人们所修改。以至于原本那些绕行的人,也选择了这条捷径。

我要是物管,就把所有人都拖下水,比如在这个走出来的新路上定期放上狗粪的阴招,或是安装喷水装置定时开启的阳谋。但显然,一旦这里形成的既定规则被破坏时,这些人反而会觉得「我们都这样做,为什么你就要特立独行地行事呢?」

于是,这个时候就出现了规则制定者和遵守者两种人。规则的制定或许并不一定是以个体的方式进行成文制定,也有可能是当群体内的半数都采用某种规则,或是乌合之众放弃独立思考以最低智商水平思考形成规则后所形成的;这时,规则的遵守者对规则的持续存在就起到了更为重要的作用,正所谓「走的人多了,便有了路」一样,遵守者一般而言有两种逻辑:

  • 大家都这样遵守,我也应该遵守。这一类人的社会屈从度更高,几乎不会重新思考这个规则存在的合理性,他们更多是为了合群而选择遵守;
  • 当我的利益因为规则受到损害时,我也通过规则去损害他人利益以补全我的既得利益。比如,有人停在自己的私家车位上,在沟通无果的情况下,去霸占他人车位,希望物管出面进行调解,否则无人为自己的损失买单;

我不算是一个很好的规则遵守者,在学校大部分闯的祸都是我利用了规则的漏洞,所以学校也无法实际「降罪」。也是从那个时候,我开始渐渐意识到我对规则暧昧不清的界限——

若是我认同的团体、组织、乃至国家的规则,我会默认选择接受,且不希望自己成为破坏规则的那个人。比如每次在日本休假时,我的手机完全保持静音状态。

但若是我不认同的团队、组织、乃至国家的规则,我会默认选择履行自己内心的道德标准。比如在不提供桌边服务的餐厅,我会在吃完餐后自行收拾桌面和餐具至指定位置,但显然这种行为在高速公路的服务区会被大部分认为吃完就应该留在桌面让别人收拾的人当作「神经」。

当人们在选择自我约束、不认同规则的时候,就容易发生割裂的问题——我都已经遵守我认为的规则了,那就不希望你用你的规则来破坏和入侵我的空间。比如,我们在长途大巴全程佩戴牵引绳,也保证自己的狗随时在我们身边,也因为是柴犬的关系他们几乎没有吠叫,但如果他们真的发出了叫声,我们也会觉得「过意不去」而立即制止和管理。

但这仅仅是我们在遵守的规则,所以当其他不牵绳的狗来我们身边捣乱,引起骚动时,他们的主人不动于衷,我为此发过脾气,也骂得不算好听,但就是这样绝大部分的人仍然觉得规则就是其中一些傻逼的下限。

所以这件事就成了内耗的卡点。


修改规则是存在极大风险的,比如你可能会和一个群体处于对立面。比如我高中的时候,觉得新闻联播之前大家「自觉」站起来读背书本这件事很傻逼,我便向班主任要求这段时间我自己去学校的小花园独处。班主任用的词也是大家最常听到的「别人都这样,为什么你非要搞特殊?」我并不认同规则,所以也质疑大家这样乱哄哄地读书是为了学习还是为了表演。为此,我争取到了所谓的「特权」,也是因为这个「特权」,我遭到了一部分同学的排挤。

很显然,我无法修改所有人面对的规则,但也有越来越多的人因为我的选择而开始拒绝拿着书本大声背读的习惯。直到教室里原本的规则也被平衡到了——要大声背读的学生去走廊,留在教室则保持安静学习。而我依旧是那个在学校小树林跟朋友吃绝味鸭脖的人……

这个时候,就必须要点名一种「规则假意反抗者」——即虽然不认同规则,但又无法做出改变规则、无法承担为自己争取规则的特例而招人厌恶的代价,最终不得不一边遵守规则,一边咒骂规则的制定者和其他遵守者都是「傻逼」。

为什么要把这类人单拎出来?是因为如果群体里大部分的人都以这种方式遵守规则,那么这个规则更难被破坏,因为他们更容易被集体驯化。即如果新的规则与原始规则相悖、甚至不同时,他们会为了反对原始规则而选择顺应新的规则——但殊不知新的规则就是集体驯化的一环。

我理解有些人正处于「看清规则但无法违抗」的阶段,但那些嘴上骂规则、心里又深信规则不可撼动的人,是最可怕的。


回到「内耗」这件事,既然我无法接受规则,同时又因为遵守自己的规则被他人不断入侵,为什么我不反抗?之所以这件事产生了自我怀疑,是因为中间还卡了一个要素,即我们跟这场活动的组织者还算关系不错,如果我们在活动当中与其他人发生了冲突,或许会给组织者「添麻烦」。

显然这也是把我自己困住的规则,那就只能接受这种规则带来的代价——比如我必须得全程带着耳机听歌,在每个服务区下去遛狗的时候,我都要求自己做到看管好自家的狗并及时处理粪便等。

因为我对其他狗,特别是狗主人及其傻逼的狗表现得非常冷漠,所以他们也自然而然会远离我,这是我需要承担的不合群的代价——这或许也是「规则」。

总结一下,其实关于规则的思考来源于福柯的《规训与惩罚》的思考。与其直接呈现书本上的哲学语句,我个人觉得它在进入到社会现实才显得有趣。

  • 现代形式的权力不必然在本质上是压抑性的,而是主体生产性的;
  • 勒庞认为的乌合之众是否也存在「主体性」?这就意味着乌合之众的内部是否存在产生性的「规则」;
  • 从现实来看,当群体内部超过一半的人遵守某种规则,即规则「产生」;但当多数人开始破坏规则,规则则会下沉,即乌合之众的「主体性」也受到破坏;
  • 而规则的假意反叛者,则符合规训机器里的内化者身份,甚至在特定时候他们是「惩罚」的执行者(例如文革时期为了保命而拿上红本本讨伐他人的红卫兵);

Nginx 的 WAF 规则 LuaJIT 严重版本

2023年12月26日 00:00

前段时间杜老师发表了一篇《自建 CDN 服务器思路》其中介绍南墙 Web 应用防火墙,有些小伙伴们对其名字很感兴趣,而杜老师注意到了它的防护规则,感觉非常实用,顺手整理了下,分享给需要的小伙伴们。此篇为严重风险的防护规则!

fastjson漏洞拦截

过滤阶段:请求阶段

规则描述:拦截fastjson漏洞漏洞攻击

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
local jsonFilter = waf.jsonFilter

local function rMatch(v)
if v == "@type" then
return true, v
end
return false
end

local form = waf.form
if form then
local raw = form["RAW"]
local m = jsonFilter(raw, rMatch, false)
if m then
return m, raw, true
end
end

return false

json格式校验

过滤阶段:请求阶段

规则描述:高级攻击者会构造一些异常json绕过WAF检测,该规则对json格式进行安全校验,可以拦截异常json请求。

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
local form = waf.form
local rct = waf.reqContentType
local rgx = waf.rgxMatch

if rct and waf.contains(waf.toLower(rct), "application/json") and form then
local raw = form["RAW"]
if raw then
if rgx(raw, "^\\s*$", "jos") then
return false
end
local err = waf.checkJson(raw)
if err then
return true, err .. ":" .. raw, true
end
end
end

return false

XSS跨站脚本攻击

过滤阶段:请求阶段

规则描述:攻击者通常会在有漏洞的程序中插入 JavaScript、VBScript、 ActiveX或Flash以欺骗用户。一旦得手,他们可以盗取用户帐户,修改用户设置,盗取/污染cookie,做虚假广告等。

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
local kvFilter = waf.kvFilter
local checkXSS = waf.checkXSS


local function sMatch(v)
if v then
local m = checkXSS(v)
if m then
return m, v
end
end
return false
end

local form = waf.form
if form then
local m, d = kvFilter(form["FORM"], sMatch)
if m then
return m, d, true
end
end

local queryString = waf.queryString
if queryString then
local m, d = kvFilter(queryString, sMatch)
if m then
return m, d, true
end
end

local cookies = waf.cookies
if cookies then
local m, d = kvFilter(cookies, sMatch)
if m then
return m, d, true
end
end

local m, d = sMatch(waf.userAgent)
if m then
return m, d, true
end

local m, d = sMatch(waf.referer)
if m then
return m, d, true
end

return false

java安全规则集

过滤阶段:请求阶段

规则描述:检测spring、struts、java序列化等相关安全漏洞

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
local kvFilter = waf.kvFilter
local rgx = waf.rgxMatch
local urlDecode = waf.urlDecode
local requestLine = waf.requestLine
local check = waf.plugins.javaClassDetection.check

local function sMatch(v)
local m = rgx(v, "(?:\\$\\{)+(?:j(?:n|\\$\\{)|\\$\\{(?:\\w*:)+)", "joi")
if m then
return m, "Potential Log4j / Log4shell Attack: " .. v
end
m = rgx(v, "\\xac\\xed\\x00\\x05|rO0ABQ|KztAAU|Cs7QAF", "jo")
if m then
return m, "Magic bytes Detected, probable java serialization Attack: " .. v
end
m = rgx(v, "classLoader\\s*\\.\\s*resources\\s*\\.\\s*context\\s*\\.\\s*parent\\s*\\.\\s*pipeline|springframework\\s*\\.\\s*context\\s*\\.\\s*support\\s*\\.\\s*FileSystemXmlApplicationContext", "jos")
if m then
return m, "Spring Framework RCE(CVE-2022-22965): " .. v
end
m = check(v)
if m then
return m, "Potential dangerous java class: " .. v
end
return false
end

local form = waf.form
if form then
local m, d = kvFilter(form["FORM"], sMatch)
if m then
return m, d, true
end
local raw = form["RAW"]
m = rgx(raw, "\\xac\\xed\\x00\\x05|rO0ABQ|KztAAU|Cs7QAF", "jo")
if m then
return m, raw, true
end
m = check(raw)
if m then
return m, raw, true
end
end

local queryString = waf.queryString
if queryString then
local m, d = kvFilter(queryString, sMatch)
if m then
return m, d, true
end
end

local cookies = waf.cookies
if cookies then
local m, d = kvFilter(cookies, sMatch)
if m then
return m, d, true
end
end

local m, d = kvFilter(waf.reqHeaders, sMatch)
if m then
return m, d, true
end

local m = rgx(urlDecode(requestLine), "(?:\\$\\{)+(?:j(?:n|\\$\\{)|\\$\\{(?:\\w*:)+)", "joi")
if m then
return m, requestLine, true
end

return false

Shellshock漏洞

过滤阶段:请求阶段

规则描述:检测对“Shellshock”(CVE-2014-6271和CVE-2014-7169) GNU Bash RCE漏洞的攻击。

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
local kvFilter = waf.kvFilter
local rgx = waf.rgxMatch
local requestLine = waf.requestLine
local urlDecode = waf.urlDecode

local function rMatch(v)
local m = rgx(urlDecode(v), "\\(\\s*\\)\\s+{", "jos")
if m then
return m, v
end
return false
end

local m, d = kvFilter(waf.reqHeaders, rMatch)
if m then
return m, d, true
end

local m, d = rMatch(requestLine)
if m then
return m, d, true
end

return false

远程文件包含 (RFI)

过滤阶段:请求阶段

规则描述:该规则寻找常见类型的远程文件包含(RFI)攻击方法。 #-PHP“include()”函数 #-JSP <jsp:include page= 或 <c:import url= #-RFI主机与本地主机不匹配

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
local kvFilter = waf.kvFilter
local rgx = waf.rgxMatch
local host = waf.host
local counter = waf.strCounter
local str_find = string.find
local str_sub = string.sub

local function rMatch(v)
local m = rgx(v, "^(?:url:)?file|ftps?|https?)://(?:[^@]+@)?([^/]+", "joi")
if m then
local i, j = str_find(v, host, 1, true)
if i then
if counter(str_sub(v, 1, j), "/") == 2 then
return false
end
end
end
return m, v
end

local form = waf.form
if form then
local m, d = kvFilter(form["FORM"], rMatch)
if m then
return m, d, true
end
end

local queryString = waf.queryString
if queryString then
local m, d = kvFilter(queryString, rMatch)
if m then
return m, d, true
end
end

return false

json 命令注入检测

过滤阶段:请求阶段

规则描述:解析请求body中的json内容,并检测命令注入攻击。采用RCE语义检测引擎可以检查各种变形,如:cat$IFS/etc/os-release或c$()at /e??/p???等

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
local checkRCE = waf.checkRCE
local jsonFilter = waf.jsonFilter

local function rMatch(v)
local m = checkRCE(v)
if m then
return m, v
end
return false
end

local form = waf.form
if form then
local m, d = jsonFilter(form["RAW"], rMatch, false, true)
if m then
return m, d, true
end
end

return false

常规命令注入检测

过滤阶段:请求阶段

规则描述:检测url、cookie、form中的shell命令注入攻击,采用RCE语义检测引擎可以检查各种变形,如:cat$IFS/etc/os-release或c$()at /e??/p???等

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
local checkRCE = waf.checkRCE
local kvFilter = waf.kvFilter

local function rMatch(v)
local m = checkRCE(v)
if m then
return m, v
end
return false
end

local form = waf.form
if form then
local m, d = kvFilter(form["FORM"], rMatch, true)
if m then
return m, d, true
end
end

local queryString = waf.queryString
if queryString then
local m, d = kvFilter(queryString, rMatch, true)
if m then
return m, d, true
end
end

local cookies = waf.cookies
if cookies then
local m, d = kvFilter(cookies, rMatch, true)
if m then
return m, d, true
end
end
return false

json sql注入检测

过滤阶段:请求阶段

规则描述:解析请求body中的json内容,并检测sql注入攻击。采用SQL语义检测引擎,可以降低误报。

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
local checkSQLI = waf.checkSQLI
local jsonFilter = waf.jsonFilter

local function rMatch(v)
local m = checkSQLI(v)
if m then
return m, v
end
return false
end

local form = waf.form
if form then
local m, d = jsonFilter(form["RAW"], rMatch, false)
if m then
return m, d, true
end
end

return false

常规sql注入检测

过滤阶段:请求阶段

规则描述:检测url、cookie、form中的sql注入攻击。采用SQL语义检测引擎,可以降低误报。

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
local checkSQLI = waf.checkSQLI
local kvFilter = waf.kvFilter

local function sMatch(v)
local m = checkSQLI(v)
if m then
return m, v
end
return false
end

local form = waf.form
if form then
local m, d = kvFilter(form["FORM"], sMatch)
if m then
return m, d, true
end
end

local queryString = waf.queryString
if queryString then
local m, d = kvFilter(queryString, sMatch)
if m then
return m, d, true
end
end

local cookies = waf.cookies
if cookies then
local m, d = kvFilter(cookies, sMatch)
if m then
return m, d, true
end
end

local m, d = kvFilter(waf.reqHeaders, sMatch)
if m then
return m, d, true
end

return false

Invalid protocol

过滤阶段:请求阶段

规则描述:请求header数过多,超过64个。

规则内容:

1
2
3
4
if waf.hErr and waf.hErr=="truncated" then
return true,waf.hErr,true
end
return false

XXE漏洞

过滤阶段:请求阶段

规则描述:XML外部实体注入(XML External Entity)漏洞简称XXE漏洞。当允许引用外部实体时,通过构造恶意内容,可导致读取任意文件、执行系统命令、探测内网端口、攻击内网网站等危害。

规则内容:

1
2
3
4
5
6
7
if waf.form and waf.form["RAW"] then
local m = waf.rgxMatch(waf.form["RAW"], "<!(?:DOCTYPE|ENTITY)[^>]+?\\bSYSTEM\\b", "jos")
if m then
return m, waf.form["RAW"], true
end
end
return false

ImageMagick漏洞

过滤阶段:请求阶段

规则描述:ImageMagick是一个功能强大的开源图形处理软件,该漏洞可以执行任意命令和读写文件

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
local rgx = waf.rgxMatch
local function imgContentMatch(v)
local m = rgx(v, "\\bpush\\s+graphic-context\\b|\\<\\s*image\\b", "joi")
if m then
return m, v
end
return false
end
if waf.form then
local m, d = waf.knFilter(waf.form["FILES"], imgContentMatch, 0)
return m, d, true
end
return false

header头漏洞

过滤阶段:请求阶段

规则描述:httpoxy漏洞可被用来针对CGI环境设置非法代理,从而窃取服务器敏感数据。在CVE-2017-7269(IIS 6.0 WebDAV远程代码执行漏洞)中if和lock_token http头会造成溢出攻击。

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
if waf.reqHeaders.proxy ~= nil then
return true, "Proxy: " .. waf.reqHeaders.proxy, true
end

if waf.reqHeaders.lock_token ~= nil then
return true, "Lock-Token: " .. waf.reqHeaders.lock_token, true
end

if waf.reqHeaders["If"] ~= nil then
return true, "If: " .. waf.reqHeaders["If"], true
end

return false

LDAP Injection

过滤阶段:请求阶段

规则描述:拦截LDAP注入攻击

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
local kvFilter = waf.kvFilter
local rgx = waf.rgxMatch
local htmlEntityDecode = waf.htmlEntityDecode

local function rMatch(v)
local m = rgx(htmlEntityDecode(v), "^[^:\\(\\)\\&\\|\\!\\<\\>\\~]*\\)\\s*(?:\\((?:[^,\\(\\)\\=\\&\\|\\!\\<\\>\\~]+[><~]?=|\\s*[&!|]\\s*(?:\\)|\\()?\\s*)|\\)\\s*\\(\\s*[\\&\\|\\!]\\s*|[&!|]\\s*\\([^\\(\\)\\=\\&\\|\\!\\<\\>\\~]+[><~]?=[^:\\(\\)\\&\\|\\!\\<\\>\\~]*)", "jos")
if m then
return m, v
end
return false
end

local form = waf.form
if form then
local m, d = kvFilter(form["FORM"], rMatch)
if m then
return m, d, true
end
end

local queryString = waf.queryString
if queryString then
local m, d = kvFilter(queryString, rMatch)
if m then
return m, d, true
end
end

local cookies = waf.cookies
if cookies then
local m, d = kvFilter(cookies, rMatch)
if m then
return m, d, true
end
end
return false

HTTP Splitting

过滤阶段:请求阶段

规则描述:此规则检测请求文件名中的\n或\r。

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
local rgx = waf.rgxMatch
local function fMatch(v)
local m = rgx(v, "[\\n\\r]", "jo")
if m then
return m, v
end
return false
end
local m, d = fMatch(waf.uri)
if m then
return m, d, true
end
return false

HTTP Header Injection

过滤阶段:请求阶段

规则描述:HTTP头注入查找回车符(CR)%0d和换行符(LF)%0a字符,单独或与header字段名称组合使用。如果数据在响应头中返回并由客户端解释,这些字符可能会导致问题。

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
local rgx = waf.rgxMatch
local htmlEntityDecode = waf.htmlEntityDecode
local concat = table.concat

local function hMatch(v)
local m = rgx(htmlEntityDecode(v), "[\\n\\r]", "jo")
if m then
return m, v
end
return false
end

local function vMatch(v)
local m = rgx(htmlEntityDecode(v), "[\\n\\r]+(?:\\s|location|refresh|(?:set-)?cookie|(?:x-)?(?:forwarded-(?:for|host|server)|host|via|remote-ip|remote-addr|originating-IP))\\s*:", "josi")
if m then
return m, v
end
return false
end

local m, d = waf.kvFilter(waf.reqHeaders, hMatch)
if m then
return m, d, true
end

local queryString = waf.queryString
if queryString then
for k, v in pairs(waf.queryString) do
m, d = hMatch(k)
if m then
return m, d, true
end
if type(v)=="table" then
v = concat(v,",")
end
m, d = vMatch(v)
if m then
return m, d, true
end
end
end

local form = waf.form
if form then
for k, _ in pairs(form["FORM"]) do
m, d = hMatch(k)
if m then
return m, d, true
end
end
end

return false

boundary异常拦截

过滤阶段:请求阶段

规则描述:拦截请求content type头中multipart/form-data的异常boundary,如php在上传解析boundary时没有符合rfc规范,对逗号产生了错误解析。

规则内容:

1
2
3
4
5
6
7
8
9
10
11
local ct = waf.reqContentType

if ct then
if type(ct) ~= "string" then
return true, "Malform Content-Type", true
elseif waf.contains(ct, "boundary") and (waf.strCounter(ct, "boundary") > 1 or not waf.rgxMatch(ct, "boundary=[\\w\\-]+$", "jo")) then
return true, ct, true
end
end

return false

asp畸形编码过滤

过滤阶段:请求阶段

规则描述:asp中unicode畸形编码会造成waf绕过危害

规则内容:

1
2
3
4
if waf.rgxMatch(waf.reqUri,"%u00(?:aa|ba|d0|de|e2|f0|fe)","i") then
return true,waf.reqUri,true
end
return false

HTTP Response Splitting

过滤阶段:请求阶段

规则描述:该规则查找回车符(CR)%0d和换行符(LF)%0a字符。如果在响应报头中返回数据,这些字符可能会导致问题,并且可能会被中间代理服务器解释并被视为两个单独的响应。

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
local kvFilter = waf.kvFilter
local rgx = waf.rgxMatch
local htmlEntityDecode = waf.htmlEntityDecode

local function rMatch(v)
local m = rgx(v, "[\\r\\n]\\W*?(?:content-(?:type|length)|set-cookie|location):\\s*\\w", "josi")
if m then
return m, v
end
return false
end

local function hMatch(v)
local m = rgx(htmlEntityDecode(v), "(?:\\bhttp/\\d|<(?:html|meta)\\b)", "josi")
if m then
return m, v
end
return false
end

local form = waf.form
if form then
local m, d = kvFilter(form["FORM"], rMatch)
if m then
return m, d, true
end
m, d = kvFilter(form["FORM"], hMatch)
if m then
return m, d, true
end
end

local queryString = waf.queryString
if queryString then
local m, d = kvFilter(queryString, rMatch)
if m then
return m, d, true
end
m, d = kvFilter(queryString, hMatch)
if m then
return m, d, true
end
end

local cookies = waf.cookies
if cookies then
local m, d = kvFilter(cookies, rMatch)
if m then
return m, d, true
end
m, d = kvFilter(cookies, hMatch)
if m then
return m, d, true
end
end
return false

HTTP Request Smuggling

过滤阶段:请求阶段

规则描述:此规则查找与单词HTTP/\d或CR/LF字符组合的HTTP/WEBDAV方法名。这将指向试图将第二个请求注入到请求中,从而绕过对主请求执行的测试,如CVE-2019-20372(Nginx<1.17.7 请求走私漏洞)。

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
local kvFilter = waf.kvFilter
local rgx = waf.rgxMatch
local htmlEntityDecode = waf.htmlEntityDecode

local function rMatch(v)
local m = rgx(htmlEntityDecode(v), "(?:get|post|head|options|connect|put|delete|trace|track|patch|propfind|propatch|mkcol|copy|move|lock|unlock)\\s+[^\\s]+\\s+http/\\d", "josi")
if m then
return m, v
end
return false
end

local form = waf.form
if form then
local m, d = kvFilter(form["FORM"], rMatch)
if m then
return m, d, true
end
m, d = rMatch(form["RAW"])
if m then
return m, d, true
end
end

local queryString = waf.queryString
if queryString then
local m, d = kvFilter(queryString, rMatch)
if m then
return m, d, true
end
end

local cookies = waf.cookies
if cookies then
local m, d = kvFilter(cookies, rMatch)
if m then
return m, d, true
end
end
return false

上传文件内容过滤

过滤阶段:请求阶段

规则描述:过滤上传的文件内容,拦截webshell上传

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
local rgx = waf.rgxMatch
local function fileContentMatch(v)
local m = rgx(v, "<\\?.+?\\$(?:GLOBALS|_(?:GET|POST|COOKIE|REQUEST|SERVER|FILES|SESSION|ENV))|<\\?php|<jsp:|<%(?i:!|\\s*@|.*?\\brequest\\s*(?:\\.|\\())", "jos")
if m then
return m, v
end
return false
end
if waf.form then
local m, d = waf.knFilter(waf.form["FILES"], fileContentMatch, 0)
return m, d, true
end
return false

上传文件名过滤

过滤阶段:请求阶段

规则描述:过滤上传文件名中的网页脚本扩展名,拦截webshell上传

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
local rgx = waf.rgxMatch

local function fileNameMatch(v)
local m = rgx(v, "\\.(?:as|cer\\b|cdx|ph|jsp|war|class|exe|ht|env|user\\.ini)|php\\.ini", "joi")
if m then
return m, v
end
return false
end
if waf.form then
local m, d = waf.knFilter(waf.form["FILES"], fileNameMatch, 1)
return m, d, true
end

return false

防持续攻击

过滤阶段:请求阶段

规则描述:累计攻击超过100次,则在10分钟内拦截该ip访问

规则内容:

1
2
3
4
5
6
7
local ib = waf.ipBlock
local c = ib:get(waf.ip)
if c and c >= 100 then
ib:set(waf.ip, c, 600, 1)
return true, "ip blocked for continue attack: " .. waf.ip, true
end
return false

Invalid protocol

过滤阶段:请求阶段

规则描述:非法post协议

规则内容:

1
2
3
4
5
6
7
if waf.form == nil then
if waf.contains(waf.fErr, "content_type") then
return true, waf.fErr .. ": " .. waf.reqContentType, true
end
return true, waf.fErr, true
end
return false

Nginx 的 WAF 规则 LuaJIT 高危险版

2023年12月23日 00:00

前段时间杜老师发表了一篇《自建 CDN 服务器思路》其中介绍南墙 Web 应用防火墙,有些小伙伴们对其名字很感兴趣,而杜老师注意到了它的防护规则,感觉非常实用,顺手整理了下,分享给需要的小伙伴们。此篇为高危险防护规则!

SQL报错检测

过滤阶段:返回页面

规则描述:返回页面的sql报错可能会泄露服务器敏感信息

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
local check = waf.plugins.sqlErrorDetection.check
local rb = waf.respBody
local rgx = waf.rgxMatch
local has = waf.contains

if waf.status == 500 then
local m = check(rb)
if m then
if rgx(rb, "JET Database Engine|Access Database Engine|\\[Microsoft\\]\\[ODBC Microsoft Access Driver\\]", "jo") then
return m, "Microsoft Access SQL Information Leakage: " .. rb, true
end
if rgx(rb, "ORA-[0-9][0-9][0-9][0-9]|java\\.sql\\.SQLException|Oracle error|Oracle.*Driver|Warning.*oci_.*|Warning.*ora_.*", "jo") then
return m, "Oracle SQL Information Leakage: " .. rb, true
end
if rgx(rb, "DB2 SQL error:|\\[IBM\\]\\[CLI Driver\\]\\[DB2/6000\\]|CLI Driver.*DB2|DB2 SQL error|db2_\\w+\\(", "jo") then
return m, "DB2 SQL Information Leakage: " .. rb, true
end
if rgx(rb, "\\[DM_QUERY_E_SYNTAX\\]|has occurred in the vicinity of:", "jo") then
return m, "EMC SQL Information Leakage: " .. rb, true
end
if has(rb, "Dynamic SQL Error") then
return m, "firebird SQL Information Leakage: " .. rb, true
end
if rgx(rb, "Exception (?:condition )?\\d+\\. Transaction rollback\\.", "jo") then
return m, "Frontbase SQL Information Leakage: " .. rb, true
end
if has(rb, "org.hsqldb.jdbc") then
return m, "hsqldb SQL Information Leakage: " .. rb, true
end
if rgx(rb, "An illegal character has been found in the statement|com\\.informix\\.jdbc|Exception.*Informix", "jo") then
return m, "informix SQL Information Leakage: " .. rb, true
end
if rgx(rb, "Warning.*ingres_|Ingres SQLSTATE|Ingres\\W.*Driver", "jo") then
return m, "ingres SQL Information Leakage: " .. rb, true
end
if rgx(rb, "<b>Warning</b>: ibase_|Unexpected end of command in statement", "jo") then
return m, "interbase SQL Information Leakage: " .. rb, true
end
if rgx(rb, "SQL error.*POS[0-9]+|Warning.*maxdb", "jo") then
return m, "maxDB SQL Information Leakage: " .. rb, true
end
if rgx(rb, "System\\.Data\\.OleDb\\.OleDbException|\\[Microsoft\\]\\[ODBC SQL Server Driver\\]|\\[Macromedia\\]\\[SQLServer JDBC Driver\\]|\\[SqlException|System\\.Data\\.SqlClient\\.SqlException|Unclosed quotation mark after the character string|'80040e14'|mssql_query\\(\\)|Microsoft OLE DB Provider for ODBC Drivers|Microsoft OLE DB Provider for SQL Server|Incorrect syntax near|Sintaxis incorrecta cerca de|Syntax error in string in query expression|Procedure or function .* expects parameter|Unclosed quotation mark before the character string|Syntax error .* in query expression|Data type mismatch in criteria expression\\.|ADODB\\.Field \\(0x800A0BCD\\)|the used select statements have different number of columns|OLE DB.*SQL Server|Warning.*mssql_.*|Driver.*SQL[ _-]*Server|SQL Server.*Driver|SQL Server.*[0-9a-fA-F]{8}|Exception.*\\WSystem\\.Data\\.SqlClient\\.", "jo") then
return m, "Mssql SQL Information Leakage: " .. rb, true
end
if rgx(rb, "MyS(?:QL server version for the right syntax to use|qlClient\\.)|(?:supplied argument is not a valid |SQL syntax.*)MySQL|Column count doesn't match(?: value count at row)?|(?:Table '[^']+' doesn't exis|valid MySQL resul)t|You have an error in your SQL syntax(?: near|;)|Warning.{1,10}mysql_(?:[a-z_()]{1,26})?|ERROR [0-9]{4} \\([a-z0-9]{5}\\):|mysql_fetch_array\\(\\)|on MySQL result index|\\[MySQL\\]\\[ODBC", "jo") then
return m, "Mysql SQL Information Leakage: " .. rb, true
end
if rgx(rb, "PostgreSQL query failed:|pg_query\\(\\) \\[:|pg_exec\\(\\) \\[:|PostgreSQL.{1,20}ERROR|Warning.*\\bpg_.*|valid PostgreSQL result|Npgsql\\.|PG::[a-zA-Z]*Error|Supplied argument is not a valid PostgreSQL .*? resource|Unable to connect to PostgreSQL server", "jo") then
return m, "Postgres SQL Information Leakage: " .. rb, true
end
if rgx(rb, "Warning.*sqlite_|Warning.*SQLite3::|SQLite/JDBCDriver|SQLite\\.Exception|System\\.Data\\.SQLite\\.SQLiteException", "jo") then
return m, "SQLite SQL Information Leakage: " .. rb, true
end
if rgx(rb, "Sybase message:|Warning.{2,20}sybase|Sybase.*Server message", "jo") then
return m, "Sybase SQL Information Leakage: " .. rb, true
end
end
end

return false

数据泄露检测

过滤阶段:返回页面

规则描述:从返回页面检测列目录漏洞和源代码泄露问题

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
local rgx = waf.rgxMatch
local rb = waf.respBody

local m = rgx(rb, "<(?:TITLE>Index of.*?<H|title>Index of.*?<h)1>Index of|>\\[To Parent Directory\\]</[Aa]><br>", "jo")
if m then
return m, "Directory Listing: " .. rb, true
end

m = rgx(rb, "^\\s*(?:#\\!\\s?/|<%|<\\?\\s*[^x]|<jsp:)", "jo")
if m then
return m, "Source code leak: " .. rb, true
end

return false

固定会话(Session Fixation)攻击

过滤阶段:请求阶段

规则描述:会话固定攻击(session fixation attack)是利用应用系统在服务器的会话ID固定不变机制,借助他人用相同的会话ID获取认证和授权,然后利用该会话ID劫持他人的会话以成功冒充他人,造成会话固定攻击。

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
local kvFilter = waf.kvFilter
local rgx = waf.rgxMatch
local referer = waf.referer
local host = waf.host
local endWith = waf.endWith

local function sMatch(v)
local m = rgx(v, "\\bhttp-equiv\\W+set-cookie\\b", "joi")
if m then
return m, v
end
return false
end

local function nMatch(v)
local m = rgx(v, "^(?:jsessionid|aspsessionid|asp\\.net_sessionid|phpsession|phpsessid|weblogicsession|session_id|session-id|cfid|cftoken|cfsid|jservsession|jwsession)$", "joi")
if m then
return m, v
end
return false
end

local form = waf.form
if form then
local m, d = kvFilter(form["FORM"], sMatch)
if m then
return m, d, true
end
for k, v in pairs(form["FORM"]) do
m, d = nMatch(k)
if m then
if not referer then
if type(v) == "table" then
v = table.concat(v)
end
return m, d .. ":" .. v, true
else
m = ngx.re.match(referer, "^https?://(.*?)/", "jo")
if m and not endWith(m[1], host) then
if type(v) == "table" then
v = table.concat(v)
end
return m, d .. ":" .. v, true
end
end
end
end
end

local queryString = waf.queryString
if queryString then
local m, d = kvFilter(queryString, sMatch)
if m then
return m, d, true
end
for k, v in pairs(queryString) do
m, d = nMatch(k)
if m then
if not referer then
if type(v) == "table" then
v = table.concat(v)
end
return m, d .. ":" .. v, true
else
m = ngx.re.match(referer, "^https?://(.*?)/", "jo")
if m and not endWith(m[1], host) then
if type(v) == "table" then
v = table.concat(v)
end
return m, d .. ":" .. v, true
end
end
end
end
end

local cookies = waf.cookies
if cookies then
local m, d = kvFilter(cookies, sMatch)
if m then
return m, d, true
end
end

return false

通用攻击

过滤阶段:请求阶段

规则描述:本规则拦截ruby、node、js、perl注入和SSRF攻击

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
local kvFilter = waf.kvFilter
local rgx = waf.rgxMatch

local function sMatch(v)
local m = rgx(v, "Process\\s*\\.\\s*spawn\\s*\\(", "jos")
if m then
return m, "Ruby Injection Attack: "..v
end
m = rgx(v, "t(?:his\\.constructor|runcateSync\\s*\\()|\\b(?:spawn|eval)\\s*\\(|_(?:\\$\\$ND_FUNC\\$\\$_|_js_function)|String\\s*\\.\\s*fromCharCode", "jos")
if m then
return m, "Node.js Injection Attack: "..v
end
m = rgx(v, "__proto__|constructor\\s*(?:\\.|\\[)\\s*prototype", "jos")
if m then
return m, "JavaScript Prototype Pollution: "..v
end
m = rgx(v, "(?:s(?:sh(?:2(?:.(?:s(?:(?:ft|c)p|hell)|tunnel|exec))?)?|m(?:[bs]|tps?)|vn(?:\\+ssh)?|n(?:ews|mp)|ips?|ftp|3)|p(?:op(?:3s?|2)|r(?:oxy|es)|h(?:ar|p)|aparazzi|syc)|c(?:ompress.(?:bzip2|zlib)|a(?:llto|p)|id|vs)|t(?:e(?:amspeak|lnet)|urns?|ftp)|f(?:i(?:nger|sh)|(?:ee)?d|tps?)|i(?:rc[6s]?|maps?|pps?|cap|ax)|d(?:a(?:ta|v)|n(?:tp|s)|ict)|m(?:a(?:ilto|ven)|umble|ms)|n(?:e(?:tdoc|ws)|ntps?|fs)|r(?:tm(?:f?p)?|sync|ar|mi)|v(?:iew-source|entrilo|nc)|a(?:ttachment|f[ps]|cap)|b(?:eshare|itcoin|lob)|g(?:o(?:pher)?|lob|it)|u(?:nreal|t2004|dp)|e(?:xpect|d2k)|h(?:ttps?|323)|w(?:ebcal|s?s)|ja(?:bbe)?r|x(?:mpp|ri)|ldap[is]?|ogg|zip):\\/\\/(?:(?:[\\d.]{0,11}(?:(?:\\xe2(?:\\x92(?:[\\x9c\\x9d\\x9e\\x9f\\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\\xb0\\xb1\\xb2\\xb3\\xb4\\xb5]|[\\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f\\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\\x98\\x99\\x9a\\x9b]|[\\xb6\\xb7\\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe\\xbf]|[\\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87])|\\x93(?:[\\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87\\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f]|[\\x9c\\x9d\\x9e\\x9f\\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\\xa8\\xa9]|[\\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\\x98\\x99\\x9a\\x9b]|[\\xbf\\xb5\\xb6\\xb7\\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe]|[\\xab\\xac\\xad\\xae\\xaf\\xb0\\xb1\\xb2\\xb3\\xb4])|\\x91(?:[\\xaa\\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\\xb0\\xb1\\xb2\\xb3]|[\\xb4\\xb5\\xb6\\xb7\\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe\\xbf]))|\\xe3\\x80\\x82))+)|[a-z][\\w\\-\\.]{1,255}:\\d{1,5}(?:#?\\s*&?@(?:(?:\\d{1,3}\\.){3,3}\\d{1,3}|[a-z][\\w\\-\\.]{1,255}):\\d{1,5}\\/?)+|(?:0x[a-f0-9]{2}\\.){3}0x[a-f0-9]{2}|(?:0{1,4}\\d{1,3}\\.){3}0{1,4}\\d{1,3}|\\d{1,3}\\.(?:\\d{1,3}\\.\\d{5}|\\d{8})|0x(?:[a-f0-9]{16}|[a-f0-9]{8})|\\[[a-f\\d:]+(?:[\\d.]+|%\\w+)?\\]|(?:\\x5c\\x5c[a-z\\d-]\\.?_?)+|\\d{10})", "josi")
if m then
return m, "Possible Server Side Request Forgery (SSRF) Attack: "..v
end
m = rgx(v, "\\@\\{.*?\\}", "jos")
if m then
return m, "Perl Injection Attack: "..v
end
return false
end

local form = waf.form
if form then
local m, d = kvFilter(form["FORM"], sMatch)
if m then
return m, d, true
end
end

local queryString = waf.queryString
if queryString then
local m, d = kvFilter(queryString, sMatch)
if m then
return m, d, true
end
end

local cookies = waf.cookies
if cookies then
local m, d = kvFilter(cookies, sMatch)
if m then
return m, d, true
end
end

local m, d = kvFilter(waf.reqHeaders, sMatch)
if m then
return m, d, true
end
return false

php安全规则集

过滤阶段:请求阶段

规则描述:检测php相关的对象序列化等漏洞

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
local kvFilter = waf.kvFilter
local rgx = waf.rgxMatch

local function sMatch(v)
local m = rgx(v, "php://(?:std(?:in|out|err)|(?:in|out)put|fd|memory|temp|filter)|(?:ssh2(?:.(?:s(?:(?:ft|c)p|hell)|tunnel|exec))?|z(?:lib|ip)|(?:ph|r)ar|expect|bzip2|glob|ogg)://", "joi")
if m then
return m, v
end
m = rgx(v, "[oOcC]:\\d+:\"\\w+\":\\d+:{.*?}", "jos")
if m then
return m, v
end
return false
end

local function fileContentMatch(v)
local m = rgx(v, "<\\?.+?\\$_(?:GET|POST|COOKIE|REQUEST|SERVER|FILES|SESSION)|<\\?php", "jos")
if m then
return m, v
end
return false
end

local form = waf.form
if form then
local m, d = kvFilter(form["FORM"], sMatch)
if m then
return m, d, true
end
m, d = waf.knFilter(form["FILES"], fileContentMatch, 0)
if m then
return m, d, true
end
end

local queryString = waf.queryString
if queryString then
local m, d = kvFilter(queryString, sMatch)
if m then
return m, d, true
end
end

local cookies = waf.cookies
if cookies then
local m, d = kvFilter(cookies, sMatch)
if m then
return m, d, true
end
end

local m, d = kvFilter(waf.reqHeaders, sMatch)
if m then
return m, d, true
end
return false

路径遍历攻击

过滤阶段:请求阶段

规则描述:检测url、上传文件或参数中的路径遍历攻击。采用LFI语义检测引擎,可以检查如://///…\…\etc///passwd等变形攻击。

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
local checkPT = waf.checkPT
local kvFilter = waf.kvFilter

local function ptMatch(v)
local m = checkPT(v)
if m then
return m, v
end
return false
end

local url = waf.urlDecode(waf.reqUri)
if checkPT(url) then
return true, url, true
end

local form = waf.form
if form then
local m, d = kvFilter(form["FORM"], ptMatch)
if m then
return m, d, true
end
m, d = waf.knFilter(waf.form["FILES"], ptMatch, 1)
if m then
return m, d, true
end
end

local queryString = waf.queryString
if queryString then
local m, d = kvFilter(queryString, ptMatch)
if m then
return m, d, true
end
end

return false

异常请求字符编码拦截

过滤阶段:请求阶段

规则描述:黑客通常会在Content-Type头中使用异常的charset定义字符集编码来绕过waf保护,如IBM037, IBM500, cp875等

规则内容:

1
2
3
4
5
6
7
8
9
10
11
local rct = waf.reqContentType
local has = waf.contains
local counter = waf.strCounter
local rgx = waf.rgxMatch
if rct then
rct = waf.toLower(rct)
if has(rct, "charset") and (not rgx(rct, "charset\\s*=\\s*(utf\\-8|gbk|gb2312|iso\\-8859\\-1|iso\\-8859\\-15|windows\\-1252)","jo") or counter(rct, "charset") > 1) then
return true, rct, true
end
end
return false

代理头sql注入

过滤阶段:请求阶段

规则描述:过滤http请求中X-Forwarded-For、Client-IP请求头中单引号sql注入

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
local rip=waf.reqHeaders.x_forwarded_for
if rip then
if type(rip) ~= "string" then
return true,"Malform X-Forwarded-For",true
elseif waf.contains(rip,"'") then
return true,rip,true
end
end
rip=waf.reqHeaders.client_ip
if rip then
if type(rip) ~= "string" then
return true,"Malform Client-IP",true
elseif waf.contains(rip,"'") then
return true,rip,true
end
end
return false

Invalid protocol

过滤阶段:请求阶段

规则描述:cookie参数过多

规则内容:

1
2
3
4
if waf.cookies==nil then
return true,waf.cErr,true
end
return false

Invalid protocol

过滤阶段:请求阶段

规则描述:querystring参数过多

规则内容:

1
2
3
4
if waf.queryString==nil then
return true,waf.qErr,true
end
return false

Nginx 的 WAF 规则 LuaJIT 中危险版

2023年12月20日 00:00

前段时间杜老师发表了一篇《自建 CDN 服务器思路》其中介绍南墙 Web 应用防火墙,有些小伙伴们对其名字很感兴趣,而杜老师注意到了它的防护规则,感觉非常实用,顺手整理了下,分享给需要的小伙伴们。此篇为中危险防护规则!

机器人攻击防护

过滤阶段:请求阶段

规则描述:通过生成滑动旋转验证码来拦截机器人攻击,如漏洞扫描、网络爬虫、CC攻击等自动化攻击行为,Token有效期30分钟。

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
local sh = ngx.shared.ipCache
local robotIp = 'rb:' .. waf.ip
local c, f = sh:get(robotIp)

-- 如果是静态页面且没有进行滑动旋转验证码验证则返回
if not (waf.isQueryString or waf.reqContentLength > 0) and f ~= 2 then
return false
end

if not c then
sh:set(robotIp, 1, 60, 1) -- 设置1分钟也就是60秒访问计数时间段
else
if f == 2 then
return waf.checkRobot(waf) -- 启动机器人滑动旋转验证码验证
end
sh:incr(robotIp, 1)
if c + 1 >= 360 then
sh:set(robotIp, c + 1, 1800, 2) -- 达到了60秒内请求超过360次的阈值,进入机器人验证模式
return true, robotIp, true
end
end

return false

弱口令检测

过滤阶段:请求阶段

规则描述:检测常见登录页面的弱口令问题

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
local check = waf.plugins.weakPwdDetection.check
local toLower = waf.toLower
local has = waf.contains

local form = waf.form
local uri = toLower(waf.uri)
if form and (has(uri, "login") or has(uri, "logon") or has(uri, "signin")) then
local f = form["FORM"]
if f then
for k, v in pairs(f) do
k = toLower(k)
if (k == "pass" or has(k, "pwd") or has(k, "passwd") or has(k, "password")) and check(v) then
return true, form["RAW"], false
end
end
end
end

return false

敏感文件泄露检测

过滤阶段:请求阶段

规则描述:检测url中各种敏感泄露文件的路径,如svn、git、sql、log、bak等,防止被攻击者利用

规则内容:

1
2
3
4
5
local m, d = waf.plugins.fileLeakDetection.check()
if m then
return true, d, true
end
return false

请求body大小限制

过滤阶段:请求阶段

规则描述:限制请求body大小为8M以下,黑客会尝试大数据包绕过waf过滤

规则内容:

1
2
3
4
if waf.reqContentLength>8388608 then
return true,"reqBody length is "..waf.reqContentLength ,true
end
return false

HTTP Parameter Pollution

过滤阶段:请求阶段

规则描述:http参数污染攻击,该规则查找具有相同名称的多个参数,并检查一些后端参数弱校验时产生的绕过问题,如:foo[1]a=bar&foo[1]b=或foo[1]x[1]=bar&foo[1]x[2]=等。

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
local rgx = waf.rgxMatch

local function rMatch(v)
local m = rgx(v, "(?:][^\\]]+$|][^\\]]+\\[)", "jos")
if m then
return m, v
end
return false
end

local form = waf.form
if form then
for k, v in pairs(form["FORM"]) do
if type(v) == "table" then
return true, k.."="..table.concat(v, ","), true
end
local m, d = rMatch(k)
if m then
return m, d, true
end
end
end

local queryString = waf.queryString
if queryString then
for k, v in pairs(queryString) do
if type(v) == "table" then
return true, k.."="..table.concat(v, ","), true
end
local m, d = rMatch(k)
if m then
return m, d, true
end
end
end

local cookies = waf.cookies
if cookies then
for k, v in pairs(cookies) do
if type(v) == "table" then
return true, k.."="..table.concat(v, ","), true
end
local m, d = rMatch(k)
if m then
return m, d, true
end
end
end
return false

扫描器检测

过滤阶段:请求阶段

规则描述:检测常见的各种扫描器,如awvs、sqlmap、nessus、appscan、nmap等,拦截它们有助于减少黑客发现漏洞的风险

规则内容:

1
2
3
4
5
local m, d = waf.plugins.scannerDetection.check()
if m then
return true, d, true
end
return false

Nginx 的 WAF 规则 LuaJIT 低危险版

2023年12月17日 00:00

前段时间杜老师发表了一篇《自建 CDN 服务器思路》其中介绍南墙 Web 应用防火墙,有些小伙伴们对其名字很感兴趣,而杜老师注意到了它的防护规则,感觉非常实用,顺手整理了下,分享给需要的小伙伴们。此篇为低危险防护规则!

防CC攻击规则

过滤阶段:请求阶段

规则描述:当一分钟访问/api/路径频率超过360次,则在5分钟内拦截该ip访问

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if not waf.startWith(waf.toLower(waf.uri), "/api/") then
return false
end

local sh = ngx.shared.ipCache
local ccIp = 'cc-' .. waf.ip
local c, f = sh:get(ccIp)
if not c then
sh:set(ccIp, 1, 60, 1) -- 设置1分钟也就是60秒访问计数时间
else
if f == 2 then
return waf.block(true) -- 重置TCP连接,不记录日志
end
sh:incr(ccIp, 1)
if c + 1 >= 360 then
sh:set(ccIp, c + 1, 300, 2) -- 设置5分钟也就是300秒拦截时间
return true, ccIp, true
end
end

return false

IIS报错检测

过滤阶段:返回页面

规则描述:IIS返回页面的报错可能会泄露服务器敏感信息

规则内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
local rgx = waf.rgxMatch
local rb = waf.respBody

local m = rgx(rb, "[a-z]:\\x5cinetpub\\b", "jo")
if m then
return m, rb, true
end

if waf.status == 500 then
local m = rgx(rb, "Microsoft OLE DB Provider for SQL Server(?:</font>.{1,20}?error '800(?:04005|40e31)'.{1,40}?Timeout expired| \\(0x80040e31\\)<br>Timeout expired<br>)|<h1>internal server error</h1>.*?<h2>part of the server has crashed or it has a configuration error\\.</h2>|cannot connect to the server: timed out", "jo")
if m then
return m, rb, true
end
local m = rgx(rb, "\\b(?:A(?:DODB\\.Command\\b.{0,100}?\\b(?:Application uses a value of the wrong type for the current operation\\b|error')| trappable error occurred in an external object\\. The script cannot continue running\\b)|Microsoft VBScript (?:compilation (?:\\(0x8|error)|runtime (?:Error|\\(0x8))\\b|Object required: '|error '800)|<b>Version Information:</b>(?:&nbsp;|\\s)(?:Microsoft \\.NET Framework|ASP\\.NET) Version:|>error 'ASP\\b|An Error Has Occurred|>Syntax error in string in query expression|/[Ee]rror[Mm]essage\\.aspx?\\?[Ee]rror\\b", "jo")
if m then
return m, rb, true
end
end

if waf.status == 404 then
local m = rgx(rb, "\\bServer Error in.{0,50}?\\bApplication\\b", "jo")
if m then
return m, rb, true
end
end

return false

php报错检测

过滤阶段:返回页面

规则描述:返回页面的php报错可能会泄露服务器敏感信息

规则内容:

1
2
3
4
5
6
7
8
9
10
11
local check = waf.plugins.phpErrorDetection.check
local rb = waf.respBody

if waf.status == 500 then
local m, d = check(rb)
if m then
return m, "php error: " .. d, true
end
end

return false

Java报错检测

过滤阶段:返回页面

规则描述:返回页面的java报错可能会泄露服务器敏感信息

规则内容:

1
2
3
4
5
6
7
8
9
10
11
local check = waf.plugins.javaErrorDetection.check
local rb = waf.respBody

if waf.status == 500 then
local m,d = check(rb)
if m then
return m, "Java error: " .. d, true
end
end

return false

请求方法加强

过滤阶段:请求阶段

规则描述:不常用的http请求方法会出现一些安全漏洞,如:历史上Apache平台TRACE请求方法出现过XSS相关漏洞

规则内容:

1
2
3
if not waf.rgxMatch(waf.method, "^(?:GET|HEAD|POST|PUT|DELETE|OPTIONS)$") then
return true, waf.method, true
end
❌
❌