1534 words
8 min

HTMLのChunkについて

2025-06-18

前提#

HTTP/1.1では使用されるが
HTTP/2以降のプロトコルでは廃止されているので注意

そもそもChunk転送(チャンク転送)とは何者?#

Chunk転送は、HTTP/1.1で導入されたデータ転送方式のひとつ。
サーバーがレスポンスのコンテンツ長を事前に決定できない場合や、
ストリーミングデータのように順次データを送りたい場合に使われるもの。

ChatGPTの返答がリアルタイムに返ってくる動作だったり
動画ストリーミングに利用されている。

なぜにChunk転送の概念がでてきたのか#

通常、HTTPレスポンスのヘッダにはContent-Lengthが含まれる。
これにより、ブラウザやクライアントはレスポンスボディの終了位置を知ることができる。

しかし、以下のような場合にContent-Lengthを指定するのが難しい。

  • 動的に生成されるコンテンツ(ChatGPTとか)
  • ストリーミング形式でのレスポンス(動画系)

このようなケースで使用されるのがチャンク転送エンコーディング

Content-Lengthでも実装できないか#

疑問に感じた、そもそもChunkedが出てくる前はContent-Lengthで何とかなってたはずで
ポーリング等で再現できそうだが、何が駄目なのかを調べてみた

Chunk転送が来る前のストリーミング#

ストリーミングではなくプログレッシブダウンロードを行っていた
Content-Length は付与するけど、実際の再生は受信しながら再生になる
キャッシュとして端末に動画をダウンロードしながらダウンロードが終わった個所から再生していく形

プログレッシブではだめなの?#

プログレッシブダウンロードはストリーミングと違い、
一時ファイルが保存される形になるので著作権面で注意する必要がある
また、動画として事前にファイルが用意できないライブ配信には不向きな点があった

そのため、ストリーミング配信が最近は主流になっている

Chunk転送が来る前の動的に生成されるコンテンツ(チャットなど)#

  • ポーリング
  • ロングポーリング
  • 定期的リロード

を活用して処理をトリガーすることで生成されるコンテンツを読み込んでいた

それぞれ簡単にまとめると
ポーリング:クライアント側で定期的に処理を実行し(10秒ごと等)新着があるかサーバーに問い合わせる

ロングポーリング:リクエストされた後に処理が更新されるまでレスポンスを返さない、クライアントはレスポンス
されたらすぐにリクエストをして待機

定期的リロード:ページをリロードしてコンテンツを再取得する
といった形で処理をトリガーしていた

ポーリング等ではだめなの?#

いつ新着のコンテンツが発生するか分からないため
定期的 or 待機をする必要があり、無駄な処理が嵩む事になる
また、ロングポーリングに至っては接続が発生しっぱなしになるため、コネクションとしても効率が悪い

そのため、プロトコル的にも「イベント単位のプッシュ」に最適化されているチャンク転送の方が使い勝手がよい

Chunkedが出る前(HTTP/1.0とか)のKeep-Aliveは何だったのか?#

HTTP/1.0や初期のHTTP/1.1では、一応「コネクションを閉じない」設定(Keep-Alive)だけはあった
ただし、レスポンス自体は最初にContent-Lengthが必要で、ストリーミング的な更新は無理だった

チャンク転送の仕組み#

チャンク転送では、以下のようにデータを**チャンク(塊)**に分けて送信している
サーバーがレスポンスを小分けにして送るようなイメージ

HTTP/1.1 200 OK  
Transfer-Encoding: chunked  
...
各チャンクの先頭にチャンクサイズ(16進数)を記載
チャンクサイズの後に改行(CRLF)
チャンクのデータ本体
チャンクの末尾にも改行(CRLF)
...

チャンク転送の終わりは、サイズ0のチャンクを送信することで終わりを示す

SSE#

チャンク転送を使用した技術にSSEという通信方法がある
サーバー → クライアント(ブラウザ)にイベント形式のデータをストリーミングできる仕組み
text/event-stream というMIMEタイプのレスポンスで実現する
JavaScriptのEventSourceで簡単に受信できるようになっている

例えば

index.js
const source = new EventSource('/sample');
source.onmessage = (event) => console.log(event.data);

上記のコードを書くことで、/sampleから送られてくるレスポンスを
イベントとして発火できるようになる

WebSocket#

似たような仕組みに、WebSocketがある
ただ、似たような事を行っているように見えるが結構別物なので注意
こちらはWebSocketプロトコルで動作するのでHTTPではない
HTTPの仕組みと違い、双方向で通信ができることが特徴
チャット・ゲーム・株価などの双方向、対話的な通信に特化している

HTTPリクエストスマグリング#

Chunkedを知るうえで有名な攻撃手法として
HTTPリクエストスマグリングと呼ばれる攻撃手法ががあったので調べてみた

そもそもHTTPリクエストスマグリングとは何か?#

サーバーやプロキシ(リバースプロキシ、ロードバランサー)間で、
HTTPリクエストの解釈に差があることを突く攻撃のこと

たとえば、同じリクエストをサーバーは「チャンク転送」と解釈するが、
プロキシはContent-Length優先で解釈するなどの違いを利用する攻撃

POST / HTTP/1.1
Host: sample.com
Content-Length: 10
Transfer-Encoding: chunked

0

GET /sample HTTP/1.1
Host: sample.com

上記の場合
プロキシはContent-Length: 10を信じてリクエストを終了する
しかしバックエンドサーバーはチャンク転送として扱い
その後のGET /adminを別のリクエストとして解釈してしまう

違いを利用することで

  • バックエンドに不正リクエストを送り込める
  • セッション乗っ取り・キャッシュポイズニングなどを誘発する
    を狙う攻撃手法の一つ

どうすればよいのか、、、?#

対策として

  • リクエストの曖昧なヘッダ(Content-LengthとTransfer-Encodingの併用など)を許可しない
  • Webサーバーやリバースプロキシの設定を最新化し、既知の脆弱性に対応する
  • 脆弱性スキャナ(Burp Suite など)でHTTPリクエストスマグリングを検査する
    等がある

まとめ#

Chunk転送(チャンク転送)はHTTP/1.1から使用できる
Transfer-Encoding: chunkedのヘッダーを付ける事で使用できる
動的コンテンツやストリーミングレスポンスに使うもの
HTTP/2ではチャンク転送は廃止されている(ストリームとフレームという概念が存在)

HTMLのChunkについて
https://tech.storias-blog.com/blogs/http_chunk
作者
Storia
公開日
2025-06-18