【ITニュース解説】h2c (HTTP/2 平文) で通信してみた 【その1 〜 バックエンド(Go/Node.js/Python)サービス編】
2025年09月11日に「Qiita」が公開したITニュース「h2c (HTTP/2 平文) で通信してみた 【その1 〜 バックエンド(Go/Node.js/Python)サービス編】」について初心者にもわかりやすく解説しています。
ITニュース概要
HTTP/1.1は電文の区切り方に起因するdesync等の脆弱性を持つ。この問題回避のため、h2c (HTTP/2平文) 通信をGo/Node.js/Pythonバックエンドサービスで利用する方法を解説。
ITニュース解説
Web上で情報がやり取りされる際、Webブラウザとサーバーの間で通信のルールを定めたものがHTTP(Hypertext Transfer Protocol)である。このHTTPにはいくつかのバージョンがあり、その中でも長らく広く使われてきたのがHTTP/1.1だ。しかし、HTTP/1.1には、近年のセキュリティ研究によって指摘される深刻な脆弱性が存在する。このニュース記事は、そうしたHTTP/1.1の課題に触れつつ、次世代のプロトコルであるHTTP/2、特に「h2c」という形式での通信について、Go、Node.js、Pythonといったバックエンドサービスでの実装と検証を行ったものだ。
まず、HTTP/1.1の抱える問題点から解説する。HTTP/1.1では、サーバーとクライアント間でやり取りされるメッセージ(リクエストやレスポンス)が、主にテキスト形式で構成される。このメッセージの終わり、つまりどこまでが一つのメッセージなのかを示す方法が、Content-LengthヘッダとTransfer-Encoding: chunkedという二つの異なる形式で指定できる。Content-Lengthはメッセージ全体のバイト数を明示し、chunkedはメッセージを小さな「チャンク(塊)」に分けて送り、それぞれのチャンクの長さを指定し、最後に特別なゼロ長のチャンクでメッセージの終わりを示す。
この二つのメッセージ区切り方式が混在したり、プロキシサーバーなどの中間機器がこれらを異なる解釈をしたりすると、「desync(同期ずれ)」や「smuggling(密輸)」と呼ばれる脆弱性につながる可能性がある。具体的には、プロキシサーバーがクライアントから受け取った一つのリクエストを、バックエンドサーバーへ転送する際に、メッセージの区切りを誤って解釈してしまうケースだ。例えば、プロキシはContent-Lengthに基づいてメッセージの長さを判断するが、バックエンドサーバーはchunkedエンコーディングを優先してメッセージを処理するといった状況が起こりうる。これにより、プロキシとバックエンドサーバーの間で、どこまでが最初のメッセージで、どこからが次のメッセージなのかという認識にズレが生じる。
悪意のある攻撃者は、このズレを巧妙に利用する。一つのリクエストの中に、正規のリクエストと、サーバーにとって不正な次のリクエストの断片を隠し持たせることで、プロキシはそれを単一の正規リクエストの一部と見なして転送するが、バックエンドサーバーは不正な断片を別の独立したリクエストとして解釈してしまう可能性があるのだ。結果として、攻撃者はプロキシの検査をすり抜け、バックエンドサーバーに意図しない処理を実行させたり、他のユーザーのリクエストに悪影響を与えたり、場合によっては機密情報を窃取したりする危険性がある。記事で述べられている「HTTP/1.1が根本的に脆弱性が...」という指摘は、このようなテキストフォーマットのメッセージ区切り方に起因する曖昧さが、プロトコル設計の段階から潜在的なリスクを含んでいたことを示唆している。
こうしたHTTP/1.1のセキュリティ面での課題や、パフォーマンス面での制約を解決するために開発されたのが、次世代プロトコルであるHTTP/2だ。HTTP/2は、HTTP/1.1とは異なり、メッセージをテキスト形式ではなく、すべてバイナリ形式の「フレーム」という単位で扱う。各フレームには、そのフレームの種類(例えば、ヘッダー情報、データ本体など)やフレームの長さが明確に定義されており、メッセージの区切りがあいまいになることはない。これにより、HTTP/1.1で問題となっていたdesyncやsmugglingといった脆弱性が、原理的に発生しにくい構造となっている。加えて、HTTP/2は一つのTCPコネクション上で複数のリクエストとレスポンスを同時に処理できる多重化や、ヘッダー情報の効率的な圧縮など、パフォーマンス向上にも大きく貢献する。
通常、HTTP/2は通信の安全性を確保するためにTLS(Transport Layer Security)という暗号化技術と組み合わせて利用され、HTTPSとして広く普及している。しかし、この記事で取り上げられている「h2c」は、HTTP/2をTLSによる暗号化なしで平文(cleartext)のまま利用する形式を指す。では、なぜ暗号化せずにHTTP/2を使うのだろうか。その主な理由は、特定のネットワーク環境下での利用が想定されているためだ。
例えば、Webサーバーの前にリバースプロキシやロードバランサーが設置されている場合を考える。クライアントとリバースプロキシ間の通信はHTTPSで暗号化されていても、リバースプロキシとバックエンドのサービス(Go/Node.js/Pythonで実装されたものなど)間の通信は、同じデータセンター内や隔離された安全なネットワークで行われることが多い。このような内部ネットワーク環境では、すでに物理的・論理的なセキュリティ対策が施されているため、HTTP/2で通信の暗号化を行うTLSの処理オーバーヘッドを避けるために、h2cを選択することがある。h2cを利用することで、内部通信のパフォーマンスを向上させながらも、HTTP/2の持つフレームベースの明確なメッセージ区切りによるdesync対策といったセキュリティ上の利点や、多重化による効率的な通信を享受できるのだ。
この記事では、まさにこのh2cをGo、Node.js、Pythonといった主要なバックエンド開発言語で実際に実装し、その通信がどのように行われるかを検証している。これは、システムを構築する上で、HTTP/1.1の脆弱性を意識し、HTTP/2、特にh2cのような新しい通信方式を内部システムにどのように適用できるかを実践的に探る試みと言える。システムエンジニアを目指す初心者にとって、Web通信の根幹をなすHTTPプロトコルの進化とその背景にあるセキュリティ課題、そしてh2cのような実践的な利用ケースを理解することは、安全で効率的なシステム設計能力を養う上で非常に重要である。最新のプロトコルがどのように過去の問題を解決し、どのような状況で活用されるのかを学ぶことは、今後のキャリアにおいて不可欠な知識となるだろう。