Amazon CloudFrontはボディを含むGETリクエストに403(Forbidden)を返します

CloudFrontはメッセージボディーのあるGETリクエストに403(Forbidden)を返します
2020.04.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

『Real World HTTP 第2版』で知ったのですが、GETリクエストにはメッセージボディを含めることができます

より具体的には、HTTP/1.1の一世代前の仕様RFC2616 *1では、「サーバーはメッセージボディを読み込める必要はあるが、リクエストされたメソッドがボディのセマンティクスを定めていない場合は、リクエストの処理時にメッセージボディは無視されるべき」と書かれており、最新のRFC7231 *2では、「ペイロードのボディを持つことはできるが、実装によってはサーバーがこれを受け取らずに拒否することがありえる」と書かれています。(カッコ内は同書から引用)

ALB は 何もせず、CloudFront は403を返す

意図せずリクエストが拒否されると困ります。

普段触れる機会の多い AWS のマネージドサービスがどのように振る舞うのか確認したところ、Application Load Balancer (ALB) はリクエストをそのままターゲットに渡す一方で、Amazon CloudFront は 403(Forbidden)を返すという結果が得られました。

CloudFront のこの挙動はドキュメントに記載されています

GET リクエストに本文が含まれている

ビューワー GET のリクエストの本文が含まれている場合、CloudFront はビューワーに HTTP ステータスコード 403 (禁止) を返します。

実際に確認します。

$ curl -D - -X GET --data "hello=world" XXX.cloudfront.net
HTTP/1.1 403 Forbidden
Server: CloudFront
...
X-Cache: Error from cloudfront
...

ボディを含むGETリクエストをするケース

書籍にも書かれている通り、検索エンジンのElasticsearchは検索条件をJSON形式でGETのボディーに渡すことができます

$ curl -X GET "localhost:9200/twitter/_search?pretty" \
  -H 'Content-Type: application/json' -d'
{
    "query" : {
        "term" : { "user" : "kimchy" }
    }
}
'

Elasticsearch の前段に CloudFront を置く場合、素直に POST しましょう。

最後に

ウェブ系エンジニアにとって『Real World HTTP』は面白くてためになる一冊です。

ゴールデンウィーク中のSTAY HOMEのお供にどうぞ。

参考

脚注

  1. A server SHOULD read and forward a message-body on any request; if the request method does not include defined semantics for an entity-body, then the message-body SHOULD be ignored when handling the request.
  2. A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request.