0x01 前言

在安装完ModSecurity我发现日志里会出现Permission denied的内容,却并不影响服务的正常运行。经过多番查找,终于找到了问题点。

0x02 BUG

安装完ModSecurity后进行测试,查看日志会发现以下内容:

2017/09/07 10:45:40 [error] 8547#0: [client 10.1.1.16] ModSecurity: Audit log: Failed to unlock global mutex: Permission denied [hostname "modsecurity"] [uri "/favicon.ico"] [unique_id "7cAcAcAcAcAcAcAcAcAcAcAc"]

0x03 DEBUG

首先正常情况下的日志是这样的:

2017/09/07 11:09:57 [error] 8551#0: [client 10.1.1.16] ModSecurity: Access denied with code 403 (phase 2). Pattern match "^[\\d.:]+$" at REQUEST_HEADERS:Host. [file "/usr/local/nginx/modsecurity/owasp-modsecurity-crs/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf"] [line "810"] [id "920350"] [rev "2"] [msg "Host header is a numeric IP address"] [data "10.1.1.113"] [severity "WARNING"] [ver "OWASP_CRS/3.0.0"] [maturity "9"] [accuracy "9"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-protocol"] [tag "OWASP_CRS/PROTOCOL_VIOLATION/IP_HOST"] [tag "WASCTC/WASC-21"] [tag "OWASP_TOP_10/A7"] [tag "PCI/6.5.10"] [hostname "modsecurity"] [uri "/favicon.ico"] [unique_id "bcAcAcAcAcAEScIcAcAcAcAc"]

以上日志格式可以在nginx的错误日志里找到,例如我的:

[root@modsecurity 20170907]# tail -n 1 /var/log/nginx/error.log 
2017/09/07 11:09:57 [error] 8551#0: [client 10.1.1.16] ModSecurity: Access denied with code 403 (phase 2). Pattern match "^[\\d.:]+$" at REQUEST_HEADERS:Host. [file "/usr/local/nginx/modsecurity/owasp-modsecurity-crs/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf"] [line "810"] [id "920350"] [rev "2"] [msg "Host header is a numeric IP address"] [data "10.1.1.113"] [severity "WARNING"] [ver "OWASP_CRS/3.0.0"] [maturity "9"] [accuracy "9"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-protocol"] [tag "OWASP_CRS/PROTOCOL_VIOLATION/IP_HOST"] [tag "WASCTC/WASC-21"] [tag "OWASP_TOP_10/A7"] [tag "PCI/6.5.10"] [hostname "modsecurity"] [uri "/favicon.ico"] [unique_id "bcAcAcAcAcAEScIcAcAcAcAc"]

另外在modsecurity.conf里还有一个日志路径和类型的参数:

SecAuditLogType Serial
SecAuditLog /var/log/modsec_audit.log

以上解释可以在以下地址中找到:

而在modsec_audit.log文件中的日志一般是这样的:

--46e97f77-A--
[07/Sep/2017:10:45:40 +0800] 7cAcAcAcAcAcAcAcAcAcAcAc 10.1.1.16 59774 127.0.0.1 80
--46e97f77-B--
GET /favicon.ico HTTP/1.1
Host: 10.1.1.113
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
Accept: image/webp,image/apng,image/*,*/*;q=0.8
Referer: http://10.1.1.113/?../../passwd
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8

--46e97f77-F--
HTTP/1.1 403
Content-Type: text/html
Content-Length: 577
Connection: keep-alive

--46e97f77-H--
Message: Access denied with code 403 (phase 2). Pattern match "^[\\d.:]+$" at REQUEST_HEADERS:Host. [file "/usr/local/nginx/modsecurity/owasp-modsecurity-crs/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf"] [line "810"] [id "920350"] [rev "2"] [msg "Host header is a numeric IP address"] [data "10.1.1.113"] [severity "WARNING"] [ver "OWASP_CRS/3.0.0"] [maturity "9"] [accuracy "9"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-protocol"] [tag "OWASP_CRS/PROTOCOL_VIOLATION/IP_HOST"] [tag "WASCTC/WASC-21"] [tag "OWASP_TOP_10/A7"] [tag "PCI/6.5.10"]
Message: Audit log: Failed to lock global mutex: Permission denied
Action: Intercepted (phase 2)
Apache-Handler: IIS
Stopwatch: 1504752340000137 137800 (- - -)
Stopwatch2: 1504752340000137 137800; combined=582, p1=192, p2=357, p3=0, p4=0, p5=33, sr=31, sw=0, l=0, gc=0
Producer: ModSecurity for nginx (STABLE)/2.9.2 (http://www.modsecurity.org/); OWASP_CRS/3.0.2.
Server: ModSecurity Standalone
Engine-Mode: "ENABLED"

--46e97f77-Z--

问题就出在modsec_audit.log这个日志里。

你会发现除非将nginx的用户修改为root,否则哪怕将文件权限设为777也会出现这个错误。

这是因为nginx和apache都是多线程的,每条线程都需要写入日志,在这种情况下就会发生A线程打开了文件,B线程就无法打开的情况。

那么只好将错误单独写入文件,让每条线程都有权限建立文件即可。

首先需要创建一个给nginx使用的用户与用户组:

#创建用户组
[root@modsecurity ~]# groupadd nginx 

#创建用户
[root@modsecurity ~]# useradd -M -s /sbin/nologin -n nginx -g nginx

然后将nginx的用户修改为nginx:

user  nginx;

还需要新建一个日志文件夹并赋予相关权限:

#新建文件夹
[root@modsecurity ~]# mkdir /var/log/modsecurity/

#修改所有用户与用户组
[root@modsecurity ~]# chown nginx. /var/log/modsecurity

#查看相关文件夹
[root@modsecurity ~]# ll /var/log/ | grep modsecurity
drwxr-xr-x  3 nginx  nginx       21 Sep  7 10:41 modsecurity

最后修改modsecurity.conf文件:

#注释以下内容
#SecAuditLogType Serial
#SecAuditLogStorageDir /opt/modsecurity/var/audit/

#增加以下内容
SecAuditLogType Concurrent
SecAuditLogStorageDir /var/log/modsecurity

完成后reload nginx即可。

0x04 测试

完成修改并重新加载nginx后再次测试,会发现再也没有Permission denied的日志了。

而在日志目录里则会以日期为名称的文件夹,文件夹里会有以小时为名称的文件夹,文件夹下则是以事件id为名称的日志文件:

[root@modsecurity ~]# tree /var/log/modsecurity/
/var/log/modsecurity/
└── 20170907
    ├── 20170907-1041
    │   ├── 20170907-104154-AcACAcAcAcAcAcAcAcAcAcHc

该日志文件和modsec_audit.log日志里的格式一致。

修改完配置文件后,modsec_audit.log日志里的日志格式会发生变化,会变成非常简洁的格式:

modsecurity 10.1.1.16 -  [07/Sep/2017:11:09:57 +0800] "GET /?../../passwd HTTP/1.1" 403 0 "-" "-" AcAcwcOcxcAcAcAAAqjcAcOc "-" /20170907/20170907-1109/20170907-110957-AcAcwcOcxcAcAcAAAqjcAcOc 0 1804 md5:81cbec4e20652d8948e5967b55d821d4

而nginx错误日志里的格式则保持不不变。

0x05 结语

日志记录方式SecAuditLogType修改为Concurrent还一个好处,当需要将日志存储在云端,将不需要手动将日志截断,也不需要担心日志是否正在被写入。

其实这个问题并不是造成任何影响,日志还是可以被正常记录。唯一不好的是会增加日志文件的大小。

-更新:2017-09-21

modsecurity与新版nginx不兼容的问题已在modsecurity v3中解决,请参考以下文章进行编译安装: