hawk
Advanced tools
Comparing version 0.10.0 to 0.10.1
@@ -39,3 +39,3 @@ // Load modules | ||
'Content-Type': 'text/plain', | ||
'Authorization': Hawk.server.header(artifacts, { payload: payload, contentType: 'text/plain' }) | ||
'Server-Authorization': Hawk.server.header(artifacts, { payload: payload, contentType: 'text/plain' }) | ||
}; | ||
@@ -70,3 +70,2 @@ | ||
console.log(options.headers.authorization); | ||
@@ -73,0 +72,0 @@ Request(options, function (error, response, body) { |
@@ -142,3 +142,3 @@ // Load modules | ||
payload: optional payload received | ||
required: specifies is an Authorization header is required. Defaults to 'false' | ||
required: specifies if a Server-Authorization header is required. Defaults to 'false' | ||
} | ||
@@ -169,5 +169,5 @@ */ | ||
// Parse HTTP Authorization header | ||
// Parse HTTP Server-Authorization header | ||
if (!res.headers.authorization && | ||
if (!res.headers['server-authorization'] && | ||
!options.required) { | ||
@@ -178,3 +178,3 @@ | ||
var attributes = Utils.parseAuthorizationHeader(res.headers.authorization, ['mac', 'ext', 'hash']); | ||
var attributes = Utils.parseAuthorizationHeader(res.headers['server-authorization'], ['mac', 'ext', 'hash']); | ||
if (attributes instanceof Error) { | ||
@@ -181,0 +181,0 @@ return false; |
@@ -220,3 +220,3 @@ // Load modules | ||
// Generate an Authorization header for a given response | ||
// Generate a Server-Authorization header for a given response | ||
@@ -255,3 +255,2 @@ /* | ||
if (!credentials || | ||
!artifacts.id || | ||
!credentials.key || | ||
@@ -258,0 +257,0 @@ !credentials.algorithm) { |
{ | ||
"name": "hawk", | ||
"description": "HTTP Hawk Authentication Scheme", | ||
"version": "0.10.0", | ||
"version": "0.10.1", | ||
"author": "Eran Hammer <eran@hueniverse.com> (http://hueniverse.com)", | ||
@@ -6,0 +6,0 @@ "contributors": [], |
181
README.md
@@ -8,4 +8,2 @@ ![hawk Logo](https://raw.github.com/hueniverse/hawk/master/images/hawk.png) | ||
Last protocol change: **0.10.0** (changed payload hash method) | ||
[![Build Status](https://secure.travis-ci.org/hueniverse/hawk.png)](http://travis-ci.org/hueniverse/hawk) | ||
@@ -20,2 +18,3 @@ | ||
- [Payload Validation](#payload-validation) | ||
- [Response Payload Validation](#response-payload-validation) | ||
<p></p> | ||
@@ -43,8 +42,8 @@ - [**Single URI Authorization**](#single-uri-authorization) | ||
**Hawk** is an HTTP authentication scheme providing mechanisms for making authenticated HTTP requests with | ||
partial cryptographic verification of the request, covering the HTTP method, request URI, host, and optionally | ||
the request payload. | ||
partial cryptographic verification of the request and response, covering the HTTP method, request URI, host, | ||
and optionally the request payload. | ||
Similar to the HTTP [Digest access authentication schemes](http://www.ietf.org/rfc/rfc2617.txt), **Hawk** uses a set of | ||
client credentials which include a identifier (username) and key (password). Likewise, just as with the Digest scheme, | ||
the key is never included in authenticated requests; instead, it is used to calculate a request MAC value which is | ||
client credentials which include an identifier (e.g. username) and key (e.g. password). Likewise, just as with the Digest scheme, | ||
the key is never included in authenticated requests. Instead, it is used to calculate a request MAC value which is | ||
included in its place. | ||
@@ -54,5 +53,5 @@ | ||
replay attacks, in **Hawk** the client generates the nonce and uses it in combination with a timestamp, leading to less | ||
interaction with the server ("chattiness"). | ||
"chattiness" (interaction with the server). | ||
Also unlike Digest, this scheme is not intended to protect the key itself (called the password in Digest) because | ||
Also unlike Digest, this scheme is not intended to protect the key itself (the password in Digest) because | ||
the client and server must both have access to the key material in the clear. | ||
@@ -62,7 +61,9 @@ | ||
* simplify and improve HTTP authentication for services that are unwilling or unable to deploy TLS for all resources, | ||
* secure credentials against leakage (e.g., when the client uses some form of dynamic configuration to determine where to send an authenticated request), and | ||
* avoid the exposure of credentials sent to a malicious server over an unauthenticated secure channel due to client failure to validate the server's identity as part of its TLS handshake. | ||
* secure credentials against leakage (e.g., when the client uses some form of dynamic configuration to determine where | ||
to send an authenticated request), and | ||
* avoid the exposure of credentials sent to a malicious server over an unauthenticated secure channel due to client | ||
failure to validate the server's identity as part of its TLS handshake. | ||
In addition, **Hawk** supports a method for granting third-parties temporary access to individual resources using | ||
a query parameter called _bewit_ (leather straps used to attach a tracking device to the leg of a hawk). | ||
a query parameter called _bewit_ (in falconry, a leather strap used to attach a tracking device to the leg of a hawk). | ||
@@ -79,3 +80,3 @@ The **Hawk** scheme requires the establishment of a shared symmetric key between the client and the server, | ||
than once, gaining access to a protected resource. To mitigate this, clients include both a nonce and a timestamp when | ||
making requests; this gives the server enough information to prevent replay attacks. | ||
making requests. This gives the server enough information to prevent replay attacks. | ||
@@ -85,11 +86,10 @@ The nonce is generated by the client, and is a string unique across all requests with the same timestamp and | ||
The timestamp enables the server to restrict the validity period of the credentials; requests occuring afterwards | ||
The timestamp enables the server to restrict the validity period of the credentials where requests occuring afterwards | ||
are rejected. It also removes the need for the server to retain an unbounded number of nonce values for future checks. | ||
By default, **Hawk** uses a time window of 1 minute to allow for time skew between the client and server (which in | ||
translates to a maximum of 2 minutes as the skew can be positive or negative). | ||
practice translates to a maximum of 2 minutes as the skew can be positive or negative). | ||
Using a timestamp requires the client's clock to be in sync with the server's clock. **Hawk** requires both the client | ||
clock and the server clock to use NTP to ensure synchronization. However, given the limitations of some client types | ||
(e.g. browsers) to deploy NTP, the server provides the client with its current time in response to a bad timestamp or | ||
as part of an authentication challenge. | ||
(e.g. browsers) to deploy NTP, the server provides the client with its current time in response to a bad timestamp. | ||
@@ -99,3 +99,3 @@ There is no expectation that the client will adjust its system clock to match the server (in fact, this would be a | ||
for communications with that particular server. The protocol rewards clients with synchronized clocks by reducing | ||
the number of round trips required to authentication to a single request. | ||
the number of round trips required to authenticate the first request. | ||
@@ -138,6 +138,6 @@ | ||
// Generate Authorization response header | ||
// Generate Server-Authorization response header | ||
var header = Hawk.server.header(artifacts, { payload: payload, contentType: headers['Content-Type'] }); | ||
headers.Authorization = header; | ||
headers['Server-Authorization'] = header; | ||
@@ -216,8 +216,7 @@ // Send the response back | ||
The resource server returns an authentication challenge. The challenge provides the client with the server's current | ||
time and NTP server used for clock sync, which enable the client to offset its clock when making requests. | ||
The resource server returns an authentication challenge. | ||
``` | ||
HTTP/1.1 401 Unauthorized | ||
WWW-Authenticate: Hawk ts="1353832200" | ||
WWW-Authenticate: Hawk | ||
``` | ||
@@ -233,3 +232,4 @@ | ||
The client generates the authentication header by calculating a timestamp (e.g. the number of seconds since January 1, | ||
1970 00:00:00 GMT), generating a nonce, and constructing the normalized request string (newline separated values): | ||
1970 00:00:00 GMT), generating a nonce, and constructing the normalized request string (each value followed by a newline | ||
character): | ||
@@ -249,7 +249,2 @@ ``` | ||
The 'hawk.1.header' normalized string header is used to prevent MAC values from being reused after a potential change in how the | ||
protocol creates the normalized string. For example, if a future version would switch the order of nonce and timestamp, it | ||
can create an exploit opportunity for cases where the nonce is similar in format to a timestamp. In addition, the header | ||
prevents switching MAC values between a header request and a bewit request. | ||
The request MAC is calculated using HMAC with the specified hash algorithm "sha256" and the key over the normalized request string. | ||
@@ -263,3 +258,3 @@ The result is base64-encoded to produce the request MAC: | ||
The client includes the **Hawk** key identifier, timestamp, nonce, application specific data, and request MAC with the request using | ||
the HTTP "Authorization" request header field: | ||
the HTTP `Authorization` request header field: | ||
@@ -279,3 +274,3 @@ ``` | ||
**Hawk** provides optional payload validation. When generating the authentication header, the client calculates a payload hash | ||
using the specified hash algorithm. The hash is calculated over the concatenated value of: | ||
using the specified hash algorithm. The hash is calculated over the concatenated value of (each followed by a newline character): | ||
* `hawk.1.payload` | ||
@@ -291,3 +286,3 @@ * the content-type in lowercase, without any parameters (e.g. `application/json`) | ||
Results in the following input to the payload hash function (newline separated values): | ||
Results in the following input to the payload hash function (newline terminated values): | ||
@@ -307,3 +302,3 @@ ``` | ||
The client constructs the normalized request string (newline separated values): | ||
The client constructs the normalized request string (newline terminated values): | ||
@@ -324,3 +319,3 @@ ``` | ||
Then calculates the request MAC and includes the **Hawk** key identifier, timestamp, nonce, payload hash, application specific data, | ||
and request MAC with the request using the HTTP "Authorization" request header field: | ||
and request MAC, with the request using the HTTP `Authorization` request header field: | ||
@@ -345,8 +340,26 @@ ``` | ||
It is important to note that MAC validation does not mean the hash value provided by the client is valid, only that the value | ||
included in the header was nor modified. Without calculating the payload hash on the server and comparing it to the value provided | ||
included in the header was not modified. Without calculating the payload hash on the server and comparing it to the value provided | ||
by the client, the payload may be modified by an attacker. | ||
## Response Payload Validation | ||
**Hawk** provides partial response payload validation. The server includes the `Server-Authorization` response header which enables the | ||
client to authenticate the response and ensure it is talking to the right server. **Hawk** defines the HTTP `Server-Authorization` header | ||
as a response header using the exact same syntax as the `Authorization` request header field. | ||
The header is contructed using the same process as the client's request header. The server uses the same credentials and other | ||
artifacts provided by the client to constructs the normalized request string. The `ext` and `hash` values are replaced with | ||
new values based on the server response. The rest as identical to those used by the client. | ||
The result MAC digest is included with the optional `hash` and `ext` values: | ||
``` | ||
Server-Authorization: Hawk mac="XIJRsMl/4oL+nn+vKoeVZPdCHXB4yJkNnBbTbHFZUYE=", hash="f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=", ext="response-specific" | ||
``` | ||
# Single URI Authorization | ||
There are often cases in which limited and short-term access is granted to protected resource to a third party which does not | ||
There are cases in which limited and short-term access to a protected resource is granted to a third party which does not | ||
have access to the shared credentials. For example, displaying a protected image on a web page accessed by anyone. **Hawk** | ||
@@ -356,3 +369,3 @@ provides limited support for such URIs in the form of a _bewit_ - a URI query parameter appended to the request URI which contains | ||
Because of the significant security risks involved in issuing such access, bewit usage is purposely limited to only GET requests | ||
Because of the significant security risks involved in issuing such access, bewit usage is purposely limited only to GET requests | ||
and for a finite period of time. Both the client and server can issue bewit credentials, however, the server should not use the same | ||
@@ -428,2 +441,3 @@ credentials as the client to maintain clear traceability as to who issued which credentials. | ||
an incomplete list of security considerations that must be reviewed and understood before deploying **Hawk** on the server. | ||
Many of the protections provided in **Hawk** depends on whether and how they are used. | ||
@@ -444,7 +458,10 @@ ### MAC Keys Transmission | ||
**Hawk** makes no attempt to verify the authenticity of the server. A hostile party could take advantage of this by intercepting | ||
the client's requests and returning misleading or otherwise incorrect responses. Service providers should consider such attacks | ||
when developing services using this protocol, and should require transport-layer security for any requests where the authenticity | ||
of the resource server or of server responses is an issue. | ||
**Hawk** provides limited verification of the server authenticity. When receiving a response back from the server, the server | ||
may choose to include a response `Server-Authorization` header which the client can use to verify the response. However, it is up to | ||
the server to determine when such measure is included, to up to the client to enforce that policy. | ||
A hostile party could take advantage of this by intercepting the client's requests and returning misleading or otherwise | ||
incorrect responses. Service providers should consider such attacks when developing services using this protocol, and should | ||
require transport-layer security for any requests where the authenticity of the resource server or of server responses is an issue. | ||
### Plaintext Storage of Credentials | ||
@@ -478,12 +495,15 @@ | ||
The request MAC only covers the HTTP `Host` header and does not cover any other headers which can often affect how the request | ||
body is interpreted by the server (i.e. Content-Type). If the server behavior is influenced by the presence or value of such headers, | ||
an attacker can manipulate the request header without being detected. Implementers should use the `ext` feature to pass | ||
application-specific information via the Authorization header which is protected by the request MAC. | ||
The request MAC only covers the HTTP `Host` header and optionally the `Content-Type` header. It does not cover any other headers | ||
which can often affect how the request body is interpreted by the server. If the server behavior is influenced by the presence | ||
or value of such headers, an attacker can manipulate the request headers without being detected. Implementers should use the | ||
`ext` feature to pass application-specific information via the `Authorization` header which is protected by the request MAC. | ||
The response authentication, when performed, only covers the response payload, content-type, and the request information | ||
provided by the client in it's request (method, resource, timestamp, nonce, etc.). It does not cover the HTTP status code or | ||
any other response header field (e.g. Location) which can affect the client's behaviour. | ||
### Future Time Manipulation | ||
The protocol relies on a clock sync between the client and server. To accomplish this, the server informs the client of its | ||
current time as well as identifies the NTP server used (the client can opt to use either one to calculate the offset used for | ||
further interactions with the server). | ||
current time when an invalid timestamp is received. | ||
@@ -495,4 +515,5 @@ If an attacker is able to manipulate this information and cause the client to use an incorrect time, it would be able to cause | ||
The client must only use the time information provided by the server if it is sent over a TLS connection and the server identity | ||
has been verified. | ||
The client must only use the time information provided by the server if: | ||
* it was delivered over a TLS connection and the server identity has been verified, or | ||
* the `tsm` MAC digest calculated using the same client credentials over the timestamp has been verified. | ||
@@ -518,3 +539,3 @@ ### Client Clock Poisoning | ||
If you are looking for some prose explaining how all this works, there isn't any. **Hawk** is being developed as an open source | ||
If you are looking for some prose explaining how all this works, **this is it**. **Hawk** is being developed as an open source | ||
project instead of a standard. In other words, the [code](/hueniverse/hawk/tree/master/lib) is the specification. Not sure about | ||
@@ -525,19 +546,9 @@ something? Open an issue! | ||
No but it's getting close. Until this module reaches version 1.0.0 it is considered experimental and is likely to change. This also | ||
means your feedback and contribution are very welcome. Feel free to open issues with questions and suggestions. | ||
At if version 0.10.0, **Hawk** is feature-complete. However, until this module reaches version 1.0.0 it is considered experimental | ||
and is likely to change. This also means your feedback and contribution are very welcome. Feel free to open issues with questions | ||
and suggestions. | ||
### Does **Hawk** have anything to do with OAuth? | ||
Short answer: no. | ||
**Hawk** was originally proposed as the OAuth MAC Token specification. However, the OAuth working group in its consistent | ||
incompetence failed to produce a final, usable solution to address one of the most popular use cases of OAuth 1.0 - using it | ||
to authenticate simple client-server transactions (i.e. two-legged). | ||
**Hawk** provides a simple HTTP authentication scheme for making client-server requests. It does not address the OAuth use case | ||
of delegating access to a third party. If you are looking for an OAuth alternative, check out [Oz](/hueniverse/oz). | ||
### Where can I find **Hawk** implementations in other languages? | ||
**Hawk** is only officially implemented in JavaScript as a node.js module. However, others are actively porting it to other | ||
**Hawk**'s only reference implementation is provided in JavaScript as a node.js module. However, others are actively porting it to other | ||
platforms. There is already a [PHP](https://github.com/alexbilbie/PHP-Hawk), | ||
@@ -552,12 +563,12 @@ [.NET](https://github.com/pcibraro/hawknet), and [JAVA](https://github.com/wealdtech/hawk) libraries available. The full list | ||
requirements). While some keys can be used for multiple algorithm, the protocol is designed to closely bind the key and algorithm | ||
together as part of the issued credentials. | ||
together as part of the issued credentials. | ||
### Why is Host the only header covered by the request MAC? | ||
### Why is Host and Content-Type the only headers covered by the request MAC? | ||
It is really hard to include other headers. Headers can be changed by proxies and other intermediaries and there is no | ||
well-established way to normalize them. The only straight-forward solution is to include the headers in some blob (say, | ||
bas64 encoded JSON) and include that with the request, an approach taken by JWT and other such formats. However, that | ||
design violates the HTTP header boundaries, repeats information, and introduces other security issues because firewalls | ||
will not be aware of these "hidden" headers. In addition, any information repeated must be compared to the duplicated | ||
information in the header and therefore only moves the problem elsewhere. | ||
well-established way to normalize them. Many platforms change the case of header field names and values. The only | ||
straight-forward solution is to include the headers in some blob (say, base64 encoded JSON) and include that with the request, | ||
an approach taken by JWT and other such formats. However, that design violates the HTTP header boundaries, repeats information, | ||
and introduces other security issues because firewalls will not be aware of these "hidden" headers. In addition, any information | ||
repeated must be compared to the duplicated information in the header and therefore only moves the problem elsewhere. | ||
@@ -568,4 +579,3 @@ ### Why not just use HTTP Digest? | ||
a protocol handshake to the server. This pattern has become unacceptable for most web services, especially mobile | ||
where extra round-trip are costly. While Hawk includes support for sending a challenge when a request lacks | ||
authentication, it does not require it. | ||
where extra round-trip are costly. | ||
@@ -575,3 +585,3 @@ ### Why bother with all this nonce and timestamp business? | ||
**Hawk** is an attempt to find a reasonable, practical compromise between security and usability. OAuth 1.0 got timestamp | ||
and nonces half the way right but failed when it came to scalability and consistent developer experience. **Hawk** addresses | ||
and nonces halfway right but failed when it came to scalability and consistent developer experience. **Hawk** addresses | ||
it by requiring the client to sync its clock, but provides it with tools to accomplish it. | ||
@@ -591,7 +601,26 @@ | ||
to use credentials issued to someone else. It also has an optional 'delegated-by' attribute `dlg` which is the application id of the | ||
application the credentials were directly issued to. | ||
application the credentials were directly issued to. The goal of these two additions is to allow Oz to utilize **Hawk** directly, | ||
but with the additional security of delegated credentials. | ||
The goal of these two additions is to allow Oz to utilize **Hawk** directly, but with the additional security of delegated credentials. | ||
The additional support has been added without breaking or affecting **Hawk**-only use cases. | ||
### What is the purpose of the static strings used in each normalized MAC input? | ||
When calculating a hash or MAC, a static prefix (tag) is added. The prefix is used to prevent MAC values from being | ||
used or reused for a purpose other than what they were created for (i.e. prevents switching MAC values between a request, | ||
response, and a bewit use cases). It also protects against expliots created after a potential change in how the protocol | ||
creates the normalized string. For example, if a future version would switch the order of nonce and timestamp, it | ||
can create an exploit opportunity for cases where the nonce is similar in format to a timestamp. | ||
### Does **Hawk** have anything to do with OAuth? | ||
Short answer: no. | ||
**Hawk** was originally proposed as the OAuth MAC Token specification. However, the OAuth working group in its consistent | ||
incompetence failed to produce a final, usable solution to address one of the most popular use cases of OAuth 1.0 - using it | ||
to authenticate simple client-server transactions (i.e. two-legged). As you can guess, the OAuth working group is still hard | ||
at work to produce more garbage. | ||
**Hawk** provides a simple HTTP authentication scheme for making client-server requests. It does not address the OAuth use case | ||
of delegating access to a third party. If you are looking for an OAuth alternative, check out [Oz](/hueniverse/oz). | ||
# Acknowledgements | ||
@@ -598,0 +627,0 @@ |
@@ -89,3 +89,3 @@ // Load modules | ||
headers: { | ||
'authorization': 'Hawk mac="abc", bad="xyz"' | ||
'server-authorization': 'Hawk mac="abc", bad="xyz"' | ||
} | ||
@@ -103,3 +103,3 @@ }; | ||
'content-type': 'text/plain', | ||
'authorization': 'Hawk mac="_IJRsMl/4oL+nn+vKoeVZPdCHXB4yJkNnBbTbHFZUYE=", hash="f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=", ext="response-specific"' | ||
'server-authorization': 'Hawk mac="_IJRsMl/4oL+nn+vKoeVZPdCHXB4yJkNnBbTbHFZUYE=", hash="f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=", ext="response-specific"' | ||
} | ||
@@ -139,3 +139,3 @@ }; | ||
'content-type': 'text/plain', | ||
'authorization': 'Hawk mac="XIJRsMl/4oL+nn+vKoeVZPdCHXB4yJkNnBbTbHFZUYE=", hash="f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=", ext="response-specific"' | ||
'server-authorization': 'Hawk mac="XIJRsMl/4oL+nn+vKoeVZPdCHXB4yJkNnBbTbHFZUYE=", hash="f9cDF/TDm7TkYRLnGwRMfeDzT6LixQVLvrIKhh0vgmM=", ext="response-specific"' | ||
} | ||
@@ -142,0 +142,0 @@ }; |
@@ -87,4 +87,4 @@ // Load modules | ||
res.headers.authorization = Hawk.server.header(artifacts, { payload: 'some reply', contentType: 'text/plain', ext: 'response-specific' }); | ||
expect(res.headers.authorization).to.exist; | ||
res.headers['server-authorization'] = Hawk.server.header(artifacts, { payload: 'some reply', contentType: 'text/plain', ext: 'response-specific' }); | ||
expect(res.headers['server-authorization']).to.exist; | ||
@@ -91,0 +91,0 @@ expect(Hawk.client.authenticate(res, artifacts, { payload: 'some reply' })).to.equal(true); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
204835
605
2
2014