<< Back to man.ChinaUnix.net   CU网友原创,转载请注明出自ChinaUnix.net及原作者

请求过滤

当过滤引擎被激活的情况下,每个进入的请求在被处理前都要被解释和分析。分析会以一系列事先设计用来校验请求格式的内置检查作为开始。这些检查可以通过配置指示来控制。在第二个阶段,请求会通过一系列的和这个请求相匹配的用户定义的过滤器。每当发生一个肯定的匹配,特定的动作会被执行。

 

简单过滤

最简单的规律形式是“简单”形式。看上去是这样的:

SecFilter KEYWORD

这样的每一个简单过滤器,ModSecurity会在请求中查找关键字。搜索范围很松,会应用在请求的第一行上(这个样子GET /index.php?parameter=value HTTP/1.0)。对POST请求来说,请求体也会被搜索(当让是在请求体缓存被激活的前提下)。

 

路径标准化

过滤器不是作用在原始的请求数据上的,而是在一个标准化了的副本上。这样做是因为攻击者可以(而且正在)通过使用不同的躲避技术来逃过监测。比如,你可能希望通过创建一个过滤器来监测shell命令的执行

SecFilter /bin/sh

但是攻击者可以使用一个字符串:/bin/./sh(具有相同的含义)来逃过过滤器。

ModSecurity自动采用下列转换:

l         只对Windows平台生效,\转换成/

l         /./缩减为/

l         //缩减为/

l         解码使用URL编码过的字符

你可以选择激活或禁止下列检查:

l         检验URL编码

l         只允许使用指定范围内的字节

ModeSecurity当前版本中实现的标准化有时候会影响你的正常工作。你可能在写一个在其他地方检查URI的信号的时候遇到很大困难。这是因为URI在请求中的形式是“http://” ,而这个字符串会在标准化过程中翻译成“http:/”。注意在后面这个版本中只有一个斜线。

 

防止空字节攻击

空字节攻击会迷惑C/C++开发的程序,是它们误认为一个字符串在实际的结束位置之前就结束。这种类型的攻击通常会被合理设置的SecFilterByteRange过滤器拒绝掉。但是如果你没有这样做,空字节会干扰ModSecurity的处理。为了击败这类攻击,ModSecurity在解码阶段搜索空字节并把他们转换成空格。因此,在以前的版本这个过滤器

SecFilter hidden

不会检测到下列请求中的单词hidden

GET /one/two/three?p=visible%00hidden HTTP/1.0

但是在现在的版本是可以检测到的。

 

正则表达式

我们前面讨论的最简单的过滤器实际上要稍微复杂一点。它的完整的语法是这样的:

SecFilter KEYWORD [ACTIONS]

首先,KEYWORD不是一个普通单词,而是一个正则表达式。正则表达式是设计用来在文本中匹配模式的迷你编程语言。为了充分理解这个强大的工具,需要先充分理解正则表达式。我推荐从下面的资源之一入手:

l         Perl兼容的正则表达式的手册页:http://www.pcre.org/pcre.txt

l         Perl正则表达式: http://www.perldoc.com/perl5.6/pod/perlre.html

l         精通正则表达式:http://www.oreilly.com/catalog/regex

l         Google搜索“正则表达式”:http://www.google.com/search?q=regular%20expressions

要小心(A|B)+类型的正则表达式,在海量的文本上使用这样的表达式会在尺寸比较小的平台,比如Windows上导致溢出。溢出会导致无法不可回复的段错误。

第二个参数是动作列表的定义,用来指定当过滤器匹配成功是发生的动作。关于动作会在后面解释。

 

反转表达式

如果一个正则表达式的第一个字符是惊叹号,过滤器会反转这个表达式。比如下面的例子:

SecFilter !php

会拒绝所有的不包含单词php的请求。

 

高级过滤

所以SecFilter可以让你快速上手,但是你很快会发现它的搜索面太宽,工作的不是很好。另一个指示:

SecFilterSelective LOCATION KEYWORD [ACTIONS]

让你可以准确的选择在哪里进行搜索。

KEYWORD和ACTIONS设置和SedFilter是一样的。LOCATION需要解释一下。LOCATION参数包含用管道符分开的一系列的位置标识符。看一下下边的例子:

SecFilterSelective "REMOTE_ADDR|REMOTE_HOST" KEYWORD

只在客户端的IP地址和主机名上使用正则表达式。可能的位置标识符包括所有的CGI变量和其他的一些内容。下面是完整的列表:

l         REMOTE_ADDR

l         REMOTE_HOST

l         REMOTE_USER

l         REMOTE_IDENT

l         REQUEST_METHOD

l         SCRIPT_FILENAME

l         PATH_INFO

l         QUERY_STRING

l         AUTH_TYPE

l         DOCUMENT_ROOT

l         SERVER_ADMIN

l         SERVER_NAME

l         SERVER_ADDR

l         SERVER_PORT

l         SERVER_PROTOCOL

l         SERVER_SOFTWARE

l         TIME_YEAR

l         TIME_MON

l         TIME_DAY

l         TIME_HOUR

l         TIME_MIN

l         TIME_SEC

l         TIME_WDAY

l         TIME

l         API_VERSION

l         THE_REQUEST

l         REQUEST_URI

l         REQUEST_FILENAME

l         IS_SUBREQ

还有一些特殊的位置:

POST_PAYLOAD – filter the body of the POST request

ARGS - filter arguments, the same as QUERY_STRING|POST_PAYLOAD

ARGS_NAMES – variable/parameter names only

ARGS_VALUES – variable/parameter values only

COOKIES_NAMES - cookie names only

COOKIES_VALUES - cookie values only

甚至还有更特殊的:

HTTP_header – search request header header

ENV_variable – search environment variable variable

ARG_variable – search request variable/parameter variable

COOKIE_name - search cookie with name name

 

参数过滤的特殊情况

位置标识符ARG_variable在和ARG位置合并使用的时候支持反转。例如:

SecFilterSelective "ARGS|!ARG_param" KEYWORD

会搜索除了名字是“param”的参数之外的所有的参数。

 

                                                                                               

Cookies

 

ModSecurity Cookies提供完全支持。默认情况下,版本 0 Cookies被使用 (Netscape 类型的cookies, Netscape-style cookies)。然而,ModSecurity 同时也支持版本 1 CookiesRFC 2965 中定义的Cookies. 你可以使用以下的格式,定义支持版本 1 cookies

 

# enable version 1 (RFC 2965) cookies

SecFilterCookieFormat 1

 

 

默认情况下,ModSecurity不会去尝试标准化cookie的名称及值。 然而,一些应用程序或者平台(例如:PHP)会对cookeie编码,以便你可以选择为cookie添加标准化技术。你可以通过对SecFilterNormalizeCookies指令的定义实现

 

SecFilterNormalizeCookies On

 

ModSesurity 1.8.7版本以前支持SecFilterCheckCookieFormat指令。在1.8.7以后的新版本中这条指令已经被取消。这条指令可以仍然用在配置文件中,但是不起任何作用。在1.9.X以后的版本中这条指令已经被完全取消。

 

输出过滤(Output filtering

MoSecurity Apache 2版本中支持输出过滤。默认情况下,输出过滤是被禁止的,如果你想要使用必需首先打开这个选项:

 

SecFilterScanOutput On

 

之后,使用特殊变量OUTPUT简单添加选择过滤器:

SecFilterSelective OUTPUT "credit card numbers"

 

http://www.webkreator.com/php/许多和我一起研究这些朋友知道我对防止PHP致命错误( fatal errors)有些无能为力。我花了很长时间去研究防止PHP致命错误信息泄漏给用户。 (×××)(参考:http://www.webkreator.com/php/configuration/handling-fatal-and-parse-errors.html

但是现在,最终在这方面我不用太担心了。以下的指令可以从返回信息(response的主体文件中捕获PHP输出错误,而不是从单独的错误回应(response)中捕获,并且执行定制的PHP脚本(同时通报应用程序管理员)。

SecFilterSelective OUTPUT "Fatal error:" deny,status:500

ErrorDocument 500 /php-fatal-error.html

你应该注意到尽管你可以混合输入输出过滤器,但是它们不能在同一时间执行。输入过滤器在一个请求被Apache处理之前被执行。输出过滤器在Apache完成请求处理以后被执行。

 

动作(Actionsskipnext chain不能在输出(output)过滤器工作。输出过滤仅仅用于纯文本和HTML输出的过滤。添加常规的二进制内容的表达式(例如:Image)将仅仅会使服务器慢下来(~~~~~~.ModSecurity 能基于它的mime类型有选择的添加输出过滤给响应(responses)。使用SecFilterOutputMimeTypes指令你能告诉它哪一个mime 类型去监视:

SecFilterOutputMimeTypes "(null) text/html text/plain"

上面的一个简单ModScurity的配置实例会给纯文本文件HTML文件,、和mime类型不是被特殊的"(null)"位置的文件添加输出过滤。使用输出缓冲将使ModSecurity 保持完整的内存中的页输出,无论它本身有多大。内存开销是页长度的2倍以上。

 

动作(Actions

 

有以下几种动作:

 

主动作(action)将生成一个决策决定是否去继续请求或者拒绝请求。有且只有一个主动作存在。如果你在parameter里设置了几个主动作,最后一个动作将被执行。主动作为deny,

pass, redirect(转向).

第二动作将由主动作在决策中作定义,并在一个独立匹配的过滤器(filter)中被执行。在第二动作中可以是任何值,例如:exec 是一个第二动作。

 

下面的动作能改变相应的规则的流向,因为过滤引擎能跳到其他规则,或者跳到一个或几个规则。实现动作是chain skip.

 

参数不是真正的动作,而是一个针对过滤器的附加参数的方法(method)。有些参数能被用于真正的动作。例如:status deny提供一个响应编码。

 

指定动作(Specifying actions

 

你可以把动作放在三个地方。一个是SecFilterDefaultAction指令,在这里你可以定义你想在大多数过滤匹配中被执行的动作:

SecFilterDefaultAction "deny,log,status:500"

这个例子定义了一个由三个动作组成的动作列表。逗号用与在列表中分开动作。开始的两个动作是由单个的单词组成。但是第三个动作需要一个参数,用冒号把参数和动作名分隔开。

 

你也能指定过滤器预处理动作。做为一个可选参数,有两个过滤器指令可以接受一个指定动作的设置(SecFilter SecFilterSelective)。当使用的过滤器预处理动作是一个伪装请求时,这个请求在过滤匹配器中将会被拒绝。如果你想容许请求继续,你必须明确的设置一个non-fatal动作(例如:log,pass”.

对于1.8.6,如果你指定了non-fatal为默认动作(例如:log,pass”.,那么在mod_security初始化的阶段它就会被忽略。初始化阶段仅仅用来收集关于请求的信息,容许non-fatal动作是因为一些请求块错误(在mod_security中对于内部处理)。因此,如果你想mod_security在探测"detect-only"模式下运行,你应该禁止所有固有确认(检查 URL encoding, Unicode, cookie 格式化, byterange).

内置动作(Built-in actions

pass

容许在过滤匹配中请求被继续。这个动作用在当你想纪录一个匹配(match)而不并不想执行其他的动作时候。

SecFilter KEYWORD "log,pass"

allow

 

在这个动作执行后,请求将被容许通过,并且没有别的过滤器被重试。

# stop filter processing for request coming from

# the administrator's workstation

SecFilterSelective REMOTE_ADDR "^192.168.2.99$" allow

 

deny

 

在过滤匹配中中断一个请求处理。除非status动作也在使用。ModSecurity 会立即返回一个HTTP 500错误代码。如果一个请求被拒绝,文件头mod_security-action将会被添加到请求文件头列表中去。这个文件头包括code使用状态。

 

Status

 

当一个请求被拒绝的时候使用替代HTTP状态代码。

下面的规则:

SecFilter KEYWORD "deny,status:404"

当他被触发的时候将返回"Page not found"信息。如果在配置里有这条规则Apache 错误提示信息会被触发。所以,如果你以前已经为一个设定的状态定义了一个定制的错误页,那么它将会被执行并且给用户显示。

 

Redirect

 

在过滤匹配中可以重定向用户到指定的URL.例如:

SecFilter KEYWORD "redirect:http://www.modsecurity.org"

这个配置指令不考虑HTTP状态代码或者deny关键字。注意,URL中不能包括逗号。

 

Exec

 

在过滤匹配中执行二进制文件,需要在指令中添加要执行的文件的完整路径,例如:

SecFilter KEYWORD "exec:/home/ivanr/report-attack.pl"

如果这条指令存在,它对主动作不产生影响。这个动作总是调用不带参数的脚本,但是提供所有在环境中的信息。所有的通用的CGI环境变量都将放在这里。你可以在预过滤匹配中执行一个二进制文件。完成以后将增加一个mod_security-executed的报头到请求包列表中。你应该理解调用线程会导致在所有的线程将会复制到新的线程。在多进程选项中调用会导致更大的开销。

 

log

 

日志过滤用于纪录Apache的错误日志。

 

nolog

 

不纪录Apache的错误日志。

 

skipnext

 

这个动作容许你跳过一个或者多条规则。当你设定在特殊情况下,不需要完成一些校验,你可以用这个动作。默认情况下,这个动作会跳过下一条规则。如果你指定了可选参数,它能跳过任何规则的数目。

SecFilterSelective ARG_p value1 skipnext:2

SecFilterSelective ARG_p value2

SecFilterSelective ARG_p value3

 

Chain

 

链接规则容许你将几条规则链接到到一起。只有在链接中的最后条规则会影响请求,在它前面的所有的规则也必须被匹配。

在这里举一个例子:

我想限定管理员用户只能从指定的IP地址登陆。但是,管理员登陆界面是和别的用户共享的,并且我不能用标准的Apache界面。因此,我用了这两条规则:

SecFilterSelective ARG_username admin chain

SecFilterSelective REMOTE_ADDR "!^YOUR_IP_ADDRESS_HERE$"

如果参数username存在并且它的值是admin那么第一条规则匹配。之后第二条规则被执行,并且它会尝试用远程请求地址和单独的IP地址匹配。如果请求地址不匹配(注意:以!做为开始),则请求被决绝。

 

pause

 

在响应请求之前可以暂停几毫秒。这对于减速或者完全拒绝一些web扫描是非常有用的。一些扫描软件如果暂停过长它就直接放弃扫描。

在一种情况使用这个选项要特别的小心。每一个web服务器的安装配置是限定的,在任何时候它都需要提供最大请求数。如果弱扫描软件是并行执行请求,使用这个选项有一个较长延迟时间,可以创建一个“voluntary”的拒绝服务攻击。

 

mod_security增加的请求报头(Request Header

 

只要有可能,ModSecurity会在请求报头中增加信息,从而容许你的脚本发现并使用它。显然,为了你的脚本能够被执行,你必须配置ModSecurity避免它拒绝请求。乍看起来,可能有点奇怪我使用请求报头,而不是其他的手段,比如环境变量,来达到这个目的。虽然使用环境变量看起来更规范一些,输入报头对于使用ErrorDocument指示(见下文)来执行的脚本来说总是可见的,凡是对于环境变量则不然。

这是添加的报头的列表:

a)         mod_security-executed; 被执行的二进制文件的路径

b)        mod_security-action; 返回的状态码

c)        mod_security-message; 监测到的错误信息,和记录在error_log中的信息相同。

使用ErrorDocument来处理规则匹配

如果你的配置返回了HTTP状态码500,而且你配置Apache使其是要在这个状态出现时都执行一个自定义的脚本(比如ErrorDocument 500 / error500.php)来使你能够使用自己喜欢的脚本引擎来相应这些错误。关于错误的信息会放在环境变量REDIRECT_*HTTPD_MOD_SECURITY_*里(正如这里描述的:http://httpd.apache.org/docs-2.0/customerror.

html)。

ModSecurity和你的防火墙交流

某些情况下,检测到一个显著的危险攻击或是一系列攻击后,你会希望组织同一个来源的进一步的攻击。你可以通过修改防火墙使其拒绝从某一特定的IP地址发出的全部流量来做到这一点(我在iptables的基础上写了一个助手脚本,可以在这里下载:http://www.apachesecurity.net)。

这个方法可能非常危险因为它会导致拒绝服务(DoS)攻击。比如,一个攻击者可以使用一个代理来发起攻击。拒绝来自一个代理服务器的所有请求是很危险的事,因为所有合法的用户也会收到影响。

因为多数代理会发送描述原始客户端的信息(可以在下面的网址找到有关的信息:http://www.webkreator.com/cms/view.php/1685.html,在“Stop Hijacking”一节),我们可以试着聪明一点,找到真正的IP地址。虽然这样能工作,但是考虑下面的情况:

l         攻击者在直接访问应用程序,但是伪装成一个代理服务器,引用一个随机的(或者合法的)IP地址作为“真实的”源IP地址。如果我们基于推断出的信息开始拒绝请求,攻击者会简单的替换IP地址然后继续攻击。结果是我们禁止了合法的用户,但是攻击者仍然在自由地寻找应用程序地漏洞。

所以只有在下列情况下有用:你不允许通过代理访问你的应用程序,或者只允许通过广为人知的,更重要的,可信任的代理访问。

如果你仍然希望基于IP地址来禁止请求(不理会我们所有的警告),你需要写一个小的脚本,在过滤器匹配的时候执行。这个脚本应该从环境变量里取出攻击者的IP地址,然后调用iptables或者ipchains来禁止这些IP地址。在mod_security以后的版本中我们将会包含一个这样的脚本示例。