ようへいの日々精進XP

よかろうもん

Apache の LimitRequestFieldSize の挙動を確認する

tl;dr

ギョームで LimitRequestFieldSize について調べる機会があったので、改めて、手元で LimitRequestFieldSize の挙動を確認した。

LimitRequestFieldSize とは

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 の挙動を確認してみました。