Merge pull request #198 from Dreyer/fix_readme

Updated usage example in README.md
This commit is contained in:
Eran Hammer 2016-09-06 15:09:52 -07:00 коммит произвёл GitHub
Родитель 7ea2c0a926 40a9fabc3a
Коммит 05e585d410
1 изменённых файлов: 47 добавлений и 43 удалений

Просмотреть файл

@ -71,12 +71,12 @@ and the server.
## Replay Protection
Without replay protection, an attacker can use a compromised (but otherwise valid and authenticated) request more
than once, gaining access to a protected resource. To mitigate this, clients include both a nonce and a timestamp when
Without replay protection, an attacker can use a compromised (but otherwise valid and authenticated) request more
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.
The nonce is generated by the client, and is a string unique across all requests with the same timestamp and
key identifier combination.
key identifier combination.
The timestamp enables the server to restrict the validity period of the credentials where requests occurring afterwards
are rejected. It also removes the need for the server to retain an unbounded number of nonce values for future checks.
@ -99,15 +99,15 @@ the number of round trips required to authenticate the first request.
Server code:
```javascript
var Http = require('http');
var Hawk = require('hawk');
const Http = require('http');
const Hawk = require('hawk');
// Credentials lookup function
var credentialsFunc = function (id, callback) {
const credentialsFunc = function (id, callback) {
var credentials = {
const credentials = {
key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
algorithm: 'sha256',
user: 'Steve'
@ -118,20 +118,20 @@ var credentialsFunc = function (id, callback) {
// Create HTTP server
var handler = function (req, res) {
const handler = function (req, res) {
// Authenticate incoming request
Hawk.server.authenticate(req, credentialsFunc, {}, function (err, credentials, artifacts) {
Hawk.server.authenticate(req, credentialsFunc, {}, (err, credentials, artifacts) => {
// Prepare response
var payload = (!err ? 'Hello ' + credentials.user + ' ' + artifacts.ext : 'Shoosh!');
var headers = { 'Content-Type': 'text/plain' };
const payload = (!err ? `Hello ${credentials.user} ${artifacts.ext}` : 'Shoosh!');
const headers = { 'Content-Type': 'text/plain' };
// Generate Server-Authorization response header
var header = Hawk.server.header(credentials, artifacts, { payload: payload, contentType: headers['Content-Type'] });
const header = Hawk.server.header(credentials, artifacts, { payload, contentType: headers['Content-Type'] });
headers['Server-Authorization'] = header;
// Send the response back
@ -149,13 +149,13 @@ Http.createServer(handler).listen(8000, 'example.com');
Client code:
```javascript
var Request = require('request');
var Hawk = require('hawk');
const Request = require('request');
const Hawk = require('hawk');
// Client credentials
var credentials = {
const credentials = {
id: 'dh37fgj492je',
key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
algorithm: 'sha256'
@ -163,7 +163,7 @@ var credentials = {
// Request options
var requestOptions = {
const requestOptions = {
uri: 'http://example.com:8000/resource/1?b=1&a=2',
method: 'GET',
headers: {}
@ -171,7 +171,7 @@ var requestOptions = {
// Generate Authorization request header
var header = Hawk.client.header('http://example.com:8000/resource/1?b=1&a=2', 'GET', { credentials: credentials, ext: 'some-app-data' });
const header = Hawk.client.header('http://example.com:8000/resource/1?b=1&a=2', 'GET', { credentials: credentials, ext: 'some-app-data' });
requestOptions.headers.Authorization = header.field;
// Send authenticated request
@ -180,11 +180,11 @@ Request(requestOptions, function (error, response, body) {
// Authenticate the server's response
var isValid = Hawk.client.authenticate(response, credentials, header.artifacts, { payload: body });
const isValid = Hawk.client.authenticate(response, credentials, header.artifacts, { payload: body });
// Output results
console.log(response.statusCode + ': ' + body + (isValid ? ' (valid)' : ' (invalid)'));
console.log(`${response.statusCode}: ${body}` + (isValid ? ' (valid)' : ' (invalid)'));
});
```
@ -213,12 +213,12 @@ HTTP/1.1 401 Unauthorized
WWW-Authenticate: Hawk
```
The client has previously obtained a set of **Hawk** credentials for accessing resources on the "http://example.com/"
The client has previously obtained a set of **Hawk** credentials for accessing resources on the "`http://example.com/`"
server. The **Hawk** credentials issued to the client include the following attributes:
* Key identifier: dh37fgj492je
* Key: werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn
* Algorithm: sha256
* Key identifier: `dh37fgj492je`
* Key: `werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn`
* Algorithm: `sha256`
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 (each value followed by a newline
@ -237,7 +237,7 @@ some-app-ext-data
```
The request MAC is calculated using HMAC with the specified hash algorithm "sha256" and the key over the normalized request string.
The request MAC is calculated using HMAC with the specified hash algorithm "`sha256`" and the key over the normalized request string.
The result is base64-encoded to produce the request MAC:
```
@ -310,7 +310,7 @@ Host: example.com:8000
Authorization: Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", hash="Yi9LfIIFRtBEPt74PVmbTF/xVAwPn7ub15ePICfgnuY=", ext="some-app-ext-data", mac="aSe1DERmZuRl3pI36/9BdZmnErTw3sNzOOAUlfeKjVw="
```
It is up to the server if and when it validates the payload for any given request, based solely on it's security policy
It is up to the server if and when it validates the payload for any given request, based solely on its security policy
and the nature of the data included.
If the payload is available at the time of authentication, the server uses the hash value provided by the client to construct
@ -332,7 +332,7 @@ by the client, the payload may be modified by an attacker.
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
The header is constructed 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.
@ -369,7 +369,7 @@ and for a finite period of time. Both the client and server can issue bewit cred
credentials as the client to maintain clear traceability as to who issued which credentials.
In order to simplify implementation, bewit credentials do not support single-use policy and can be replayed multiple times within
the granted access timeframe.
the granted access timeframe.
## Bewit Usage Example
@ -377,15 +377,15 @@ the granted access timeframe.
Server code:
```javascript
var Http = require('http');
var Hawk = require('hawk');
const Http = require('http');
const Hawk = require('hawk');
// Credentials lookup function
var credentialsFunc = function (id, callback) {
const credentialsFunc = function (id, callback) {
var credentials = {
const credentials = {
key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
algorithm: 'sha256'
};
@ -395,9 +395,9 @@ var credentialsFunc = function (id, callback) {
// Create HTTP server
var handler = function (req, res) {
const handler = function (req, res) {
Hawk.uri.authenticate(req, credentialsFunc, {}, function (err, credentials, attributes) {
Hawk.uri.authenticate(req, credentialsFunc, {}, (err, credentials, attributes) => {
res.writeHead(!err ? 200 : 401, { 'Content-Type': 'text/plain' });
res.end(!err ? 'Access granted' : 'Shoosh!');
@ -410,13 +410,13 @@ Http.createServer(handler).listen(8000, 'example.com');
Bewit code generation:
```javascript
var Request = require('request');
var Hawk = require('hawk');
const Request = require('request');
const Hawk = require('hawk');
// Client credentials
var credentials = {
const credentials = {
id: 'dh37fgj492je',
key: 'werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn',
algorithm: 'sha256'
@ -424,9 +424,13 @@ var credentials = {
// Generate bewit
var duration = 60 * 5; // 5 Minutes
var bewit = Hawk.uri.getBewit('http://example.com:8080/resource/1?b=1&a=2', { credentials: credentials, ttlSec: duration, ext: 'some-app-data' });
var uri = 'http://example.com:8000/resource/1?b=1&a=2' + '&bewit=' + bewit;
const duration = 60 * 5; // 5 Minutes
const bewit = Hawk.uri.getBewit('http://example.com:8000/resource/1?b=1&a=2', { credentials: credentials, ttlSec: duration, ext: 'some-app-data' });
const uri = 'http://example.com:8000/resource/1?b=1&a=2' + '&bewit=' + bewit;
// Output URI
console.log('URI: ' + uri);
```
@ -492,9 +496,9 @@ which can often affect how the request body is interpreted by the server. If the
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.
The response authentication, when performed, only covers the response payload, content-type, and the request information
provided by the client in its 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
@ -527,7 +531,7 @@ and sensitive information.
### Host Header Forgery
Hawk validates the incoming request MAC against the incoming HTTP Host header. However, unless the optional `host` and `port`
options are used with `server.authenticate()`, a malicous client can mint new host names pointing to the server's IP address and
options are used with `server.authenticate()`, a malicious client can mint new host names pointing to the server's IP address and
use that to craft an attack by sending a valid request that's meant for another hostname than the one used by the server. Server
implementors must manually verify that the host header received matches their expectation (or use the options mentioned above).