このセクションでは、HTTP/2の基礎について簡単に説明します。ここでは、Burpに関連する部分だけを取り上げます。背景となる基礎的な概念を理解すると、HTTP/2特有の攻撃手法を行うための、Burpの個性的な機能を最大限に活用できます。
HTTP/1リクエストは単一の、テキストベースのエンティティです。そのためサーバは、一連の特殊な区切り文字による文字列操作を行い、必要なデータの識別や抽出をする必要があります。たとえば、各ヘッダは改行で区切られ、名前と値はコロンで区切られています。
BurpはHTTP/2のリクエストを人間が読めるで2通りの形式で表示していますが、実際には内部でバイナリ形式を使用しています。これは、あらかじめ決められたオフセットに基づいて、サーバがリクエストからデータを読み取れるということです。つまり、それぞれの情報の開始と終了位置が明確に定義されているので、区切り文字は必要ありません。
その結果、HTTP/2のリクエスト内で改行やコロンなどは特別な意味を持たなくなり、HTTP/1では不可能な方法で挿入できます。たとえば、HTTP/2のヘッダ名と値は、技術的には改行文字を保持できます。これは仕様上、公式には禁止されていますが、一部のサーバでこれが許容されている場合に、Inspectorを使えばできてしまいます。これは多くのHTTP/2特有の攻撃や、一部の最新の研究の基礎になっています。
ネットワーク上で、HTTP/2メッセージは1つまたは複数の独立した"フレーム"として送信されます。HEADERSフレームは、HTTP/1リクエストのリクエスト行とヘッダセクションに相当します。これに続いて、メッセージボディデータを含むいくつかのDATAフレームが続くかもしれません。
簡単にするために、BurpではHTTP/2メッセージの個々のフレームを表示していません。それらを組み合わせて、1つのリクエストやレスポンスを構成し表示します。
HTTP/2メッセージの各フレームの前には、何バイト読み込むかを明示的に示す長さフィールドがあります。したがって、サーバはフレーム長の合計を計算するだけで、メッセージの全体の長さを簡単に算出できます。
これは、HTTP/1で使用されているContent-Length
やTransfer-Encoding
の仕組みよりもはるかにシンプルで堅牢です。
HTTP/1では、ヘッダ名は通常、大文字と小文字を区別しません。HTTP/2では、技術的にはヘッダ名に大文字が使えますが、HTTP/2の仕様に準拠していないため、サーバでリクエストが拒否される可能性があります。
HTTP/2では、一連の"疑似ヘッダ"を使用して、メッセージに関する重要な情報を送信します。最も注目すべきは、一部の疑似ヘッダがHTTP/1のリクエスト行とステータス行を効果的に置き換えていることです。
全部で5つの疑似ヘッダがあります:
:method
- GET
やPOST
など、リクエストのHTTPメソッドです。
:path
- リクエストパスです。これには、クエリストリングも含まれます。
:authority
- HTTP/1のHost
ヘッダとほぼ同等です。
:scheme
- リクエストのスキームで、http
またはhttps
です。HTTP/1にこれに相当するものはありません。
:status
- レスポンスのステータスコードです。
仕様によると、すべての疑似ヘッダは通常のヘッダの前に送信されるべきであるとされています。Burpは、Inspectorで手動で上書きしない限り、これらの疑似ヘッダを固定の順序で送信します。
疑似ヘッダを参照する際は、通常のヘッダと区別するために、名前の前にコロンを付けるのが一般的です。これは、この情報を人間が読める形式で表示するための1つの方法に過ぎないことに注意してください。ネットワーク上では、これらの名前は単なるバイナリバイトで、実際にはコロンを含んでいません。