You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 4 Next »

Hash Authentication

This document describes a method of providing client applications the ability to authenticate to our APIs. These APIs are Web APIs; clients use simple HTTP requests and responses to send and receive data.

We use a client applciation "username", a shared secret and a derived hash value to authenticate the requests, to determine which client application is talking to our API. The shared secret will be a string known to both the client application and the API back end. Typically, IS&T determines the value of the secret and communicates the value to the client application developer through a secure channel: a phone conversation, perhaps.

Example

A simple API request URI for retrieving a class list might look like this:

GET /esapis/v1.0/classlist?term=2015SP&subject=8.011

To use the hash authentication scheme, the client would add three additional request parameters to the request:

  • user (an IS&T-assigned username representing the client system)

  • timestamp (the current date and time)

  • derived hash token

The hash token is determined by concatenating parameter values (including the timestamp, but not including the user) being sent in the request with the shared secret string, and then running the resultant string through the SHA256 hashing algorithm. The resulting string will be added as the final parameter in the request; its parameter name will be “hash”.

For example, let’s say the shared secret is “September”, the assigned user is "gravytrain",  and that the following data is being sent in the GET request:

Before sending the request, the client will add a timestamp to the data in the request, so now the request will be something like:

 

GET /esapis/v1.0/classlist?term=2015SP&subject=8.011&timestamp=20140715113137

 

Then (also before the request is sent) to derive the hash value, the client will:

a) concatenate the parameter values data (not the parameter names) with the shared secret, giving:

2015SP8.01120140715113137September

The order of the values in this string is important - the API will be expecting the values in a particular order, so we will need to agree on an order and make sure we always use the same order.

b) run this string through the SHA-256 hash algorithm to give:

275607e4db71e75ba9a3d5e091efaf0f5e550cbbcf0a8a3b4502a960bdcebc85

c) add this hash value as a request parameter

d) add the “user” parameter to the request, so the data finally sent in the request is:

GET /esapis/v1.0/classlist?term=2015SP&subject=8.011&timestamp=20140715113137&user=gravytrain&hash=275607e4db71e75ba9a3d5e091efaf0f5e550cbbcf0a8a3b4502a960bdcebc85&user=gravytrain

When this request is received by the API backend, the API will use the same procedure to derive a SHA-256 hash value, using the data from the incoming request. If the API's derived hash matches the incoming hash, the request will be deemed to be valid. If not, the request will be rejected.

The timestamp will be used to expire requests. When the API receives a request, even if the hash algorithm passes the test described above, we will then check the timestamp - if the timestamp is older than some pre-agreed interval (say, 5 minutes) the request will be rejected.

Sample Code (Python)

The following code illustrates the generation of the URI used in the above example in the Python language. In this example, the following pre-determined values are used:

  1. The client app's "user name" is: "gravytrain"
  2. The shared secret value is: "327nPW8"

IMPORTANT: we would never hard-code the value of the secret in a script in a production application; we would pass it in as a command-line argument or read it from a secure configuration file. The hard-coding is done here just to simplify the example.

import urllib2
import json
import hashlib
import datetime

# The base URL:
urlBase="https://esapis-test.mit.edu:8443/esapis/v1.0/classlist?term=2015SP&subject=8.011"

# For authentication, as well as the base query parameters (term and subject), 
# the URL must include these additional query parameters:
#    user, timestamp, hash
#
# Form the hash variable (SHA-256 hash of base parameter values + timestamp + shared secret).

user = "gravytrain"
secret = "September"

timeStamp = datetime.datetime.today().strftime('%Y%m%d%H%M%S')
toBeHashed = "2015SP" + "8.011" + timeStamp + secret
hashObj = hashlib.sha256(toBeHashed.encode())

# Complete the URL string by adding the additional parameters (timestamp, user, and hash):
url = urlBase + "&timestamp=" + timeStamp + "&user=" + user + "&hash=" + hashObj.hexdigest()

# Get the data from the API in JSON form.
result = json.load(urllib2.urlopen(url))

 

Some Other Languages/Environments

Other languages provide similar capability for generating SHA256 hash values. All the examples are generating hashes for a string with value "some value".

Java:
import java.security.MessageDigest;

...

        String textToBeHashed = "some value";
        MessageDigest digest = MessageDigest.getInstance(args[1]);
        byte[] hash = digest.digest(textToBeHashed.getBytes("UTF-8"));    
        StringBuffer hexString = new StringBuffer();
        for (int i = 0; i < hash.length; i++) {
            String hex = Integer.toHexString(0xff & hash[i]);
            if(hex.length() == 1) hexString.append('0');
            hexString.append(hex);
        }
Bash Shell Command Line:
echo -n "some value"|sha256sum
Javascript:
<script type="text/javascript" src="sjcl.min.js" ></script>

<script language="JavaScript" type="text/javascript">
	var bitArray = sjcl.hash.sha256.hash("some value");
	var hash = sjcl.codec.hex.fromBits(bitArray);
</script>
  • No labels