💎

RailsでRack::Sendfileを使っていない場合は外しておいた方が良いという話

2022/05/15に公開

Rack::Sendfile の問題

Rack::Sendfile の機能についてはRails でファイルを返さず nginx で返す X-Accel-Redirect の設定と解説の記事がわかりやすいです。

問題となるのは以下のhackeroneで報告した内容です。
https://hackerone.com/reports/1057216

https://github.com/rack/rack/blob/v2.2.2/lib/rack/sendfile.rb#L152-L156

Rack::Sendfileはリクエストヘッダーの値を使って正規表現を組み立てています。この値がnginxなどアプリケーションサーバの前にあるリバースプロキシから送信されている場合は問題ないのですが、クライアントからも送信可能な値であるため、リクエストヘッダーを細工することで自由な正規表現の組み立て、つまりRegex Injectionが可能です。

具体的な脅威としてはReDoS、またはnginxを使っている場合にsecret internalの内容が漏洩する可能性です。

ReDoSのタイムアウトについて

ReDoSについて以前試したのですが、途中で実行を止めることができたのはUnicornのタイムアウトのみで、Pumaでは停止されませんでした。Rack::TimeoutについてはRack::Sendfileより前に読み込まれていれば停止できるようです。
[1]

Ruby 3.2.0 Preview 1ではタイムアウトの設定が導入されました。3.2系の安定版を利用できるようになると影響は軽減されるかもしれません。
https://www.ruby-lang.org/ja/news/2022/04/03/ruby-3-2-0-preview1-released/

あなたのRubyアプリケーションの要件に基づいて適切にRegexp.timeoutを設定することで、DoSのリスクを防止、または大幅に緩和できます。ぜひあなたのアプリケーションで試してみてください。フィードバックを歓迎します。

Ruby on Rails の問題

Railsはデフォルトで Rack::Sendfile が読み込まれており、send_fileで使われています。

❯ RAILS_ENV=production bundle exec rails middleware
use ActionDispatch::HostAuthorization
use Rack::Sendfile  <- ここ
use ActionDispatch::Executor
use Rack::Runtime
use Rack::MethodOverride
use ActionDispatch::RequestId
use ActionDispatch::RemoteIp
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use ActionDispatch::DebugExceptions
use ActionDispatch::Callbacks
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use ActionDispatch::Flash
use ActionDispatch::ContentSecurityPolicy::Middleware
use ActionDispatch::PermissionsPolicy::Middleware
use Rack::Head
use Rack::ConditionalGet
use Rack::ETag
use Rack::TempfileReaper
run RailsServer::Application.routes

これを除外するのはbreaking changeになるということで次のメジャーリリースで対応とのことになりました。
https://github.com/rails/rails/issues/41148https://github.com/rails/rails/pull/44556 で対応中のようです。

つまり現状のRailsサーバでは、何も設定しなければこの問題が発生している可能性があります。
リバースプロキシの機能を使っていないのであれば外しておくことを推奨します。

config.middleware.delete Rack::Sendfile

すべての環境でこの問題が発生するかというとそうでもないようでして、詳しいことは調べきれていません。リバースプロキシやCDN、WAFの設定で除外されている可能性があります。

事例としてはshopifyではそれらしき問題が起きていたようです(https://hackerone.com/reports/1027873)

Rubyの脆弱性 (CVE-2022-28738: Regexp コンパイル時のダブルフリー)

2022/4/12にRuby本体のRegexpの問題が公開されました。

https://www.ruby-lang.org/ja/news/2022/04/12/double-free-in-regexp-compilation-cve-2022-28738/

Regexp のコンパイル処理にバグがあり、細工したソース文字列で Regexp オブジェクトを作成すると、同じメモリが二度解放される可能性があります。これは「ダブルフリー」と呼ばれる脆弱性です。 一般的に、信頼できない入力から生成された Regexp オブジェクトを作成し、使用することは安全ではないと考えられています。しかしながら、今回のケースでは総合的に判断した結果、この問題を脆弱性として扱うことにしました。

影響を受けるのは3.0以上のバージョンで、3.0.4、3.1.2で修正されています。

Rack::Sendfileの問題との組み合わせが不味そうに見えますが、任意コード実行まで導けるものなのかは知識が足りないため検証できていません。

脚注
  1. 2023/2/25 Rack::Timeoutの記述を修正 ↩︎

Discussion