Summary

  • RFC 9530 gives HTTP precise integrity fields for message content and selected representation data. A successful comparison proves a narrow byte relationship; it does not authenticate the sender or authorize an action.
  • A decision-grade verifier records the byte domain, algorithm policy, recomputation, signature coverage, key authority, freshness, replay result and final application decision as separate predicates.

The green badge was true

The system's first statement was technically correct. The submitted body hashed to the value carried in Content-Digest. Its second statement—“therefore this policy may be applied”—had no basis in that calculation.

This is a more dangerous failure than an obviously broken checksum. The dashboard does not need to lie. It only needs to leave the noun out. “Verified” sounds complete because it does not say what was verified. The bytes were verified against a value supplied in the same request. The sender, key, permission, time window, replay status and meaning of those bytes were not.

An attacker does not need to defeat SHA-256 to exploit that gap. The attacker can hash the attacker's own content. Cryptographic strength protects a relationship between inputs and outputs; it cannot decide who was entitled to choose the input.

Two fields, two byte domains

RFC 9530 replaces the older Digest design with names that make the object of calculation explicit. Content-Digest applies a registered hash algorithm to the actual content carried by an HTTP message. Repr-Digest applies it to the entire selected representation data.

Those objects can coincide, but they are not interchangeable. A content coding changes the message content while remaining a characteristic of the representation. A range response can carry only part of a representation. A HEAD response can describe a representation without carrying the same content as GET. A PATCH document can be the representation enclosed in a state-changing request without being the resulting state of the target resource.

A verifier therefore needs an answer before it needs a hash: which invariant is the application trying to protect? If a gateway verifies compressed wire content while a downstream service believes it verified decoded representation data, both components can truthfully report success about different byte strings.

RFC 9530's history explains why this precision matters. It obsoletes RFC 3230 after implementations interpreted “instance” inconsistently, often calculating over message content where representation data had been intended. Renaming the fields does not remove the operational boundary; it makes disagreements easier to name and test.

The field is a structured claim

Both integrity fields are Structured Field Dictionaries. A member key names the algorithm; its value is a byte sequence carrying the digest result. More than one algorithm can be present, which can support migrations between algorithms.

Parsing that dictionary is not a security decision. The receiver still needs a policy for which algorithms it recognizes, which it accepts for this threat model, how it handles multiple values and whether failure is terminal. The IANA registry records algorithm status. RFC 9530 recommends Active algorithms for many uses and says Deprecated algorithms must not be used in a potentially adversarial setting.

Base64 punctuation around a byte sequence does not add authority. Encoding turns bytes into a transportable text form. Hashing maps input bytes to a digest. Signing binds selected components to a key under a signature algorithm. These are different operations, with different evidence.

The Want-Content-Digest and Want-Repr-Digest fields are also easy to overread. They communicate interest and relative algorithm preferences. RFC 9530 calls them hints: the receiver may ignore them, choose another algorithm or omit an integrity field without creating a protocol error. An application that requires a digest must state and enforce that requirement itself.

Integrity stops at its named object

RFC 9530 is unusually direct about the boundary. Integrity fields apply to content or representation data, not to the HTTP message or its fields in full. The specification does not define authentication, authorization or privacy.

That excludes several conclusions that operational software often compresses into one green icon. A matching digest does not prove which account sent a request. It does not prove that the sender may change a route, rotate a credential or publish a package. It does not establish that the content is well-formed, harmless, true or complete. It does not establish that a cached response is fresh. It does not show that a signed request has not been replayed.

The correct output is a predicate with an object: content_digest_matched or representation_digest_matched. The vague output verified=true destroys the very boundary the standard created.

Signing the digest is composition, not substitution

HTTP Message Signatures can protect selected HTTP components, including an integrity field. That is valuable. It can bind the declared Content-Digest value to a key and protect relevant metadata chosen by an application profile.

It does not collapse two checks into one. RFC 9421 makes component selection explicit. If Content-Digest is absent from the signature input, signature success says nothing about that field. If it is covered, the verifier must still recompute the digest over the received content and compare the result.

Consider a signed request in which the signature covers Content-Digest, the method and the target. If an intermediary or bug substitutes the body but leaves the signed digest field untouched, the signature can remain valid. Only independent digest recomputation detects that the body no longer matches the signed declaration.

The converse is equally important. If the service recomputes a digest but never verifies the signature, an unauthenticated attacker can supply a new body and matching digest. Digest verification and signature verification are adjacent controls, not aliases.

Even a valid signature is not yet authorization. The application still has to decide whether the verified key is acceptable for this operation, whether required components were covered, whether the creation and expiry parameters are acceptable, and whether nonce or other policy rejects replay. A key can be authentic and still lack permission.

Trailers create a timing boundary

RFC 9530 allows integrity fields in headers or trailers. A trailer is useful when the sender cannot calculate the digest until it has streamed the content. It also changes when the receiver has enough evidence to act.

If an application commits state while the body is streaming and checks the trailer afterward, a later mismatch may arrive after the irreversible action. The safe design stages data or uses a transaction boundary that remains reversible until the complete body and integrity field have been validated.

Carriage also differs across HTTP versions. HTTP/1.1 has trailer-section and framing rules; HTTP/2 carries a final field block after DATA; HTTP/3 has its own field-section and stream behavior. Frameworks and intermediaries may discard, merge or expose trailers differently. A configuration promise is not proof. The production path must demonstrate that the final application sees the field and waits for the result before acting.

Fresh bytes can still be stale evidence

A cached object can retain the exact bytes it had yesterday. Its digest can match perfectly today. HTTP caching rules—not the digest—decide whether it is fresh, whether it must be revalidated and whether a stale response may be reused.

The same separation applies to replay. A captured signed request can contain an intact body, an intact digest and a valid signature. If the application accepts it twice, none of those checks has failed. Freshness windows, nonces, request identifiers and idempotency policy control whether repetition is allowed.

Semantic validation is another ledger. A configuration file can be byte-perfect and syntactically valid yet grant an attacker administrator access. A software archive can match its publisher's digest and still contain vulnerable code. Integrity preserves the object presented to the hash; it does not approve the object's effect.

The negative tests define the claim

Begin with the case most checksum demos omit: create malicious content, compute the correct digest and submit both. The integrity check must pass, while authentication or authorization rejects the action. That single test proves whether the service understands its own green badge.

Then alter one body byte while retaining the digest, and alter the digest while retaining the body. Both paths must fail before state change. Sign a request that omits Content-Digest from its covered components and prove the signature cannot be promoted into content coverage. Next, sign the field, modify the body and demonstrate that signature-only validation is insufficient until the digest is recomputed.

Exercise multiple algorithms, including unknown, deprecated and locally forbidden choices. Ordering must not create a downgrade. Run the same payload through compression, decompression, range processing and representation reconstruction. Every component must name the byte domain it verified.

Finally, deliver the field as a trailer through every supported proxy and HTTP version. Replay a valid signed request. Serve stale cached bytes with a matching digest. Feed syntactically valid but operationally dangerous content. The expected result is not one universal failure; it is that each independent gate reports exactly the claim it owns.