nginx naxsi 模块
背景
上周项目组的伙伴在灰度访问项目时,发现发送不了消息了。排查各个请求发现有请求被ng拦截了。
于是找到ng拦截日志,路径在ng配置的error日志中,默认在nginx根目录下的log目录下的error.log
如下:
2018/08/03 16:45:43 [error] 25994#0: *4783 NAXSI_FMT: ip=118.249.55.30&server=livechat-touch-client_test&uri=/ad/test/livechat-touch-client/chat/829/gipyojle/xhr_send&learning=0&vers=0.53-1&total_processed=56&total_blocked=11&block=1&zone0=BODY&id0=11&var_name0=, client: 118.249.55.30, server: localhost, request: "POST /ad/test/livechat-touch-client/chat/829/gipyojle/xhr_send?t=1533285944041 HTTP/1.1", host: "livechat-touch-client_test", referrer: "https://shop.10086.cn/ad/test/livechat-touch-client/pub-page/liveChatTouchHome.html?tenantId=1000091&code=BS&channelType=1012"
归纳下naxsi错误日志解释
- ip : Client's ip(访客IP)
- server : Requested Hostname (as seen in http header Host)(服务名称,这里为ng的location)
- uri: Requested URI (without arguments, stops at ?)(请求地址)
- learning: tells if naxsi was in learning mode (0/1)(学习模式是否开启)
- vers : Naxsi version, only since 0.51(naxsi版本)
- total_processed: Total number of requests processed by nginx's worker (ng处理工作进程)
- total_blocked: Total number of requests blocked by (naxsi) nginx's worker(naxsi拦截进程)
- zoneN: Zone in which match happened (see "Zones" in the table below)(规则匹配发生的区域,包括:arg|body|head)
- idN: The rule id that matched(匹配的拦截规则号)
- ** var_nameN: Variable name in which match happened (optional)(拦截规则匹配时的参数名)**
- cscoreN : named score tag
- scoreN : associated named score value 得分(每一项naxsi规则都有对应的得分)
那么我们就知道这个日志表明:该uri请求违反了id=11的naxsi规则,被拦截了。那么id=11的规则是什么呢?让我们了解下naxsi定义的规则,配置在ng的http中规则文件:
include /interactive/openresty18800/nginx/conf/naxsi_conf/naxsi_core.rules;
naxsi 核心规则(节选)
##################################
## INTERNAL RULES IDS:1-999 ##
##################################
#@MainRule "msg:weird request, unable to parse" id:1;
#@MainRule "msg:request too big, stored on disk and not parsed" id:2;
#@MainRule "msg:invalid hex encoding, null bytes" id:10;
#@MainRule "msg:unknown content-type" id:11;
#@MainRule "msg:invalid formatted url" id:12;
#@MainRule "msg:invalid POST format" id:13;
#@MainRule "msg:invalid POST boundary" id:14;
##################################
## SQL Injections IDs:1000-1099 ##
##################################
MainRule "rx:select|union|update|delete|insert|table|from|ascii|hex|unhex|drop" "msg:sql keywords" "mz:BODY|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:4" id:1000;
MainRule "str:\"" "msg:double quote" "mz:BODY|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:8,$XSS:8" id:1001;
MainRule "str:0x" "msg:0x, possible hex encoding" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:2" id:1002;
-
其中:(基本上都是http级别MainRule的规则)
location level (BasicRule) http level (MainRule)
ID 0-999为naxsi的内部规则,如不在白名单中,则自动生效。 其余为自定义规则,naxsi已经帮我们默认配置了大多数情况下都可适用的规则,一般来说是比较全面的,我们也可以参考。
-
匹配规则
rx:foo|bar : will match foo or bar
str:foo|bar : will match foo|bar
【下述需要第三方插件-后续有需要再研究】
d:libinj_xss : will match if libinjection says it's XSS (>= 0.55rc2)
d:libinj_sql : will match if libinjection says it's SQLi (>= 0.55rc2) -
得分
s: 前缀 $LABEL 区分标示 可自定义,如:footer。 score 得分 可自定义,如4 得分示例:s:$FOOTER:4 则表示匹配此规则,则得分为4. 结合CheckRule,根据标示和得分定义拦截配置。 CheckRules示例: CheckRule "$FOOTER >= 4" BLOCK 标示当规则匹配$FOOTER得分大于等于4时,则拦截。配置为上述拦截规则,则表示出现拦截,得分即为4,则符合拦截规则。 更多CheckRules,参考:https://github.com/nbs-system/naxsi/wiki/checkrules-bnf
5、匹配区域
字符匹配:
ARGS: GET args
HEADERS: HTTP Headers
BODY: POST args (and RAW_BODY)
URL: The URL itself (before '?')
$ARGS_VAR:string: named GET argument
$HEADERS_VAR:string : named HTTP header
$BODY_VAR:string: named POST argument
正则匹配:
$HEADERS_VAR_X:regex: regex matching a named HTTP header (>= 0.52)
$ARGS_VAR_X:regex: regex matching the name of a GET argument (>= 0.52)
$BODY_VAR_X:regex: regex matching the name of a POST argument (>= 0.52)
可制定匹配的URL,同样包括字符匹配和正则匹配
$URL:string: restricted to this url
$URL_X:regex: restricted to url matching regex (>= 0.52)
那么 @MainRule "msg:unknown content-type" id:11; 就是请求违反的规则,不知名的内容类型。从浏览器此请求header看,它的content-type为text/plain.
对比生产其他ng配置,发现其在naxsi的白名单中放过了id11,故可正常运行。 那么,我们再灰度环境配置中,增加此白名单即可解决。 让我们来看看,如何配置naxsi的白名单。
naxsi 白名单配置
其中wl 单独匹配放过某项规则,如:
- wl:0 : Whitelist all rules 代表放过所有规则
- wl:42 : Whitelist rule #42 代表放过id=42的规则
- wl:42,41,43 : Whitelist rules 42, 41 and 43 代表放过id=42/41/43规则
- wl:-42 : Whitelist all user rules (>= 1000), excepting rule 42 代表放过所有规则除了42规则
mz:MATCHZONE 配合wl规则,制定对应匹配区域规则,区域包括: URL, ARGS, HEADERS, BODY.
示例:url为/foo 请求放过BODY请求中参数名中的规则1310,1311
BasicRule id:1310,1311 "mz:$URL:/foo|BODY|NAME";
备注:增加|NAME标示对应目标为参数名,而非参数值。
更多示例,可参考
https://github.com/nbs-system/naxsi/wiki/whitelists-examples
附录-nginx增加naxis配置
nginx安装,增加naxis配置:
wget http://nginx.org/download/nginx-x.x.xx.tar.gz
wget https://github.com/nbs-system/naxsi/archive/x.xx.x.tar.gz
tar xvzf nginx-x.x.xx.tar.gz
tar xvzf naxsi-x.xx.tar.gz
cd nginx-x.x.xx/
./configure --add-module=../naxsi-x.xx/naxsi_src/ [add/remove your favorite/usual options]
make
make install
nginx配置:
#Only for nginx's version with modular support
load_module /../modules/ngx_http_naxsi_module.so;
events {
...
}
http {
include /tmp/naxsi_ut/naxsi_core.rules; #引用核心规则
...
server {
listen ...;
server_name ...;
location / {
#Enable naxsi
SecRulesEnabled;
#Enable learning mode
LearningMode;
#Define where blocked requests go
DeniedUrl "/50x.html";
#CheckRules, determining when naxsi needs to take action
CheckRule "$SQL >= 8" BLOCK;
CheckRule "$RFI >= 8" BLOCK;
CheckRule "$TRAVERSAL >= 4" BLOCK;
CheckRule "$EVADE >= 4" BLOCK;
CheckRule "$XSS >= 8" BLOCK;
#naxsi logs goes there
error_log /.../foo.log;
...
}
error_page 500 502 503 504 /50x.html;
#This is where the blocked requests are going
location = /50x.html {
return 418; #I'm a teapot \o/
}
}
}