在这个备忘录(ModSecurity)中,创建一个简易的WAF来阻断包含特定字符串参数的请求
首先
因为想要进行一些简单的验证和确认,我想快速地构建一个WAF,这是当时的备忘录。
尽管发现了owasp/modsecurity的Docker镜像,但在提供的环境变量列表中,并没有设置阻断包含特定字符串的请求的变量,这是触发的原因。
要做的事
使用OWASP提供的ModSecurity的Docker镜像,创建一个能够阻止包含参数中包含“test”关键词的GET/POST请求的WAF。
ModSecurity提供了apache、nginx和IIS三种不同的镜像,但本次我们将使用nginx。
如果想要创建一个更加完善的WAF,我建议加入包含核心规则集(CRS)在内的配置,但本次不会涉及到那些内容。
环境
% sw_vers
ProductName: macOS
ProductVersion: 11.6
BuildVersion: 20G165
% docker --version
Docker version 20.10.12, build e91ed57
% docker-compose --version
docker-compose version 1.29.2, build 5becea4c
做过的事情
最终准备的文件和目录如下所示。
% tree .
.
├── docker-compose.yml
├── modsecurity
│ ├── custom-error.html
│ ├── default.conf
│ ├── index.html
│ ├── log
│ └── modsecurity.conf
└── nginx
├── default.conf
├── index.html
└── succeeded.html
以下是docker-compose.yml文件的内容。
在这里,waf主要是指ModSecurity,nginx被配置为waf后端的应用程序服务器。
version: "3"
services:
waf:
image: owasp/modsecurity:nginx
ports:
- "8080:80"
restart: always
volumes:
- ./modsecurity/default.conf:/etc/nginx/conf.d/default.conf
- ./modsecurity/index.html:/var/www/html/index.html
- ./modsecurity/custom-error.html:/var/www/html/custom-error.html
- ./modsecurity/modsecurity.conf:/etc/modsecurity.d/modsecurity-override.conf
- ./modsecurity/log:/var/log/nginx
container_name: waf-nginx
networks:
- default
nginx:
image: nginx:1.20.2
ports:
- "80:80"
restart: always
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
- ./nginx/index.html:/var/www/html/index.html
- ./nginx/succeeded.html:/var/www/html/nginx/index.html
container_name: nginx
networks:
- default
networks:
default:
应用服务器(nginx)的配置
在nginx目录下,我们配置了3个nginx的设置文件。
当请求通过waf进来时,我们显示”nginx-succeeded”这个字符串。
为了进行启动时的连通性检查,我们进行了location /的设置。
我们还通过配置error_page来使POST请求返回相同的结果。
server {
listen 80;
listen [::]:80;
server_name localhost;
location /nginx/ {
root /var/www/html;
index index.html;
}
location / {
root /var/www/html;
index index.html;
}
error_page 405 =200 $uri;
}
nginx
nginx-succeeded
WAF(基于nginx的ModSecurity)的设置
以下是nginx的配置(default.conf)内容。关于location,当收到http://localhost/nginx的请求时,会将请求传递给后端的nginx。如果请求被ModSecurity拦截,HTTP状态码将变为403,并显示字符串”modsecurity-blocked!”。
server {
listen 80;
listen [::]:80;
server_name localhost;
location / {
root /var/www/html;
index index.html;
}
location /nginx {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect http:// https://;
proxy_pass http://nginx/nginx/;
}
error_page 403 /custom-error.html;
location = /custom-error.html {
root /var/www/html;
internal;
}
}
以下是ModSecurity的配置。
其中两个重要点如下。
SecRuleEngine On … デフォルトがDetectionOnlyになっていて、検知だけして遮断しない設定なので、遮断するようにOnを指定。
SecRule ARGS_NAMES “test” … このSecRuleがdockerコンテナに渡す環境変数として用意されていないので、configファイルを書いてコンテナに渡すようにしました。この設定でGETやPOSTなどのリクエストのパラメータ名が”test”であれば、ログ出力して遮断する設定にしています。POSTだとRequest Bodyを見ないといけないので、”phase:2″を指定しているところが注意点。
SecRuleEngine On
SecRequestBodyAccess On
SecAuditEngine On
SecAuditLog /var/log/nginx/modsec_audit.log
SecAuditLogParts ABCFHZ
SecRule ARGS_NAMES "test" "id:3,phase:2,t:lowercase,deny,log"
modsecurity
modsecurity-blocked!
确认动作
我先运行了docker-compose up -d,然后使用Google Chrome的Advanced REST Client进行了操作确认。
总结
我已經製作了一個簡單的WAF。
雖然SecRule部分有很多參數,也可以使用正則表達式等更多功能,但ARGS_POST無法正常運行且使我遇到了困難。最終,我通過使用ARGS或ARGS_NAMES解決了這個問題,但如果再次有機會接觸,我會更深入地進行研究。
请参考
-
- https://qiita.com/housu_jp/items/1c0204c8cf0ce32a7605
-
- https://atmarkit.itmedia.co.jp/ait/articles/1409/18/news010_4.html
-
- https://coreruleset.org/docs/rules/creating/
-
- https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-(v2.x)
-
- https://hub.docker.com/r/owasp/modsecurity
- https://qiita.com/ryounagaoka/items/fd641e39a196b47db875