зеркало из https://github.com/mozilla/hawk.git
Merge pull request #198 from Dreyer/fix_readme
Updated usage example in README.md
This commit is contained in:
Коммит
05e585d410
90
README.md
90
README.md
|
@ -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).
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче