こんにちは、技術担当執行役員の大曲です。
今回は、KUSANAGI の ratelimit コマンドで実施できるリクエスト制限のコマンド、およびその仕様について、解説していきたいと思います。
公開されているサイトには、一般的には見えませんが、脆弱性を狙った様々なアクセスがあります。中には、遠慮が一切なく、多数の攻撃を一気に送りつけてくるようなものもあります。KUSANAGI の ratelimit コマンドは、有効化することによって、同一リクエスト元からの連続的なアクセスを制限することができ、このような攻撃によるサーバ負荷上昇、およびサイトダウンのリスクを低減することができます。
ratelimit コマンドを使える環境について
KUSANAGI の ratelimit コマンドは、利用する Webサーバに nginx を選択している場合のみ、有効となります。これは、ratelimit コマンドが、nginx の ngx_http_limit_req_module モジュールの設定をコントロールすることにより実現しているためとなります。
また、コマンドが利用できるバージョンとして、KUSANAGI 9の全バージョン、および KUSANAGI 8 の 8.5.1-1 以上で利用可能です。ただし、バグの修正対応もなされているため、常に最新版で利用することをおすすめいたします。
ratelimit コマンドの使い方
リクエスト制限が有効化されているかどうかは、ratelimit status コマンドで確認することができます。
ratelimit の全コマンドは、オプションとしてプロファイルを指定することができます。省略した場合は、カレントプロファイルが対象となります。
$ kusanagi ratelimit status
ratelimit is on.
ratelimit completed
リクエスト制限を有効化する場合は、ratelimit on、無効化する場合は、ratelimit off コマンドで行います。
$ kusanagi ratelimit on
reload completed.
ratelimit completed.
$ kusanagi ratelimit off
reload completed.
ratelimit completed.
参照:https://kusanagi.tokyo/kusanagi9/document/commands/#ratelimit_status
ratelimit によるリクエスト制限の仕様について
KUSANAGI の共通で適用される設定の nginx.conf には、limit_req_zone ディレクティブの記載があり、以下のように設定されています。
limit_req_zone $remote_addr$http_x_forwarded_for zone=one:10m rate=100r/s;
$remote_addr$http_x_forwarded_for の部分が、リクエスト制限の対象となる部分で、リクエスト元IPが代入される $remote_addr と、ロードバランサー等の利用時にリクエスト元IPが代入される $http_x_forwarded_for を結合したものとなっています。これにより、サーバ単体での利用時だけでなく、ロードバランサーやCDN、リバースプロキシを利用している環境においても、問題なく動作するようになっています。
続く zone=one:10m の部分が、リクエストの状態を保持しておくメモリ領域に関する設定となっていて、one が領域名、10m がサイズで 10MBの領域を示しています。one という名前のメモリ領域 10MBを確保し、そこにリクエスト制限の対象($remote_addr$http_x_forwarded_for)ごとに、最新のリクエスト実績を保持します。10MBの領域では、およそ160,000 件のリクエスト制限の対象を保持でき、運用上必要十分な設定となっています。
rate=100r/s の部分が、しきい値の設定で、1秒間に100リクエストを上限値としています。秒間100リクエストは多いように思われるかもしれませんが、WordPress の管理画面でのAPIリクエストなどを考慮すると、デフォルトではこのくらいが問題が起きにくい値として設定されています。
まとめると、KUSANAGI 環境の ratelimit は、最新のおよそ160,000件のリクエスト制限の対象($remote_addr$http_x_forwarded_for)に対して、秒間100リクエストを超えた場合に制限対象と判断するようになっています。
次に、制限をかけるURLについて解説します。プロビジョンした設定ファイルには、limit_req ディレクティブが記載された ratelimit.inc をインクルードする記述がなされています。このインクルードの記述は、拡張子が php、もしくは cgi の location ディレティブに記載されていますので、php や cgi が動作するリクエストが制限対象としています。
逆にいうと、html や js、css といった静的リソースに対しての制限は行っていません。これは、静的リソースより php や cgi の方が、リクエストあたりの処理負荷が圧倒的に高く、DoS攻撃に対しての弱点になりやすいことと、静的リソースは、サイトごとによってリクエスト数の差異が大きいため、しきい値を判断しにくいためです。
include conf.d/ratelimit.inc;
最後に、実際に制限をかける limit_req ディレクティブの設定について解説いたします。
ratelimit.inc には以下の記載がなされています。zone は、領域名の指定で、limit_req_zone で設定された領域名の one が指定されています。burst は、しきい値を超えた際の一時的緩和措置の値で、秒間100リクエストを超えるようなリクエストでも、10リクエストは正常処理するようになっています。nodelay は、上限値を超えた場合に遅延処理をしないという設定で、しきい値 + burst の 10 を超えたリクエストは、即座に 503 エラーを返すようになっています。
limit_req zone=one burst=10 nodelay;
ただし、ratelimit コマンドは、あくまでも1サーバのnginx で処理できるリクエストに対してのリクエスト制限であり、より大規模なDDoS攻撃には、対処できなくなる場合があります。そのような攻撃への対応には、CDNサービスでの対策を検討してください。
※ 本記事は、2023年3月時点での仕様となります。今後の改訂によって変わる可能性がありますので、ご留意ください。