A Method for Signing an HTTP Requests
for OAuthThe MITRE Corporationjricher@mitre.orgPing Identityve7jtb@ve7jtb.comhttp://www.thread-safe.com/ARM LimitedAustriaHannes.Tschofenig@gmx.nethttp://www.tschofenig.priv.at
Security
OAuth Working GroupThis document a method for offering data origin authentication and
integrity protection of HTTP requests. To convey the relevant data items
in the request a JSON-based encapsulation is used and the JSON Web
Signature (JWS) technique is re-used. JWS offers integrity protection
using symmetric as well as asymmetric cryptography.In order to protect an HTTP request with a signature, a method for
conveying various parameters and to compute a signature is needed.
Ideally, this should be done without replicating the information already
present in the HTTP request. This version of the document still
replicates most of the headers though.The keying material required for this signature calculation is
distributed via mechanisms described in companion documents (see and ). The JSON Web Signature
(JWS) specification is
re-used for computing a digital signature (which uses asymmetric
cryptography) or a keyed message digest (in case of symmetric
cryptography).The scope of the mechanism described in this document is shown in
where a client in possession of keying material
that is tied to the access token creates a JSON object, signs it, and
issues an request to a resource server for access to a protected
resource.Many HTTP application frameworks insert extra headers, query
parameters, and otherwise manipulate the HTTP request on its way from
the web server into the application code itself. It is the goal of this
draft to have a signature protection mechanism that is sufficiently
robust against such deployment constraints (while still providing
sufficient security benefits).The method of conveying the token and signed request to the protected
resource server is undefined by this document, but could be re-used.The mechanism described in this document does not provide
authentication of the resource server to the client. This version of the
document does not provide a cryptographic binding to Transport Layer
Security (TLS) used underneath the an HTTPS request.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 RFC 2119.We use the term 'sign' (or 'signature') to denote both a keyed
message digest and a digital signature operation.This section describes how to generate a JSON object below is
included as a member of the JSON object. All members are OPTIONAL.The HTTP Method used to make this request. This MUST
be the uppercase HTTP verb as a JSON string.The HTTP URL host component as a JSON string. This
MAY include the port separated from the host by a colon in host:port
format.The HTTP URL path component of the request as an
HTTP string.The hashed HTTP URL query parameter map of the
request as a two-part JSON array. The first part of this array is a
JSON array listing all query parameters that were used in the
calculation of the hash in the order that they were added to the
hashed value as described below. The second part of this array is a
JSON string containing the Base64URL encoded hash itself, calculated
as described below.The hashed HTTP request headers as a two-part JSON
array. The first part of this array is a JSON array listing all
headers that were used in the calculation of the hash in the order
that they were added to the hashed value as described below. The
second part of this array is a JSON string containing the Base64URL
encoded hash itself, calculated as described below.The base64URL encoded hash of the HTTP Request body,
calculated as the HMAC of the byte array of the body.The "ts" (timestamp) element provides replay
protection of the JSON object. Its value MUST be a number containing
an IntDate value representing number of whole integer seconds from
midnight, January 1, 1970 GMT.The hashes SHALL be calculated using the HMAC algorithm using a
hash size equal to the size of the surrounding JWT's alg header field.
That is, if the JWT uses HS256 or RS256, the HMAC here uses a 256-bit
HMAC. If the JWT uses RS512, the HMAC here uses 512-bit HMAC, and so
forth.To generate the query parameter list and hash, the client creates
two data objects: an ordered list of strings to hold the query
parameter names and a string buffer to hold the data to be hashed.The client iterates through all query parameters in whatever order
it chooses and for each query parameter it does the following:Adds the name of the query parameter to the end of the
list.Encodes the name and value of the query parameter as
"name=value" and appends it to the string buffer. [[Separated by
an ampersand? Alternatively we could have this also pulled into an
ordered list and post-process the concatenation, but that might be
too deep into the weeds. ]]Repeated parameter names are processed separately with no
special handling. Parameters MAY be skipped by the client if they are
not required (or desired) to be covered by the signature.The client then calculates the HMAC hash over the resulting string
buffer. The list and the hash result are added as the value of the "p"
member.To generate the header list and hash, the client creates two data
objects: an ordered list of strings to hold the header names and a
string buffer to hold the data to be hashed.The client iterates through all query parameters in whatever order
it chooses and for each query parameter it does the following:Adds the name of the header to the end of the list.Encodes the name and value of the header as "name: value" and
appends it to the string buffer. [[Separated by a newline?
Alternatively we could have this also pulled into an ordered list
and post-process the concatenation, but that might be too deep
into the weeds. ]]Repeated header names are processed separately with no
special handling. Headers MAY be skipped by the client if they are not
required (or desired) to be covered by the signature.The client then calculates the HMAC hash over the resulting string
buffer. The list and the hash result are added as the value of the "h"
member.Validation of the overall signature is done using the standard JWS
mechanisms for JSON structures. However, in order to trust any of the
hashed mechanisms above, an application MUST re-create and verify a hash
for each component. Additionally, an application MUST compare the
replicated values included in various JSON fields with the actual header
fields of the request. Failure to-do so will allow an attacker to modify
the underlying request, connect do different resources while at the same
time having the application layer verify the signature correctly.The client has at its disposal a map that indexes the query
parameter names to the values given. The client creates a string
buffer for calculating the hash. The client then iterates through the
"list" portion of the "p" parameter. For each item in the list (in the
order of the list) it does the following:Fetch the value of the parameter from the HTTP request
parameter map. If a parameter is found in the list of signed
parameters but not in the map, the validation fails.Encode the parameter as "name=value" and concatenate it to the
end of the string buffer. [[same separator issue as above.]]The client calculates the hash of the string buffer and base64url
encodes it. The client compares that string to the string passed in as
the hash. If the two match, the hash validates, and all named
parameters and their values are considered covered by the
signature.There MAY be additional query parameters that are not listed in the
list and are therefore not covered by the signature. The client MUST
decide whether or not to accept a request with these uncovered
parameters.The client has at its disposal a map that indexes the header names
to the values given. The client creates a string buffer for
calculating the hash. The client then iterates through the "list"
portion of the "h" parameter. For each item in the list (in the order
of the list) it does the following:Fetch the value of the header from the HTTP request header map.
If a header is found in the list of signed parameters but not in
the map, the validation fails.Encode the parameter as "name: value" and concatenate it to the
end of the string buffer. [[same separator issue as above.]]The client calculates the hash of the string buffer and base64url
encodes it. The client compares that string to the string passed in as
the hash. If the two match, the hash validates, and all named headers
and their values are considered covered by the signature.There MAY be additional headers that are not listed in the list and
are therefore not covered by the signature. The client MUST decide
whether or not to accept a request with these uncovered headers.Example goes in here but will look like something like this
(symmetric key case). Section 11.1 of defines the OAuth Access
Token Type Registry and this document adds another token type to this
registry.pop(none)Proof-of-possession
access token for use with OAuth 2.0IETF[[ this document ]]This specification registers the pop
type value in the IANA JSON Web Signature and Encryption Type Values
registry : "typ" Header Parameter Value: popAbbreviation for MIME Type: NoneChange Controller: IETFSpecification Document(s): [[ this document ]]This specification can be used with and without Transport Layer
Security (TLS).Without TLS this protocol provides a mechanism for verifying the
integrity of requests, it provides no confidentiality protection.
Consequently, eavesdroppers will have full access to communication
content and any further messages exchanged between the client and the
resource server. This could be problematic when data is exchanged that
requires care, such as personal data.When TLS is used then confidentiality can be ensured; this version
of the specification does, however, not provide the TLS channel
binding feature, which ensures that the TLS channel is
cryptographically bound to the application layer protocol
authentication defined in this document.The use of TLS in combination with the signed HTTP request
mechanism is highly recommended to ensure the confidentiality of the
user's data.This protocol allows clients to verify the authenticity of resource
servers only when TLS is used. With TLS the resource server is
authenticated as part of the TLS handshake. The mechanism described in
this document does not provide any mechanism for the client to
authenticate the resource server at the application layer.The mechanism described in this document works similar to many
three party authentication and key exchange mechanisms. In order to
compute the signature over the HTTP request, the client must have
access to a key bound to the access token (in plaintext form).If an attacker were to gain access to these stored secrets at the
client or (in case of symmetric keys) at the resource server he or she
would be able to perform any action on behalf of any client.It is therefore paramount to the security of the protocol that the
private keys associated with the access tokens are protected from
unauthorized access.Unless TLS is used between the client and the resource server,
eavesdroppers will have full access to requests sent by the client.
They will thus be able to mount off-line brute-force attacks to
recover the session key or private key used to compute the keyed
message digest or digital signature, respectively.This specification assumes that the keying material for use with
the described HTTP signing mechanism has been distributed via other
mechanisms, such as . Hence, it is the
responsibility of the authorization server and or the client to be
careful when generating fresh and unique keys with sufficient entropy
to resist such attacks for at least the length of time that the
session keys (and the access tokens) are valid.For example, if the key bound to the access token is valid for one
day, authorization servers must ensure that it is not possible to
mount a brute force attack that recovers that key in less than one
day. Of course, servers are urged to err on the side of caution, and
use the longest key length reasonable.This specification includes a number of features which may make
resource exhaustion attacks against resource servers possible. For
example, a resource server may need to need to the resource server has
to process the incoming request, verify the access token, perform
signature verification, and might have (in certain circumstances)
consult back-end databases or the authorization server before granting
access to the protected resource.An attacker may exploit this to perform a denial of service attack
by sending a large number of invalid requests to the server. The
computational overhead of verifying the keyed message digest alone is,
however, not sufficient to mount a denial of service attack since
keyed message digest functions belong to the computationally fastest
cryptographic algorithms. The situation may, however, be different
when using asymmetric cryptography, which is also supported by the
JWS.This specification provides flexibility for selectively protecting
header fields and even the body of the message. Since all components
of the HTTP request are only optionally protected by this method, and
even some components may be protected only in part (e.g., some headers
but not others) it is up to application developers to verify that any
parameters in a request are actually covered by the signature.The application verifying this signature MUST NOT assume that any
particular parameter is appropriately covered by the signature. Any
applications that are sensitive of header or query parameter order
MUST verify the order of the parameters on their own. The application
MUST also compare the values in the JSON container with the actual
parameters received with the HTTP request. Failure to make this
comparison will render the signature mechanism useless.The authors acknowledge the OAuth Working Group and submit this draft
for feedback and input into the ongoing work of signed HTTP requests for
the interaction between clients and resource servers.