在Nginx下安装和配置完Naxsi之后,为了能够使网站能够区分非法行为和合法行为,需要管理员将合法行为列入白名单。管理员可以通过分析nginx的错误日志手动添加白名单规则,或者通过密集的自动学习工具(nxapi或nxtool),这些工具将自动生成有关网站行为的白名单规则。本文主要介绍白名单规则以及如何通过分析nginx错误日志手动添加白名单规则。
白名单规则配置
naxsi核心规则文件naxsi_core.rules需要在nginx配置文件nginx.conf下的http部分导入,而naxsi白名单规则文件naxsi_whitelists.rules一般在nginx配置文件nginx.conf下的location部分导入,可放置在CheckRules语句之前。
location部分对应的配置内容如下。
include naxsi_whitelists.rules;#导入白名单规则
SecRulesEnabled;
DeniedUrl "/RequestDenied";
CheckRule "$SQL >= 8" BLOCK;
CheckRule "$RFI >= 8" BLOCK;
CheckRule "$TRAVERSAL >=4" BLOCK;
CheckRule "$EVADE >= 4" BLOCK;
CheckRule "$XSS >= 8" BLOCK;
error_log /path/to/foo.log;#配置Naxsi错误日志
为了区分Naxsi和Nginx的错误日志,可以为Naxsi设置相应的错误日志目录和文件名。在本文中,Naxsi对应的错误日志为foo.log。
白名单规则语法
如果服务器安装的是Wordpress或者ruTorrent或者dokuwiki或者drupal等,可以直接在naxsi-rules找到Naxsi官方制作的白名单。如果都没有找到适合的白名单,就只能自己去配置白名单了。
白名单规则的语法如下所示。然后介绍语法中的重要组成部分。
BasicRule wl:ID [negative] [mz:[$URL:target_url]|[match_zone]|[$ARGS_VAR:varname]|[$BODY_VARS:varname]|[$HEADERS_VAR:varname]|[NAME]]
Whitelisted ID (wl:…)
这部分指的是哪些拦截规则会进入白名单。以下举例进行说明。
wl:0 : 把所有拦截规则加入白名单
wl:42 : 把ID为42的拦截规则加入白名单
wl:42,41,43 : 把ID为42, 41 和 43的拦截规则加入白名单
wl:-42 : 把所有拦截规则加入白名单,除了ID为42的拦截规则
MatchZone (mz:…)
这部分指的是本条白名单的生效区域。区域有如下组成部分。
- ARGS: GET的整个参数内容,如: foo=bar&in=%20
- $ARGS_VAR: GET参数的参数名, 如 foo=bar&in=%20中的 foo和in。
- $ARGS_VAR_X: 正则匹配的GET参数的参数名
- HEADERS: 整个HTTP协议头内容
- $HEADERS_VAR: HTTP协议头的参数名
- $HEADERS_VAR_X: 正则匹配的HTTP协议头的参数名
- BODY: POST的整个参数内容
- $BODY_VAR: POST参数的参数名
- $BODY_VAR_X: 正则匹配的POST参数的参数名
- URL(整个链接?前的部分链接)
- $URL:域名后的路径
- $URL_X: 正则匹配的URL(整个链接?前的部分链接)
- FILE_EXT: 文件名 (POST上传文件时上传的文件名)
- RAW_BODY: HTTP请求的BODY部分的原始的未解析的内容
白名单规则示例
以下对静态的白名单规则进行举例说明。
BasicRule wl:1000;
已知拦截规则1000是过滤包含select|union|update|delete|insert|table|from|ascii|hex|unhex之类SQL关键字的规则。
在本子规则中完全禁用拦截规则1000。因为没有指定区域,所以全部加入白名单。
BasicRule wl:1000 “mz:$ARGS_VAR:foo”;
在全部GET参数名为foo的值中禁用拦截规则1000 (即不用1000规则检查GET中参数名为foo中的值)。所以, http://127.0.0.1/?foo=select * from a 不会被过滤。
BasicRule wl:1000 “mz:$ARGS_VAR:foo|$URL:/bar”;
在URL为/bar的GET请求中参数名为foo的值中禁用拦截规则1000。所以, http://127.0.0.1/bar?foo=select * from a 不会被过滤。
BasicRule wl:1000 “mz:$URL:/bar|ARGS”;
在URL为/bar的GET请求中的参数禁用拦截规则1000。所以, http://127.0.0.1/bar?my=select * from a 不会被过滤。http://127.0.0.1/bar?from=weibo 也不会被过滤。
BasicRule wl:1000 “mz:ARGS|NAME”;
在全部GET请求中对所有参数名(只是名,不包含参数值)中禁用拦截规则1000。所以, http://127.0.0.1?from=weibo 不会被过滤。但是, http://127.0.0.1?foo=select 会被过滤(因为select属于参数值,不在白名单范围内)。
BasicRule wl:1000 “mz:$URL:/bar|ARGS|NAME”;
在URL为/bar的全部GET请求中对所有参数名(只是名,不包含参数值)中禁用拦截规则1000。所以, http://127.0.0.1/bar?from=weibo 不会被过滤。但是, http://127.0.0.1/bar?foo=select 会被过滤(因为select属于参数值,不在白名单范围内)。
BasicRule wl:0 “mz:$URL_X:^/upload/(.).(.)$|URL”;
在全部请求中对符合^/upload/(.).(.)$正则规则的URL禁用全部拦截规则。所以, http://127.0.0.1/upload/select.db 不会被过滤 (原本会触发1000拦截规则)。
以下对含正则表达式的白名单规则进行举例说明。
BasicRule wl:1000 “mz:$ARGS_VAR_X:meh”;
在全部GET参数名含有meh的值中禁用拦截规则1000 (即不用1000规则检查GET中参数名含有meh中的值)。所以, http://127.0.0.1/?smehe=select * from a 不会被过滤。
BasicRule wl:1000 “mz:$ARGS_VAR_X:^meh”;
在全部GET参数名以meh开始的值中禁用拦截规则1000 (即不用1000规则检查GET中参数名以meh开始的值)。所以, http://127.0.0.1/?mehe=select * from a 不会被过滤。
BasicRule wl:1000 “mz:$ARGS_VAR_X:^meh_[0-9]+$”
在全部GET参数名格式为“meh_数字”的值中禁用拦截规则1000 (即不用1000规则检查GET中参数名格式为“meh_数字”的值)。所以, http://127.0.0.1/?meh_12=select * from a 不会被过滤。
BasicRule wl:1000 “mz:$URL_X:^/foo|ARGS”;
在URL以/foo开始的GET请求中的参数禁用拦截规则1000。所以, http://127.0.0.1/foo1?my=select * from a 不会被过滤。http://127.0.0.1/foo2?from=weibo 也不会被过滤。
BasicRule wl:1000 “mz:$URL_X:^/foo|$ARGS_VAR_X:^[0-9]”;
在URL以/foo开始的GET请求中的以数字开始命名的参数禁用拦截规则1000。所以, http://127.0.0.1/foo1?2my=select * from a 不会被过滤。http://127.0.0.1/foo2?1from=weibo 也不会被过滤。
以下对RAW_BODY的白名单规则进行举例说明。以RAW_BODY为目标的白名单规则的编写方式与任何其他BODY规则相同。
BasicRule wl:4241 “mz:$URL:/|BODY”;
已知拦截规则4241是即便在学习模式下也要过滤RAW_BODT中包含字符串RANDOMTHINGS的规则。
在本子规则中,在URL为/的BODY中的内容禁用拦截规则4241,意味着该目录下的任意BODY内容都不会被过滤。
以下对FILE_EXT的白名单规则进行举例说明。
BasicRule wl:1337 “mz:$URL:/index.html|FILE_EXT”;
在本子规则中,在URL为/index.html的文件上传部分禁用拦截规则1337,意味着可在该目录下上传任意文件。
以下对JSON的白名单规则进行举例说明。
BasicRule wl:1302 “mz:$BODY_VAR:lol”;
JSON可被当作BODY, 以变量的形式表示文本内容。在本子规则中,对POST的参数lol禁用拦截规则1302,即以下JSON内容可以被通过。
{
"lol" : "foo<bar"
}
手动编写白名单规则
以下为访问http://yourwebsiteaddress/?foo=select * from a的错误日志记录。
2018/08/19 13:35:16 [error] 1#0: *187 NAXSI_FMT: ip=*.*.*.*&server=yourwebsiteaddress&uri=/&learning=0&vers=0.55.3&total_processed=116&total_blocked=1&block=1&cscore0=$SQL&score0=4&cscore1=$XSS&score1=8&zone0=ARGS&id0=1000&var_name0=foo, client: 10.30.169.105, server: bkjy.xmu.edu.cn, request: "GET /?a=select%20*%20from%20a HTTP/1.1", host: "bkjy.xmu.edu.cn"
从zone0=ARGS可看出被过滤的区域是ARGS,从id0=1000可看出拦截规则的id是1000,从var_name0=foo可看出被过滤的变量为foo。因此可以编写如下白名单规则。
BasicRule wl:1000 "mz:$ARGS_VAR:foo";
参考资料
1.Naxsi Wiki
2.NGINX的WAF模块-Naxsi 配置白名单
3.whitelists-bnf
4.matchzones-bnf
5.whitelists-examples