NginxへのModSecurityとOWASP CRSの導入:オープンソースWAF構築ガイド

Security tutorial - IT technology blog
Security tutorial - IT technology blog

深夜2時14分。PagerDutyのアラートがけたたましく鳴り響き、Grafanaのダッシュボードを見るとバックエンドデータベースのCPU使用率が100%に張り付いています。tail -f /var/log/nginx/access.logを確認すると、インデックスのない検索エンドポイントに対して毎秒3,200件ものPOSTリクエストが殺到していました。

攻撃者は' OR 1=1--といった典型的なSQLインジェクションのプローブに加え、/etc/passwdを狙ったパストラバーサルのスキャンを仕掛けています。WAFレイヤーが存在しない場合、こうした悪意あるトラフィックは直接アプリケーションワーカーへと到達します。不正なクエリがワーカーのスレッドを次々と占有し、あっという間に100接続のデータベース接続プールを枯渇させてしまいます。夜明けを迎える前に、Nginx上でインライン動作するWeb Application Firewallを立ち上げなければなりません。

クラウドエッジWAF vs. Nginxホスト型ModSecurity

オリジンサーバーに激しい攻撃が仕掛けられた際、不正なパケットを遮断する方法は主に2つあります。アップストリームのクラウドファイアウォールを利用するか、あるいはModSecurityのようなホスト内エンジンを利用するかです。

どちらの方式も既知の脆弱性シグネチャと照合してペイロードを評価しますが、アーキテクチャ上の動作レイヤーが異なります:

  • クラウドWAF(AWS WAF、Cloudflare、Fastly):DNSおよびCDNエッジに配置されます。トラフィックがVPSやベアメタルのネットワークインターフェースに到達する前にリクエストを評価します。ポリシーは各プロバイダーの管理コンソールやTerraformスクリプト経由で管理します。
  • ホスト型ModSecurity v3(libmodsecurity + Nginxコネクタ):動的モジュールとしてNginxインスタンス内部で動作します。リクエストが内部のアプリケーションソケットに渡される直前に、ヘッダー、パラメータ、クッキー、リクエストボディを評価します。

日常的な運用における両アプローチの比較は以下のとおりです:

運用上の比較項目 クラウドエッジWAF ホスト型ModSecurity + OWASP CRS
導入・セットアップ DNSを切り替えるだけで迅速に導入可能だが、外部ルーティングや証明書の共有が必要。 Nginxへの動的モジュールのコンパイルまたはロードが必要。
データプライバシーとコンプライアンス 復号されたTLSペイロードが外部のCDNベンダーを経由する。 サードパーティへのデータ露出ゼロ。ペイロードは完全にホストのRAM内でのみ処理される。
帯域消費型の大量攻撃(DDoS) 物理ネットワークインターフェースが飽和する前に、マルチギガビット規模の攻撃トラフィックを吸収できる。 サーバーの上り/下り回線帯域が攻撃で飽和した場合、防御できない。
ルールエンジンの制御性 ベンダーのルール制限や有償プランの制約を受ける。 SecRuleディレクティブ、PCRE正規表現、Lua、生CRSルールファイルを完全に制御可能。
コストの予測可能性 リクエスト数(100万件単位)や検査帯域に応じた従量課金。急激なトラフィック急増時には高額化のリスクがある。 既存のCPUコア上で動作する完全無料のオープンソースソフトウェア。

エンジン内検査とエッジフィルタリングの比較・検討

Nginx内部でファイアウォールを稼働させることには大きなメリットがある一方で、運用上の責任も伴います。

Nginx上でModSecurityを動かすメリット

  • データの主権(Data Sovereignty):サードパーティのプロキシが顧客のペイロード、セッションクッキー、認証トークンを読み取ることは一切ありません。HIPAA、PCI-DSS、GDPRなどの厳格なデータ隔離要件がある場合でも、コンプライアンス上の摩擦を回避できます。
  • 内部コンテキストの把握:ModSecurityは、外部CDNからは見えない内部ルーティングヘッダー、マイクロサービスのパス書き換え、アップストリームのプロキシヘッダーまで検査できます。
  • コストの確実性:トラフィックが急増しても、月末に想定外の多額な検査費用を請求される心配がありません。

Nginx上でModSecurityを動かすデメリット

  • CPU負荷とレイテンシ:リクエストボディに対する正規表現のパース処理には計算リソースが必要です。標準的なワークロードにおいて、複雑なルールセットを実行すると通常HTTPリクエストごとに2ms〜8msの処理レイテンシが発生します。
  • 誤検知(False Positives):デフォルトのルールでは、正当なJSONペイロードやユーザーが投稿したMarkdownテキストまでブロックしてしまうことがあります。正常なトラフィックを通すための除外ルールを策定する必要があります。
  • バイナリの結合度:コネクタモジュールは、稼働中のNginxの正確なABIとリンクします。Nginxパッケージのマイナーアップグレード時であっても、バイナリの不一致を防ぐためにngx_http_modsecurity_module.soの再コンパイルが必要になる場合があります。

推奨アーキテクチャ:Libmodsecurity3とOWASP CRS v4

インシデント発生中に場当たり的なカスタムルールを急造するのは避けましょう。ゼロデイ攻撃やOWASP Top 10の脆弱性を遮断するための実績ある基盤となるのが、ModSecurity v3とOWASP Core Rule Set(CRS)v4の組み合わせです。

Ubuntu 22.04および24.04 LTSサーバーでは、次の3つの要素を中心に構築します:

  • コアエンジン:共有C++ライブラリとしてビルドされたlibmodsecurity3。
  • Nginxコネクタ:既存のNginxパッケージに動的ロードされるngx_http_modsecurity_module.so。
  • 検知ルール:パラノイアレベル1(Paranoia Level 1)のアノマリースコアリングモードで動作するOWASP CRS v4。

ステップ別の導入手順

エンジンのコンパイル、Nginxへのコネクタのロード、ルールの有効化までの手順を順を追って解説します。

ステップ1:ビルド依存パッケージのインストール

PCRE2、XMLパース、JSON処理に必要なコンパイラ、ビルドツール、開発用ヘッダーをインストールします:

sudo apt-get update
sudo apt-get install -y apt-utils autoconf automake build-essential \
    git libcurl4-openssl-dev libgeoip-dev liblmdb-dev libpcre2-dev \
    libpcre3-dev libtool libxml2-dev libyajl-dev pkgconf zlib1g-dev

ステップ2:Libmodsecurity v3のビルドとインストール

スタンドアロンのv3ブランチを取得し、システムの標準ライブラリパスにコンパイルしてインストールします:

cd /usr/local/src
sudo git clone --depth 1 -b v3/master https://github.com/owasp-modsecurity/ModSecurity.git
cd ModSecurity
sudo git submodule init
sudo git submodule update
sudo ./build.sh
sudo ./configure
sudo make -j$(nproc)
sudo make install
sudo ldconfig

これによりlibmodsecurity.soがコンパイルされ、/usr/local/modsecurity/lib/配下に配置されます。

ステップ3:動的Nginxコネクタのコンパイル

コネクタモジュールは、稼働中のNginxバイナリと完全に一致していなければなりません。現在のパッケージバージョンを確認します:

nginx -v
# 出力: nginx version: nginx/1.24.0

一致するソースコードをダウンロードし、--with-compatオプションを指定して動的モジュールを設定・コンパイルします:

cd /usr/local/src
sudo git clone --depth 1 https://github.com/owasp-modsecurity/ModSecurity-nginx.git

wget http://nginx.org/download/nginx-1.24.0.tar.gz
tar -xzvf nginx-1.24.0.tar.gz
cd nginx-1.24.0

./configure --with-compat --add-dynamic-module=/usr/local/src/ModSecurity-nginx
make modules

sudo cp objs/ngx_http_modsecurity_module.so /etc/nginx/modules/

ステップ4:ModSecurityとOWASP CRS v4の設定

設定ファイルとルールパッケージを配置するために、/etc/nginx/modsec/内にクリーンなディレクトリ構成を作成します:

sudo mkdir -p /etc/nginx/modsec
cd /usr/local/src/ModSecurity
sudo cp modsecurity.conf-recommended /etc/nginx/modsec/modsecurity.conf
sudo cp unicode.mapping /etc/nginx/modsec/

cd /etc/nginx/modsec
sudo git clone --depth 1 -b v4.0/master https://github.com/coreruleset/coreruleset.git
sudo cp coreruleset/crs-setup.conf.example coreruleset/crs-setup.conf

コア設定、セットアップ設定、CRSルールを読み込むためのメインエントリーポイント/etc/nginx/modsec/main.confを作成します:

cat << 'EOF' | sudo tee /etc/nginx/modsec/main.conf
Include /etc/nginx/modsec/modsecurity.conf
Include /etc/nginx/modsec/coreruleset/crs-setup.conf
Include /etc/nginx/modsec/coreruleset/rules/*.conf
EOF

ステップ5:エンジンモードの調整と監査ログの設定

本番切り替え時に過度なブロックによって正規ユーザーのセッションを遮断してしまわないよう注意が必要です。/etc/nginx/modsec/modsecurity.confを開き、エンジンディレクティブを確認します:

sudo sed -i 's/SecRuleEngine DetectionOnly/SecRuleEngine On/' /etc/nginx/modsec/modsecurity.conf

独自のペイロードスキーマを持つ大量トラフィックのAPIを運用している場合は、まず30〜60分ほどDetectionOnly(検知のみ)に設定しておきましょう。ログに記録された検知内容を確認し、誤検知をチューニングしてからディレクティブをOnに切り替えます。

サーバーメンテナンス中に管理インターフェースへのアクセスを制限し、認証情報ボールトのキーをローテーションする際、サーバー用パスワードの生成には toolcraft.app/ja/tools/security/password-generator のパスワードジェネレーターを活用しています。完全にブラウザ内で動作するため、データがネットワーク経由で送信される心配がありません。本番環境の管理画面を高エントロピーなシークレットで保護したら、次はNginxとの統合に進みましょう。

ステップ6:モジュールのロードとバーチャルホストへの適用

/etc/nginx/nginx.confの先頭行にモジュール読み込みディレクティブを追加します:

load_module modules/ngx_http_modsecurity_module.so;

user www-data;
worker_processes auto;
pid /run/nginx.pid;

対象となるバーチャルホストのserverブロック内でModSecurityを有効化します:

server {
    listen 80;
    server_name api.example.com;

    modsecurity on;
    modsecurity_rules_file /etc/nginx/modsec/main.conf;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

設定テストを実行し、ダウンタイムなしでワーカープロセスをリロードします:

sudo nginx -t && sudo systemctl reload nginx

ステップ7:ブロック動作と監査ログの確認

外部クライアントから模擬的なパストラバーサルのプローブを送信し、Nginxがリクエストを正しく遮断するか検証します:

curl -i "http://api.example.com/?exec=/etc/passwd"

リバースプロキシが即座にペイロードを拒絶し、403 Forbiddenステータスを返すはずです:

HTTP/1.1 403 Forbidden
Server: nginx
Date: Thu, 15 Oct 2026 02:35:10 GMT
Content-Type: text/html
Content-Length: 153
Connection: keep-alive

/var/log/nginx/error.logでログに記録された検知内容を確認します:

sudo tail -n 20 /var/log/nginx/error.log

ルール930110または930120が発火していることが確認できます:[id "930110"] [msg "Path Traversal Attack (/../)"] [data "Matched Data: /etc/passwd found"] [severity "CRITICAL"]。パケットはアップストリームのワーカーに到達する前に破棄され、データベースの接続プールが解放され、アプリケーションのレイテンシが正常に戻ります。

Share: