LoginSignup
2
3

More than 1 year has passed since last update.

特定の文字列をパラメタに含むリクエストを遮断する簡易的なWAFをつくるメモ(ModSecurity)

Posted at

はじめに

ちょっとした検証とか確認でWAFをさくっと作りたいと思ったので、その時のメモ。
owasp/modsecurityのdockerイメージがあることがわかったものの、用意されている環境変数一覧の中に、特定の文字列を含むようなリクエストを遮断するような設定をする変数がなかったのがきっかけです。

やること

OWASPで用意しているModSecurityのdockerイメージを使って、"test"というワードをパラメータに含むGET/POSTリクエストを遮断するWAFを作成します。
ModSecurityのイメージはapache, nginx, IISの3種類用意されていますが、今回はnginxを使用します。
もっと本格的なWAFを作ろうと思うと、Core Rule Set(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、nginxwafの後段に配置するアプリケーションサーバを想定しています。

docker-compose.yml
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ディレクトリ以下にはnginx用の設定ファイル3つを配置しています。
waf経由でリクエストが来たときには、「nginx-succeeded」という文字列を表示するようにしています。
起動時の疎通確認用にlocation /の設定をしています。
POSTでも同じ結果を返すようにerror_pageの設定を入れています。

nginx/default.conf
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/index.html
nginx
nginx/succeeded.html
nginx-succeeded

WAF(ModSecurity on nginx)の設定

nginxの設定(default.conf)の内容を↓に載せています。
locationについては、http://localhost/nginxのリクエストのときに後段のnginxにリクエストを渡すような設定にしています。
ModSecurityでリクエストが遮断されたときにはhttp status codeが403になるので、このとき「modsecurity-blocked!」という文字列が表示されるようにしています。

modsecurity/default.conf
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の設定が↓になります。
重要なのが、以下の2点です。

  • SecRuleEngine On ... デフォルトがDetectionOnlyになっていて、検知だけして遮断しない設定なので、遮断するようにOnを指定。
  • SecRule ARGS_NAMES "test" ... このSecRuleがdockerコンテナに渡す環境変数として用意されていないので、configファイルを書いてコンテナに渡すようにしました。この設定でGETやPOSTなどのリクエストのパラメータ名が"test"であれば、ログ出力して遮断する設定にしています。POSTだとRequest Bodyを見ないといけないので、"phase:2"を指定しているところが注意点。
modsecurity/modsecurity.conf
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/index.html
modsecurity
modsecurity/custom-error.html
modsecurity-blocked!

動作確認

docker-compose up -dで起動したあと、Google ChromeのAdvanced REST Clientで動作確認しました。

modsecurity.gif

まとめ

簡単なWAFを作ってみました。
SecRuleのところは色んなパラメータがあったり、正規表現が使えたりともっとできることは多いですが、ARGS_POSTがうまく動かなかったりしてつまりました。結果的にはARGSARGS_NAMESで解決したのですが、今度また触る機会があれば、もうちょっと調べてみようと思います。

参考

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3