lua-resty-waf - OpenResty スタック上に構築された高性能 WAF
注記: lua-resty-waf は実質的に放棄されています。このプロジェクトは、Nginx 向け ModSecurity が実行可能な選択肢ではなかった時代に役割がありましたが、もはやそうではありません。2020年にプロジェクトを再生させる試みがありましたが、私にはこれを完了するリソースがありません。この作業は redux ブランチで部分的に完了しています。
lua-resty-waf は、OpenResty スタックを使用して構築されたリバースプロキシ WAF です。Nginx Lua API を使用して HTTP リクエスト情報を分析し、柔軟なルール構造に対して処理します。lua-resty-waf には、ModSecurity CRS を模倣したルールセットに加えて、初期開発とテスト中に作成されたいくつかのカスタムルール、および新興脅威に対する小さな仮想パッチセットが同梱されています。さらに、lua-resty-waf には既存の ModSecurity ルールを自動的に変換するツールが同梱されており、ユーザーは新しいルール構文を学ぶことなく lua-resty-waf の実装を拡張できます。
lua-resty-waf は、もともと Robert Paprocki が Western Governor's University での修士論文のために開発しました。
lua-resty-waf は、いくつかのサードパーティ製 resty Lua モジュールを必要としますが、これらはすべて lua-resty-waf に同梱されているため、個別にインストールする必要はありません。lua-resty-waf は、OpenResty ソフトウェアバンドルを実行しているシステムにインストールすることをお勧めします。lua-resty-waf は、別々の Nginx ソースと Nginx Lua モジュールパッケージを使用して構築されたプラットフォームではテストされていません。
最適な正規表現コンパイルパフォーマンスを得るには、JIT コンパイルをサポートするバージョンの PCRE を使用して Nginx/OpenResty をビルドすることをお勧めします。OS がこれを提供しない場合、JIT 対応の PCRE を Nginx/OpenResty ビルドに直接組み込むことができます。これを行うには、--with-pcre 設定フラグで PCRE ソースへのパスを指定します。例:```sh
PCREソースは[PCREウェブサイト](http://www.pcre.org/)からダウンロードできます。JIT対応のPCREライブラリを使用したOpenRestyの構築手順については、こちらの[ブログ記事](https://www.cryptobells.com/building-openresty-with-pcre-jit/)も参照してください。
## パフォーマンス
lua-resty-wafは、効率性とスケーラビリティを念頭に設計されています。Nginxの非同期処理モデルと効率的な設計を活用し、各トランザクションを可能な限り迅速に処理します。負荷テストによると、ModSecurity CRSの背後にあるロジックを模倣するように設計された、提供されているすべてのルールセットを実装したデプロイメントでは、リクエストあたり約300〜500マイクロ秒でトランザクションを処理します。これは[CloudflareのWAF](https://www.cloudflare.com/waf)が宣伝するパフォーマンスに相当します。テストは妥当なハードウェア構成(E3-1230 CPU、32 GB RAM、RAID 0の2 x 840 EVO)で実行され、最大で毎秒約15,000リクエストを処理しました。詳細については、[こちらのブログ記事](http://www.cryptobells.com/freewaf-a-high-performance-scalable-open-web-firewall)を参照してください。
lua-resty-wafのワークロードは、ほぼ完全にCPUバウンドです。Lua VM内のメモリフットプリント(`lua-shared-dict`に支えられた永続ストレージを除く)は、およそ2MBです。
## インストール
シンプルなMakefileが提供されています:```
# make && sudo make install
または、Luarocks 経由でインストール:```
lua-resty-waf は、[OPM](https://github.com/openresty/opm) パッケージマネージャーを利用します。これは最新の OpenResty ディストリビューションで利用可能です。クライアント OPM ツールを使用するには、システムの `PATH` 環境変数に `resty` コマンドラインツールが含まれている必要があります。
デフォルトでは、lua-resty-waf はアプリケーションに即座に影響を与えないよう SIMULATE モードで実行されることに注意してください。ルールアクションを有効にしたいユーザーは、運用モードを明示的に ACTIVE に設定する必要があります。
## 概要```lua
http {
init_by_lua_block {
-- use resty.core for performance improvement, see the status note above
require "resty.core"
-- require the base module
local lua_resty_waf = require "resty.waf"
-- perform some preloading and optimization
lua_resty_waf.init()
}
server {
location / {
access_by_lua_block {
local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
-- define options that will be inherited across all scopes
waf:set_option("debug", true)
waf:set_option("mode", "ACTIVE")
-- this may be desirable for low-traffic or testing sites
-- by default, event logs are not written until the buffer is full
-- for testing, flush the log buffer every 5 seconds
--
-- this is only necessary when configuring a remote TCP/UDP
-- socket server for event logs. otherwise, this is ignored
waf:set_option("event_log_periodic_flush", 5)
-- run the firewall
waf:exec()
}
header_filter_by_lua_block {
local lua_resty_waf = require "resty.waf"
-- note that options set in previous handlers (in the same scope)
-- do not need to be set again
local waf = lua_resty_waf:new()
waf:exec()
}
body_filter_by_lua_block {
local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
waf:exec()
}
log_by_lua_block {
local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
waf:exec()
}
}
}
}
ModSecurity SecRules ファイルをディスクから変換して初期化します。なお、ルールセットは add_ruleset で追加する必要があります(キーにはファイルの basename を指定する必要があります)。
例:```lua http { init_by_lua_block { local lua_resty_waf = require "resty.waf"
-- this translates and calculates a ruleset called 'ruleset_name'
local ok, errs = pcall(function()
lua_resty_waf.load_secrules("/path/to/secrules/ruleset_name")
end)
-- errs is an array-like table
if errs then
for i = 1, #errs do
ngx.log(ngx.ERR, errs[i])
end
end
}
server {
location / {
access_by_lua_block {
local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
-- in order to use the loaded ruleset, it must be added via
-- the 'add_ruleset' option
waf:set_option("add_ruleset", "ruleset_name")
}
}
}
}
さらに、`load_secrules` はオプションの2番目の引数として、さまざまな翻訳関数に渡すオプションのテーブルを受け取ることができます。認識されるオプションは次のとおりです:
* *path*: `@pmFromFile` などの演算子がデータファイルを検索するためのファイルシステムパスを定義します。このキーが定義されていない場合、カレントワーキングディレクトリ (`.`) が使用されます
* *force*: ルール変数の翻訳に失敗したときにエラーを出して中断しない
* *loose*: ルールアクションの翻訳に失敗したときにエラーを出して中断しない
* *quiet*: ルールアクションの翻訳に失敗したときにエラーや警告を出さない
この関数は、翻訳エラーを捕捉して後で処理するためのテーブルを3番目のオプションとして受け取ることもできます。このオプションが存在しない場合やテーブルでない場合、翻訳エラーは代わりにエラーログに記録されます。
### lua-resty-waf.init()
デフォルトで配布されるルールセットを介して利用可能になった内容に基づいて、ルールとルールセットの事前計算を実行します。この関数を呼び出すことが推奨されますが、必須ではありません (呼び出さない場合はわずかなパフォーマンス低下が生じます)。この関数はこのスコープ外で呼び出すべきではありません。
*例*:```lua
http {
init_by_lua_block {
local lua_resty_waf = require "resty.waf"
lua_resty_waf.init()
}
}
lua-resty-waf の新しいインスタンスを生成します。lua-resty-waf を実行するすべてのリクエストハンドラフェーズでこのメソッドを呼び出し、戻り値を使用して後続のオブジェクトメソッドを呼び出す必要があります。
例:```lua location / { access_by_lua_block { local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
}
}
### lua-resty-waf:set_option()
スコープ単位でオプションを設定します。
*例*:```lua
location / {
access_by_lua_block {
local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
-- enable debug logging only for this scope
waf:set_option("debug", true)
}
}
WAFを実行する前に、トランザクション変数を定義します(TX変数コレクションに格納されます)。これは、OWASP CRS などの複雑なルールセットで使用される変数を定義するために使用できます。
例:```lua location / { access_by_lua_block { local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
waf:set_var("FOO", "bar")
}
}
他の ModSecurity ルールと同様に、変数の存在は WAF 処理に機能的な変更をもたらしません。`TX` 変数を理解して使用する責任はルール作成者にあります。
### lua-resty-waf:sieve_rule()
特定のルールに対するコレクション除外を定義します。
*例*:```lua
location / {
access_by_lua_block {
local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
local sieves = {
{
type = "ARGS",
elts = "foo",
action = "ignore",
}
}
waf:sieve_rule("12345", sieves)
}
}
詳細と高度な使用例については、rule sieves のwikiページを参照してください。
ルールエンジンを実行します。デフォルトでは、エンジンは現在実行中のフェーズに従って実行されます。オプションのテーブルを渡すことができ、ユーザーは別のフェーズの実行を"モック"することができます。
例:```lua location / { access_by_lua_block { local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
-- execute according to access phase collections and rules
waf:exec()
}
content_by_lua_block {
local lua_resty_waf = require "waf"
local waf = lua_resty_waf:new()
-- execute header_filter rules, passing in a table of additional collections
-- this assumes the 'request_headers' and 'status' Lua variables were
-- declared and initialized elsewhere
local opts = {
phase = 'header_filter',
collections = {
REQUEST_HEADERS = request_headers,
STATUS = status,
}
}
waf:exec(opts)
}
}
### lua-resty-waf:write_log_events()
トランザクションから生成された監査ログエントリを書き込みます。これは、`exec` が `log_by_lua` ハンドラで呼び出された場合にのみ省略可能です。
*例*:```lua
location / {
log_by_lua_block {
local lua_resty_waf = require "resty.waf"
local waf = lua_resty_waf:new()
-- write out any event log entries to the
-- configured target, if applicable
waf:write_log_events()
}
}
デフォルト: なし
処理中に使用する追加ルールセットを追加します。これにより、ユーザーは同梱のルールディレクトリを上書きせずに、カスタムルールセットを実装できます。追加のルールセットは、lua_package_path 内にある "rules" というフォルダ内に配置する必要があります。
例:```lua http { -- the rule file 50000.json must live at -- /path/to/extra/rulesets/rules/50000.json lua_package_path '/path/to/extra/rulesets/?.lua;;';
server {
location / {
access_by_lua_block {
waf:set_option("add_ruleset", "50000_extra_rules")
}
}
}
}
`set_option` に値のテーブルを渡すことで、複数のルールセットを追加できます。ルールセット名は処理前にソートされることに注意してください。ルールセットは昇順(低い順から高い順)で処理されます。
### add_ruleset_string
*デフォルト*: なし
処理中に使用する追加のルールセットを追加します。これにより、同梱のルールディレクトリを上書きすることなく、ユーザーがカスタムルールセットを実装できます。ルールセットは、変換されたルールセット JSON 構造の形式で、Lua 文字列としてインラインで定義されます。
*例*:```lua
location / {
access_by_lua_block {
waf:set_option("add_ruleset_string", "70000_extra_rules", [=[{"access":[{"action":"DENY","id":73,"operator":"REGEX","opts":{},"pattern":"foo","vars":[{"parse":{"values":1},"type":"REQUEST_ARGS"}]}],"body_filter":[],"header_filter":[]}]=])
}
}
Note that ruleset names are sorted before processing, and must be given as strings. Rulesets are processed in a low-to-high sorted order.
デフォルト: false
allowed_content_types テーブルに含まれていない Content-Type ヘッダーが送信された場合に、lua-resty-waf がリクエストの処理を継続するように指示します。このようなリクエストのリクエストボディは lua-resty-waf によって処理されません (REQUEST_BODY コレクションは nil になります)。これにより、ユーザーは遭遇する可能性のあるすべての Content-Type ヘッダーを明示的にホワイトリストに登録する必要がなくなります。
例:```lua location / { access_by_lua_block { waf:set_option("allow_unknown_content_types", true) } }
### allowed_content_types
*デフォルト*: none
デフォルトのContent-Typeである `application/x-www-form-urlencoded` および `multipart/form-data` に加えて、許可される1つ以上のContent-Typeヘッダーを定義します。コンテンツタイプが `allowed_content_types` のいずれかに一致するリクエストは、`REQUEST_BODY` コレクションを(テーブルではなく)内容を含む単一の文字列に設定します。コンテンツタイプがこれらの値、`application/x-www-form-urlencoded`、または `multipart/form-data` のいずれにも一致しないリクエストは拒否されます。
*例*:```lua
location / {
access_by_lua_block {
-- define a single allowed Content-Type value
waf:set_option("allowed_content_types", "text/xml")
-- defines multiple allowed Content-Type values
waf:set_option("allowed_content_types", { "text/html", "text/json", "application/json" })
}
}
Note that mutiple set_option calls with a parameter of allowed_content_types will simply override the existing options table, so if you want to define multiple allowed content types, you must define them as a Lua table as shown above.
デフォルト: false
デバッグログを無効/有効にします。デバッグログステートメントは error_log に出力されます。デバッグログは非常にコストがかかるため、本番環境では使用しないでください。
例:```lua location / { access_by_lua_block { waf:set_option("debug", true) } }
### debug_log_level
*デフォルト*: ngx.INFO
デバッグログに使用される nginx のログレベル定数を設定します。
*例*:```lua
location / {
access_by_lua_block {
waf:set_option("debug_log_level", ngx.DEBUG)
}
}
デフォルト: ngx.HTTP_FORBIDDEN
リクエストを拒否するときに使用するステータスを設定します。
例:```lua location / { access_by_lua_block { waf:set_option("deny_status", ngx.HTTP_NOT_FOUND) } }
### disable_pcre_optimization
*デフォルト*: false
すべての `ngx.re.match`、`ngx.re.find`、`ngx.re.sub` 呼び出しから `oj` フラグを削除します。これは、古い PCRE ライブラリが使用されている場合に役立つことがありますが、深刻なパフォーマンス低下を引き起こすため、その使用は強く推奨されません。代わりに、ユーザーはモダンで JIT 対応の PCRE ライブラリを備えた OpenResty をビルドすることをお勧めします。
*例*:```lua
location / {
access_by_lua_block {
waf:set_option("disable_pcre_optimization", true)
}
}
注: この動作は非推奨であり、将来のバージョンで削除される予定です。
デフォルト: true
lua-resty-waf によって変更されなかったトランザクションにおいて、ルールマッチのログエントリを書き込むかどうかを決定します。「変更された」とは、lua-resty-waf がアクション ACCEPT または DENY のルールに作用したことを意味します。このオプションが設定されていない場合、lua-resty-waf はトランザクションが変更されていなくてもルールマッチをログに記録します。デフォルトでは、lua-resty-waf はトランザクションが変更された場合にのみマッチのログエントリを書き込みます。
例:```lua location / { access_by_lua_block { waf:set_option("event_log_altered_only", false) } }
`mode` は、トランザクションが変更されたと見なされるかどうかの判定には影響しないことに注意してください。つまり、`DENY` アクションを持つルールがマッチした場合でも、lua-resty-waf が `SIMULATE` モードで実行されているなら、トランザクションは依然として変更されたと見なされ、ルールマッチはログに記録されます。
### event_log_buffer_size
*Default*: 4096
イベントログを保持するために使用されるバッファのしきい値サイズ(バイト単位)を定義します。このしきい値に達すると、バッファはフラッシュされます。
*Example*:```lua
location / {
access_by_lua_block {
-- 8 KB event log message buffer
waf:set_option("event_log_buffer_size", 8192)
}
}
デフォルト: ngx.INFO
イベントログに使用する nginx ログレベル定数を設定します。
例:```lua location / { access_by_lua_block { waf:set_option("event_log_level", ngx.WARN) } }
### event_log_ngx_vars
*デフォルト*: 空
`ngx.var` からログイベントに含める追加変数を定義します。これは、アラートに追加のコンテキストを付与するための一般的な方法です。変数名は、ログエントリ内の `ngx` キーの下にあるエントリのキーとなります。変数が nginx 変数として存在しない場合は、イベントに項目は追加されません。
*例*:```lua
location / {
access_by_lua_block {
waf:set_option("event_log_ngx_vars", "host")
waf:set_option("event_log_ngx_vars", "request_id")
}
}
結果として得られるイベントには、次の追加項目があります:```json { "ngx": { "host": "example.com", "request_id": "373bcce584e3c18a" } }
### event_log_periodic_flush
*デフォルト*: なし
イベントログバッファが定期的にフラッシュされる間隔を秒単位で定義します。値が設定されていない場合、バッファは定期的にフラッシュされず、`event_log_buffer_size` のしきい値に達したときのみフラッシュされます。このオプションは、長期間イベントログデータを受信しない可能性のある非常に低トラフィックなサイト向けに設定します。古いデータがバッファに溜まるのを防ぐためです。
*例*:```lua
location / {
access_by_lua_block {
-- flush the event log buffer every 30 seconds
waf:set_option("event_log_periodic_flush", 30)
}
}
デフォルト: false
true に設定すると、ログエントリにはリクエスト引数が uri_args キーの下に含まれます。
例:```lua location / { access_by_lua_block { waf:set_option("event_log_request_arguments", true) } }
### event_log_request_body
*デフォルト*: false
true に設定すると、ログエントリには `request_body` キーの下にリクエストボディが含まれます。
*例*:```lua
location / {
access_by_lua_block {
waf:set_option("event_log_request_body", true)
}
}
デフォルト: false
HTTPリクエストのヘッダーは、request_headers キーの下でログイベントにコピーされます。
例:```lua location / { access_by_lua_block { waf:set_option("event_log_request_headers", true) } }
生成されたイベントには、次の追加項目があります:```json
{
"request_headers": {
"accept": "*/*",
"user-agent": "curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3"
}
}
デフォルト: false
TCP/UDP経由でログを記録する際にSSL接続を有効にします。
例:```lua location / { access_by_lua_block { waf:set_option("event_log_ssl", true) } }
### event_log_ssl_sni_host
*デフォルト*: なし
`lua-resty-logger-socket` 接続のSNIホストを設定します。
*例*:```lua
location / {
access_by_lua_block {
waf:set_option("event_log_ssl_sni_host", "loghost.example.com")
}
}
デフォルト: false
TCP/UDPを介したロギング時に、SSL接続の証明書検証を有効にします。
例:```lua location / { access_by_lua_block { waf:set_option("event_log_ssl_verify", true) } }
### event_log_socket_proto
*デフォルト*: udp
イベントログをリモートソケット経由で送信する際に使用するIPプロトコル(TCPまたはUDP)を定義します。プロトコルに関係なく、同じバッファリングと定期フラッシュのロジックが使用されます。
*例*:```lua
location / {
access_by_lua_block {
-- send logs via TCP
waf:set_option("event_log_socket_proto", "tcp")
}
}
Default: error
イベントログの宛先を定義します。lua-resty-waf は現在、エラーログ、ローカルファイルシステム上の別ファイル、またはリモートのTCPまたはUDPサーバーへのロギングをサポートしています。後者の2つの場合、イベントログはバッファリングされ、定義されたしきい値に達するとフラッシュされます(イベントログオプションの詳細については下記を参照してください)。
Example:```lua location / { access_by_lua_block { -- send event logs to the server's error_log location (default) waf:set_option("event_log_target", "error")
-- send event logs to a local file on disk
waf:set_option("event_log_target", "file")
-- send event logs to a remote server
waf:set_option("event_log_target", "socket")
}
}
使用しているロギングライブラリの制限により、定義できるターゲットソケットは1つだけです。つまり、特定のホスト/ポートの組み合わせを持つ`socket`ターゲットは1つだけ設定できます。2番目のホスト/ポートの組み合わせを設定すると、データが正しくログに記録されません。
### event_log_target_host
*デフォルト*: なし
リモートサーバーを対象とするイベントログのターゲットサーバーを定義します。
*例*:```lua
location / {
access_by_lua_block {
waf:set_option("event_log_target_host", "10.10.10.10")
}
}
Default: none
イベントログがローカルファイルシステムの場所を対象とする場合のターゲットパスを定義します。
例:```lua location / { access_by_lua_block { waf:set_option("event_log_target_path", "/var/log/lua-resty-waf/event.log") } }
このパスは、nginx ユーザーが書き込み可能な場所にある必要があります。なお、性質上、ディスクへのログ記録は、高並行環境で著しいパフォーマンス低下を引き起こす可能性があることに注意してください。
### event_log_target_port
*デフォルト*: なし
リモートサーバーを対象とするイベントログのターゲットポートを定義します。
*例*:```lua
location / {
access_by_lua_block {
waf:set_option("event_log_target_port", 9001)
}
}
デフォルト: なし
ルールが一致したときに実行されるアクションの機能を上書きします。詳細は例を参照してください
例:```lua
location / {
access_by_lua_block {
local deny_override = function(waf, ctx)
ngx.log(ngx.INFO, "Overriding DENY action")
ngx.status = 404
end
-- override the DENY action with the function defined above
waf:set_option("hook_action", "DENY", deny_override)
}
}
### ignore_rule
*デフォルト*: なし
モジュールに指定されたルールIDを無視するよう指示します。チェーン内のルールを無視すると、チェーン全体が無視され、処理はチェーンに続く次のルールに進みます。
*例*:```lua
location / {
access_by_lua_block {
waf:set_option("ignore_rule", 40294)
waf:set_option("ignore_rule", {40002, 41036})
}
}
set_optionにルールIDのテーブルを渡すことで、複数のルールを無視できます。
デフォルト: なし
モジュールにルールセット全体を無視するよう指示します。これは、一部のルールセット(SQLiやXSS CRSルールセットなど)が誤検知を起こしすぎる場合や、アプリケーションに適用できない場合に役立ちます。
例:```lua location / { access_by_lua_block { waf:set_option("ignore_ruleset", "41000_sqli") } }
### mode
*デフォルト*: SIMULATE
モジュールの動作モードを設定します。オプションは ACTIVE、INACTIVE、SIMULATE です。ACTIVE モードでは、ルールの一致がログに記録され、アクションが実行されます。SIMULATE モードでは、lua-resty-waf は有効な各ルールをループし、ルールの一致をログに記録しますが、指定された実行においてアクションは完了しません。INACTIVE モードはモジュールの実行を防ぎます。
デフォルトでは、モードが明示的に設定されていない場合に SIMULATE が選択されます。これにより、新しいユーザーはモードを ACTIVE に設定してブロックを積極的に実装する必要があります。
*例*:```lua
location / {
access_by_lua_block {
waf:set_option("mode", "ACTIVE")
}
}
デフォルト: なし
RBLルックアップに使用するDNSリゾルバーを設定します。現在はUDP/53トラフィックのみがサポートされています。このオプションは、ホスト名ではなく数値アドレスとして定義する必要があります。このオプションが定義されていない場合、すべてのRBLルックアップルールはfalseを返します。
例:```lua location / { access_by_lua_block { waf:set_option("nameservers", "10.10.10.10") } }
### process_multipart_body
*デフォルト* true
`lua-resty-upload` モジュールを使用して、multipart/form-data リクエストボディ(存在する場合)の処理を有効にします。将来的には、lua-resty-waf はこの処理を使用してアップロードボディのより厳密なチェックを行うかもしれませんが、現時点ではこのモジュールはリクエストボディに対して最小限の健全性チェックのみを実行し、リクエストボディが無効であってもイベントをログに記録しません。このチェックが不要な場合、または上流モジュールのバグが HTTP アップロードで問題を引き起こしている場合は、このオプションを無効にしてください。
*例*:```lua
location / {
access_by_lua_block {
-- disable processing of multipart/form-data requests
-- note that the request body will still be sent to the upstream
waf:set_option("process_multipart_body", false)
}
}
デフォルト: false
上流リクエストに HTTP ヘッダー X-Lua-Resty-WAF-ID を設定し、その値としてトランザクション ID を使用します。この ID は、デバッグログに含まれるトランザクション ID(設定されている場合)と関連付けられます。これは、リクエスト追跡やデバッグ目的に役立ちます。
例:```lua location / { access_by_lua_block { waf:set_option("req_tid_header", true) } }
### res_body_max_size
*デフォルト*: 1048576 (1 MB)
レスポンスボディが処理されないコンテンツ長のしきい値を定義します。このレスポンスボディのサイズは、Content-Length レスポンスヘッダーによって決定されます。このヘッダーがレスポンスに存在しない場合、レスポンスボディは決して処理されません。
*例*:```lua
location / {
access_by_lua_block {
-- increase the max response size to 2 MB
waf:set_option("res_body_max_size", 1024 * 1024 * 2)
}
}
Note that by nature, it is required to buffer the entire response body in order to properly use the response as a collection, so increasing this number significantly is not recommended without justification (and ample server resources).
Default: "text/plain", "text/html"
lua-resty-waf がレスポンスボディを処理する MIME タイプを定義します。この値は Content-Type ヘッダーによって決定されます。このヘッダーが存在しない場合、またはレスポンスタイプがこのリストに含まれない場合、レスポンスボディは処理されません。このオプションを設定すると、指定した MIME タイプが既存のデフォルトである text/plain と text/html に追加されます。
Example:```lua location / { access_by_lua_block { -- mime types that will be processed are now text/plain, text/html, and text/json waf:set_option("res_body_mime_types", "text/json") } }
複数のMIMEタイプは、`set_option`にタイプのテーブルを渡すことで追加できます。
### res_tid_header
*デフォルト*: false
ダウンストリームの応答に、トランザクションIDを値とするHTTPヘッダー`X-Lua-Resty-WAF-ID`を設定します。このIDは、デバッグログ(設定されている場合)に含まれるトランザクションIDと対応します。これは、リクエストの追跡やデバッグ目的に役立ちます。
*例*:```lua
location / {
access_by_lua_block {
waf:set_option("res_tid_header", true)
}
}
Default: 5
異常スコアリングのしきい値を設定します。しきい値に達すると、lua-resty-waf はリクエストを拒否します。
Example:```lua location / { access_by_lua_block { waf:set_option("score_threshold", 10) } }
### storage_backend
*デフォルト*: dict
永続的な変数ストレージに使用するエンジンを定義します。現在利用可能なオプションは、*dict*(ngx_lua 共有メモリゾーン)、*memcached*、および *redis* です。
*例*:```lua
location / {
acccess_by_lua_block {
waf:set_option("storage_backend", "memcached")
}
}
デフォルト: true
リモートの永続ストレージホストへの接続に対するTCPキープアライブを有効または無効にします。
例:```lua location / { acccess_by_lua_block { waf:set_option("storage_keepalive", false) } }
### storage_keepalive_timeout
*デフォルト*: 10000
リモートの永続ストレージホスト向けcosocket keepaliveプールのタイムアウトを(ミリ秒単位で)設定します。
*例*:```lua
location / {
acccess_by_lua_block {
waf:set_option("storage_keepalive_timeout", 30000)
}
}
デフォルト: 100
リモートの永続ストレージホスト向けcosocket keepaliveプールのプールサイズを設定します。
例:```lua location / { acccess_by_lua_block { waf:set_option("storage_keepalive_pool_size", 50) } }
### storage_memcached_host
*デフォルト*: 127.0.0.1
memcachedを永続変数ストレージエンジンとして使用する場合に使用するホストを定義します。
*例*:```lua
location / {
acccess_by_lua_block {
waf:set_option("storage_memcached_host", "10.10.10.10")
}
}
デフォルト: 11211
永続的な変数ストレージエンジンとしてmemcachedを使用する際に使用するポートを定義します。
例:```lua location / { acccess_by_lua_block { waf:set_option("storage_memcached_port", 11221) } }
### storage_redis_host
*デフォルト*: 127.0.0.1
redis を永続的な変数ストレージエンジンとして使用する際に使用するホストを定義します。
*例*:```lua
location / {
acccess_by_lua_block {
waf:set_option("storage_redis_host", "10.10.10.10")
}
}
デフォルト: 6379
永続変数ストレージエンジンとしてredisを使用する際に使用するポートを定義します。
例:```lua location / { acccess_by_lua_block { waf:set_option("storage_redis_port", 6397) } }
### storage_zone
*デフォルト*: なし
永続ストレージデータを保持するために使用される `lua_shared_dict` を定義します。このゾーンは、設定の `http{}` ブロック内で定義する必要があります。
*例*:_```lua
http {
-- define a 64M shared memory zone to hold persistent storage data
lua_shared_dict persistent_storage 64m;
}
location / {
access_by_lua_block {
waf:set_option("storage_zone", "persistent_storage")
}
}
複数の共有ゾーンを定義して使用できますが、各設定場所で定義できるゾーンは1つだけです。ゾーンがいっぱいになり、共有ディクショナリインターフェースが追加のキーを追加できない場合、次の内容がエラーログに記録されます:
Error adding key to persistent storage, increase the size of the lua_shared_dict
lua-resty-waf はリクエストライフサイクルの複数のフェーズで実行されるように設計されています。ルールは次のフェーズで処理できます:
これらのフェーズは、それぞれ対応する Nginx lua ハンドラー (access_by_lua、header_filter_by_lua、body_filter_by_lua、log_by_lua) に対応します。このリストにない lua フェーズハンドラーで lua-resty-waf を実行すると、正常に動作しないことに注意してください。以前のフェーズで利用可能なすべてのデータは、後続のフェーズでも利用できます。つまり、access フェーズで利用可能なデータは header_filter および body_filter フェーズでも利用できますが、その逆はできません。
lua-resty-waf には、ModSecurity CRS の機能を模倣するように設計された多数のルールセットが同梱されています。参考までに、これらのルールセットを以下に示します:
lua-resty-waf は、ディスク上に保存された JSON ブロブからルール定義を解析します。ルールは、目的と深刻度に基づいてグループ化され、ルールセットとして定義されます。同梱のルールセットは、ModSecurity CRS の一部の機能、特に base_rules 定義を模倣するために作成されました。さらに、同梱の modsec2lua-resty-waf.pl スクリプトを使用して、追加のルールセットやカスタムルールセットを lua-resty-waf 互換の JSON ブロブに変換できます。
翻訳スクリプトには、サポートされていないアクション、コレクション、オペレーターに関していくつかの制限があることに注意してください。既知の非互換性の最新リストについては、この Wiki ページ を参照してください。
Freenode IRC チャンネル #lua-resty-waf があります。Travis CI がこのチャンネルに通知を送信します。このチャンネルで質問やコメントを自由に残してください。
さらに、CodeWake で Q&A を利用できます:
すべてのプルリクエストは開発ブランチを対象にしてください。PR が大きな変更である場合は、フィーチャーブランチを対象にしてください。master へのコミットは、ドキュメントの更新や、モジュール自体に影響を与えないその他の変更(開発ブランチにきれいにマージできるもの)のみにしてください。
lua-resty-waf は継続的な開発と改善が進行中であり、そのため機能とパフォーマンスに制限がある場合があります。現在知られている制限は、このリポジトリの GitHub イシュートラッカーで確認できます。
このプログラムはフリーソフトウェアです。あなたはこれを再配布し、および/または変更することができます。 その条件は、Free Software Foundation によって公開された GNU General Public License に基づきます。 ライセンスはバージョン3、または (あなたの選択で)それ以降のバージョンのいずれかです。
このプログラムは、有用であることを期待して配布されていますが、 いかなる保証もありません。暗黙の保証も含めて、一切保証しません。 商品性または特定目的への適合性についての保証もありません。詳細は、 GNU General Public License を参照してください。
このプログラムとともに GNU General Public License のコピーを受け取っているはずです。 受け取っていない場合は、http://www.gnu.org/licenses/ を参照してください。
バグは GitHub イシュートラッカーでチケットを作成して報告してください。