tl;dr
ギョームで LimitRequestFieldSize について調べる機会があったので、改めて、手元で LimitRequestFieldSize の挙動を確認した。
LimitRequestFieldSize とは
- https://httpd.apache.org/docs/2.4/ja/mod/core.html#limitrequestfieldsize
- HTTP リクエストヘッダ一つで受付けるバイト数 bytes の上限を設定出来る
- 値を調整することで、異常なリクエストを送りつけてくる DDoS を防ぐことが出来る
- デフォルトは 8190 バイト
HTTP リクエストヘッダー 1 つで受け付けられるバイト数の上限ということで、設定値を 100 バイトに制限した場合、以下のようなリクエストを送信すると、各ヘッダ行で 100 バイト制限がかかることになる。
> Host: localhost:8080 # ここで 100 バイト > User-Agent: curl/7.64.1 # ここで 100 バイト > Accept: */* # ここで 100 バイト > Cookie: name=xxxxxxxxxx # ここで 100 バイト
挙動を試す
検証環境
Apache の Docker コンテナを利用する。
root@71158ebff5ab:/usr/local/apache2# httpd -V Server version: Apache/2.4.46 (Unix) Server built: Aug 5 2020 23:20:17 Server's Module Magic Number: 20120211:93 Server loaded: APR 1.6.5, APR-UTIL 1.6.1 Compiled using: APR 1.6.5, APR-UTIL 1.6.1 Architecture: 64-bit Server MPM: event threaded: yes (fixed thread count) forked: yes (variable process count) Server compiled with.... -D APR_HAS_SENDFILE -D APR_HAS_MMAP -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled) -D APR_USE_SYSVSEM_SERIALIZE -D APR_USE_PTHREAD_SERIALIZE -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT -D APR_HAS_OTHER_CHILD -D AP_HAVE_RELIABLE_PIPED_LOGS -D DYNAMIC_MODULE_LIMIT=256 -D HTTPD_ROOT="/usr/local/apache2" -D SUEXEC_BIN="/usr/local/apache2/bin/suexec" -D DEFAULT_PIDLOG="logs/httpd.pid" -D DEFAULT_SCOREBOARD="logs/apache_runtime_status" -D DEFAULT_ERRORLOG="logs/error_log" -D AP_TYPES_CONFIG_FILE="conf/mime.types" -D SERVER_CONFIG_FILE="conf/httpd.conf"
LimitRequestFieldSize を 100 に設定してみる
LimitRequestFieldSize 100
まずは、普通にリクエストを投げてみる。
$ curl localhost:8080 -I HTTP/1.1 200 OK Date: Tue, 23 Feb 2021 08:45:35 GMT Server: Apache ... 略 ...
次に、100 バイト (100 文字) の cookie を送信してみる。
$ curl -b 'name=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' http://localhost:8080/ -I HTTP/1.1 400 Bad Request Date: Tue, 23 Feb 2021 08:47:59 GMT Server: Apache Connection: close Content-Type: text/html; charset=iso-8859-1
BadRequest が返ってきた。100 バイト制限だから 100 文字の値が受け付けられるわけではなさそう。
$ curl -b 'name=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' http://localhost:8080/ -I HTTP/1.1 200 OK Date: Tue, 23 Feb 2021 08:52:41 GMT Server: Apache ... 略 ...
実際には 88 文字まで x
を減らすと正常なレスポンス (ステータスコード: 200) が返却されるようになった。
これは、なんでだろうなーと思って、curl の --verbose
オプションを付けてリクエストヘッダを見てみた。
* Trying ::1... * TCP_NODELAY set * Connected to localhost (::1) port 8080 (#0) > HEAD / HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.64.1 > Accept: */* > Cookie: name=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
どうやら、Cookie のキー名と、ヘッダの Cookie:
という文字列を含め 100 バイトの計算で制限がかかるようだ。(空白はカウントされない)
ちゃんとソースコードを読んだわけではないので、あくまでも予想。
ちょっとだけ Apache のソースコードをリーディング
LimitRequestFieldSize のデフォルト値は
httpd.h に定義されている。
https://github.com/apache/httpd/blob/2.4.x/include/httpd.h
/** default limit on bytes in any one header field */ #ifndef DEFAULT_LIMIT_REQUEST_FIELDSIZE #define DEFAULT_LIMIT_REQUEST_FIELDSIZE 8190
default limit on bytes in any one header field
って書いてある。
気になるのが、同ソースコード内のコメントに、以下のように記述されている。
/* * Limits on the size of various request items. These limits primarily * exist to prevent simple denial-of-service attacks on a server based * on misuse of the protocol. The recommended values will depend on the * nature of the server resources -- CGI scripts and database backends * might require large values, but most servers could get by with much * smaller limits than we use below. The request message body size can * be limited by the per-dir config directive LimitRequestBody. * * Internal buffer sizes are two bytes more than the DEFAULT_LIMIT_REQUEST_LINE * and DEFAULT_LIMIT_REQUEST_FIELDSIZE below, which explains the 8190. * These two limits can be lowered or raised by the server config * directives LimitRequestLine and LimitRequestFieldsize, respectively. * * DEFAULT_LIMIT_REQUEST_FIELDS can be modified or disabled (set = 0) by * the server config directive LimitRequestFields. */ ...
ざっくり意訳すると...
- これらの値は単純な DDoS を防ぐ為に存在している
- 場合によっては、推奨値よりも大きな値を設定する必要があるが、ほとんど変える必要は無い
あまり大きな数値は設定しないほうが良さそうなことが解る。
以上
手元で動かしながら、Apache の LimitRequestFieldSize の挙動を確認してみました。