OAuth Request Body HashGooglebeaton@google.com
Yahoo!
eran@hueniverse.comhttp://hueniverse.com
This specification extends the OAuth signature to include
integrity checks on HTTP request bodies with content types other than
application/x-www-form-urlencoded.
The OAuth Core specification provides
body integrity checking only for
application/x-www-form-urlencoded
request bodies. Other types of request bodies are left unsigned.
An eavesdropper or man-in-the-middle who captures a signed request URI
may be able to forward or replay that URI with a different HTTP
request body. Nonce checking and the use of https can mitigate this
risk, but may not be available in some environments. Even when
nonce checking and https are used, signing the request body provides
an additional layer of defense.
This specification describes a method to provide an integrity check
on non-form-encoded request bodies. The normal OAuth signature
base string is enhanced by adding an additional parameter with the hash
of the request body. An unkeyed hash is used for the reasons
described in .
This extension is forward compatible: Service Providers
that have not implemented this extension can verify requests
sent by Consumers that have implemented this extension.
If the Service Provider
implements this specification the integrity of the body is guaranteed.
If the Service Provider does not check body signatures, the remainder
of the request will still validate using the OAuth Core signature
algorithm.
This specification is only useful when cryptographic signatures
are used. The OAuth PLAINTEXT signature algorithm does not provide
integrity checks for any portion of the request and is not supported
by this specification.
The use of this specification with versions of the OAuth protocol other than
1.0 is undefined.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in
.
Unless otherwise noted, this specification is written as a direct
continuation of , inheriting the
definitions and guidelines set by it.
To make the specification easier to read, HTTP entity-bodies
following the encoding
requirements of the
application/x-www-form-urlencoded
content-type as defined by
are simply referred to as form-encoded.
The body hash algorithm is determined by the OAuth signature method used:
If the OAuth signature method is HMAC-SHA1
or RSA-SHA1, SHA1 MUST be used
as the body hash algorithm.
If the OAuth signature method is PLAINTEXT, use of this
specification provides no security benefit and is NOT RECOMMENDED.
New OAuth signature method specifications SHOULD specify the hash
algorithm used to generate the body hash.
The value of the oauth_body_hash parameter SHALL be set as follows:
The body hash value is calculated by executing the selected
hash algorithm over the request body. The request body is
the entity body as defined in
section 7.2. If the request does not have an entity body, the
hash should be taken over the empty string.
The calculated body hash value is encoded using
Base64 per .
OAuth Consumers
include the oauth_body_hash parameter according to the rules
described in this section, and continue to sign requests in the
manner described by section 9.
Not all requests should contain the oauth_body_hash parameter.
OAuth Consumers SHOULD NOT include an oauth_body_hash parameter
when making Request Token or Access Token OAuth requests.
OAuth Consumers MUST NOT include an oauth_body_hash parameter on
requests with form-encoded request bodies. The presence or absence
OAuth Consumers SHOULD include the oauth_body_hash parameter on all
other requests.
Some OAuth Service
Providers have implemented Request Token and Access Token endpoints
that reject requests that include unknown parameters. Sending
an oauth_body_hash parameter to such endpoints will cause protocol
failures. The oauth_body_hash parameter does not provide additional
security for OAuth request token and access token requests since
all of
the protocol parameters are signed by the OAuth Core signature
mechanism. Omitting the parameter improves interoperability without
reducing security.
The presence or absence
of the oauth_body_hash parameter is used to indicate to Service
Providers how they should check the integrity of the request body.
If no oauth_body_hash parameter is present, that indicates that
the request body is form-encoded and signed using the OAuth Core
signature algorithm. If the oauth_body_hash parameter is present,
the body is signed according to this extension. Including
an oauth_body_hash on form-encoded requests would make it impossible
for Service Providers to determine which body signing mechanism
was used for the request. This ambiguity would, in turn, allow
the attack described in .
To include the oauth_body_hash parameter in OAuth-authenticated
requests, Consumers SHALL:
Determine whether the parameter should be included using
the rules described in .
Calculate the body hash value as described in
Set the oauth_body_hash parameter to the obtained value.
Sign the request as per
section 9.
The oauth_body_hash parameter MUST be
included in the Signature Base String together with the
other request parameters.
Transmit the oauth_body_hash parameter along with the other
OAuth Protocol parameters in the signed OAuth request.
Service Providers verify the integrity of request bodies
by verifying the OAuth signature as described in
and also verifying the value of the
oauth_body_hash parameter.
Service Providers MUST decide whether the oauth_body_hash parameter
is necessary according to the rules described in
.
If the request MUST NOT have an oauth_body_hash parameter,
Service Providers MUST verify that no oauth_body_hash parameter is
present.
In particular, any requests with a form-encoded content-type
and an oauth_body_hash parameter MUST be rejected because of
of the attack described in .
If the request should have an oauth_body_hash parameter
but does not contain one, the request was sent by a
Consumer that does not support this extension. The integrity
of the request body cannot be checked using this specification.
Service Providers MAY accept such requests for interoperability,
or they MAY reject such requests in favor of security.
If the Service Provider determines body hash verification is
necessary, the Service Provider calculates the expected
body hash for the request as described in
.
The Service Provider then compares the expected body hash with
the value sent by the Consumer in the oauth_body_hash parameter.
If the values match, the body is intact and the request can
proceed.
If the values do not match, the request MUST be rejected.
Rather than comparing text values, Service Providers MAY
Base64 decode (per ) the oauth_body_hash parameter and perform the
comparison on the octets of the hash. This reduces the risk of
minor differences in URI encoding or Base64 encoding causing
spurious integrity check failures.
This memo includes no request to IANA.
Many factors besides the bytes of the request body can
influence the interpretation of the body of the HTTP
request. For example, a content-type or content-encoding
header can change the way a server handles an HTTP request.
This specification does not include an integrity check
on the HTTP request headers. OAuth deployments whose
security could be impacted by an attacker who tampers with
HTTP request headers should use other mechanisms (such as HTTPS)
to protect the confidentiality and integrity of the entire HTTP
request.
In
the NIST Computer Security Division has recommended that applications
stop using SHA-1 for digital signatures.
As of the time
of this writing, all of the cryptographic signature schemes defined
for OAuth are based on SHA-1. OAuth signature methods based on
stronger hash functions need to be developed, and those signature
methods will need to specify algorithms for calculating the
oauth_body_hash as well.
Sample HTTP request:
Base64 encoded SHA-1 hash of the body:
Signature Base String (with some line breaks added for
readability):
Signed request with body hash (with some line breaks added for
readability):
Sample HTTP request:
Base64 encoded SHA-1 hash of the (non-existent) body:
Signature Base String (line breaks added for readability):
Signed request with body hash (with some line breaks added for
readability):
Not all programming platforms provide an easy mechanism to obtain
the raw octets of the HTTP entity body. Reading the entity body
as raw octets may have side effects, such as inhibiting automatic
character set conversion. Some platforms do not allow
direct access to the entity body at all if the content-type
is application/x-www-form-urlencoded. Transfer-encodings such as gzip
also complicate implementation. On the other hand,
reading the entity body as text may perform lossy conversions
that prevent recovery of the original octet stream in some
situtations. Character set conversions are not always one-to-one
mappings, so solutions that rely on converting text back to the
original octet stream are likely to fail in environments with
multibyte characters.
All of these factors, and others, can make it difficult to drop in a
"verify-the-signature" filtering layer prior to other request
processing. The verification layer must consider the assumptions
of downstream processing code on the state of the request body.
Implementers of this specification should be aware of these
difficulties and consider the best way to address them in their
programming frameworks.
This specification deliberately uses an unkeyed hash algorithm
(SHA-1) to provide an integrity check on the body instead of
a keyed hash algorithm such as HMAC-SHA1. This decision was made
because signing arbitrary octet streams is poor cryptographic hygiene.
It can lead to unexpected problems with cryptographic protocols.
For example, consider a proxy that uses OAuth to add authentication
information to requests sent by an untrusted third-party. If the
proxy signs arbitrary octet streams, the third-party can use the
proxy as an oracle to forge authentication messages.
Including the result of an unkeyed hash in the normal signature
base string allows the proxy to add an integrity check on the
original message without creating a signing oracle.
This specification requires that Consumers not send the oauth_body_hash
parameter on requests with form-encoded bodies, and requires that
Service Providers reject requests that have form-encoded bodies
and an oauth_body_hash parameter. These restrictions are necessary
in order to prevent a MITM from removing non-form-encoded request
bodies. The attack would work as follows:
Consumer signs a request with a non-form-encoded request body
and includes a matching content-type header such as
"application/json" or "text/plain". The oauth_body_hash parameter
is included as well.
MITM intercepts request and modifies the content-type of the
request to be "application/x-www-form-urlencoded". The MITM
also removes the request body. The request is then forwarded
to the Service Provider.
The Service Provider receives the request and the signature
validates according to the OAuth Core signature specification.
The Service Provider then needs to decide whether to check
the oauth_body_hash value as well. Since the request content-type
is form-encoded, the Service Provider does not check the
oauth_body_hash.
The removal of the body goes undetected.
The impact of this attack is probably minimal. The attacker can
remove the request body, but cannot replace it with their own. Stil,
the goal of this specification is guaranteeing body integrity
when both Consumers and Service Providers use the oauth_body_hash
parameter. Out of an excess of caution, this specification requires
that Service Providers reject request that have both a form-encoded
request body and an oauth_body_hash parameter.
An alternate solution, requiring that Service Providers check the
oauth_body_hash parameter even on form-encoded request bodies, was
rejected due to implementation challenges. Some web development
frameworks block access to the raw entity body for form-encoded
requests.
Several members of the community contributed valuable feedback and suggestions, including
Allen Tom, Ben Laurie, Dirk Balfanz, George Fletcher, John Panzer, Louis Ryan, and Marc Worrell.
OAuth Core 1.0Special Publication 800-107, Recommendation for Applications Using Approved Hash AlgorithmsNIST Computer Security Division