REST次のようなリクエストを受け取るAPIを構築しています:
GET /api/entities
GET /api/entities?filter=X&sort=Y
これは簡単なようです。クライアントにHMAC(パス+クエリ、キー)を送信し、キー識別子とHMACをヘッダーなどで送信してから、サーバーで同じことを行って、一致するかどうかを確認します。
ここに私の懸念があります:
POST /api/entities
{ "foo": "bar" }
クライアントがそのパスとクエリでHMACを計算する場合、理論的にはそのHMACを使用して任意のボディを送信できます。
tl; dr JSONボディの有無にかかわらず、GET、POST、PUTリクエストのリクエスト署名を適切に実装するにはどうすればよいですか?
ペイロードもHMACする必要があります。パスとクエリパラメータのHMACを含むヘッダーを含めることを述べたので、本文のHMACを含む別のヘッダーを作成できます。ただし、おそらく1つのHMACのみを送信する必要があるため、攻撃者はさまざまなセクションを組み合わせて照合することはできません。したがって、次のようなことができます。
HMAC-Signature: HMAC( HMAC(path + query, key) + HMAC(body, key), key)
HMACをまとめて廃棄し、クライアント証明書でTLSを使用することができます。 nonceを導入しない限り、HMACはリプレイ攻撃の対象になります。さらに、HTTP仕様を一貫して解釈することが難しい場合があることを考慮する必要があります。ブラウザー(およびクライアントライブラリ)によって、文字エンコーディングなどのアプローチが異なります。 1つのアプリケーションがa?b='
が、別のユーザーがa?b=%27
、デコードする前に、これらの2つのリソース/クエリ文字列は非常に異なるHMACを持っています。