0x01 前言

前些天我为nginx配置安装了Naxsi WAF(安装naxsi为nginx提供WAF服务),它的规则对于入门者来说确实有点复杂。

我在这里记录一下这几天我学了解到的知识。

0x02 类型

首先naxsi有三种规则类型,相对应的功能如下:

  • MainRule:定义检测规则和分数
  • BasicRule:定义MainRule的白名单
  • CheckRule:定义当分数达到阀值时所采取的动作

MainRule可以在这里找到:

naxsi/naxsi_config/naxsi_core.rules

BasicRule可以在这里找到:

nbs-system/naxsi-rules

而CheckRule则是文章(安装naxsi为nginx提供WAF服务)中需要添加到location块中的内容:

CheckRule "$SQL >= 8" BLOCK;
CheckRule "$RFI >= 8" BLOCK;
CheckRule "$TRAVERSAL >= 4" BLOCK;
CheckRule "$EVADE >= 4" BLOCK;
CheckRule "$XSS >= 8" BLOCK;

0x03 MainRule

规则例子:

MainRule "str:0x" "msg:0x, possible hex encoding" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:2" id:1002;

MainRule后看紧跟着的是匹配模式,模式有:

  • str:字符串
  • rx:正则表达式
  • d:libinj_xss:libinjection检测为xss
  • d:libinj_sql:libinjection检测为sql注入

例子中的”str:0x”,代表匹配 0x 这个字符。

然后是描述,仅用于描述规则,不会有其他动作:

"msg:0x, possible hex encoding"

然后是匹配区域Match Zones:

"mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie"

mz支持以下区域:

  • ARGS: GET args 参数
  • HEADERS:HTTP Headers
  • BODY: POST args (和 RAW_BODY)
  • URL:在?之前的URL

在例子中的HEADERS采取了更为详细的声明:$HEADERS_VAR:Cookie。同样的,其他区域也同样支持详细声明:

  • $ARGS_VAR:string: named GET argument
  • $HEADERS_VAR:string : named HTTP header
  • $BODY_VAR:string: named POST argument

紧跟着的是评分Score:

"s:$SQL:2"

如果某个请求符合这条规则,那么名为$SQL的这个计数器就会加2;如果这个请求中有多个参数符合这条规则,那么计数器也会相应地增加。

当$SQL这个计数器符合在location中CheckRule对于$SQL计数器的定义时,将采取相对应的动作,如:

CheckRule "$SQL >= 8" BLOCK;

当计数器$SQL分数大于等于8,nginx将禁止访问。

最后是规则id,这id在编写白名单的时候会用到:

id:1002

0x04 BasicRule

白名单的添加最好能以日志为基础进行操作。如果你不想在配置Naxsi的时候导致服务无法访问,那么可以打开学习模式:

LearningMode;
SecRulesEnabled;
DeniedUrl "/RequestDenied";
CheckRule "$SQL >= 8" BLOCK;
CheckRule "$RFI >= 8" BLOCK;
CheckRule "$TRAVERSAL >= 4" BLOCK;
CheckRule "$EVADE >= 4" BLOCK;
CheckRule "$XSS >= 8" BLOCK;

在location块中加入 LearningMode; 即可。

首先来看看日志:

2013/11/10 07:36:19 [error] 8278#0: *5932 NAXSI_FMT: ip=X.X.X.X&server=Y.Y.Y.Y&uri=/phpMyAdmin-2.8.2/scripts/setup.php&learning=0&vers=0.52&total_processed=472&total_blocked=204&block=0&cscore0=$UWA&score0=8&zone0=HEADERS&id0=42000227&var_name0=user-agent, client: X.X.X.X, server: blog.memze.ro, request: "GET /phpMyAdmin-2.8.2/scripts/setup.php HTTP/1.1", host: "X.X.X.X"

一上面这个日志为例,可以看到访问请求出发了id为42000227,匹配区域为HEADERS,字符串为user-agent的规则。

那么白名单可以写成以下这种形式:

BasicRule wl:42000227 "mz:$URL:/phpMyAdmin-2.8.2/scripts/setup.php|$HEADERS:user-agent";

下一次访问以下地址的时候:

/phpMyAdmin-2.8.2/scripts/setup.php

id为42000227中HEADERS的检测就不会再匹配user-agent。

0x05 CheckRule

CheckRule "$SQL >= 8" BLOCK;
CheckRule "$RFI >= 8" BLOCK;
CheckRule "$TRAVERSAL >= 4" BLOCK;
CheckRule "$EVADE >= 4" BLOCK;
CheckRule "$XSS >= 8" BLOCK;

以上是加载在location中的CheckRule。他们的主要作用是读取计数器中的数值,与CheckRule中所设定的数值进行对比,一旦符合设定,那么将进行响应的动作。

以上的CheckRule意味着当名为$SQL、$RFI、$TRAVERSAL、$EVADE和$XSS这些计数器的值达到设定值后,将禁止访问。

动作不仅仅有BLOCK,还有以下这些:

  • DROP:抛弃请求,不做任何回应
  • BLOCK:根据DeniedUrl的设定进行跳转
  • ALLOW:允许通过
  • LOG:仅记录在日志中,不做任何动作

0x06 结语

最为方便的事规则支持正则表达式,这大大方便了我们的工作。

刚开始的时候是很难理解和使用规则,但尝试过一周后就能理解并熟悉应用了。