Request authentication is the process of verifying the identity of the sender of a request. In the context of Amazon Web Services (AWS) requests, authentication is the process by which AWS can confirm that a request came from a registered user, as well as the identity of that registered user.
To enable authentication, each request must carry information about the identity of the request sender. The request must also contain additional information that AWS can use to verify that the request can only have been produced by the sender identified. If the request passes this verification test it is determined to be “authentic” and AWS has sufficient information to verify the identity of the sender.
Verifying the identity of the sender of a request is important, as it ensures that only those requests made by the person or party responsible for the AWS account specified in the request are accepted and allowed to interact with AWS services. In this manner, request authentication allows Amazon to track the usage of AWS services on a per request basis. This enables Amazon to charge and bill AWS subscribers for use of AWS paid (not free) services.
To access Amazon web services, a developer must create an AWS account. AWS accounts are associated with Amazon.com accounts. To sign in to an AWS account, a developer uses his or her Amazon.com account e-mail and password.
Upon creating the AWS account, the developer is assigned an Access Key ID (AWSAccessKeyId) and a Secret Access Key. The Access Key ID, which is associated with the AWS account, is used in requests to identify the party responsible for the request. However, because an Access Key ID is sent as a request parameter, it is not secret and could be used by anyone sending a request to AWS. To protect from impersonation, the request sender must provide additional information that can be used to verify the sender’s identity and ensure that the request is legitimate. This additional information, a request signature that is calculated using the Secret Access Key, demonstrates possession of a shared secret known only to AWS and the sender of the request. A Secret Access Key is a 20-character alphanumeric sequence generated by AWS.
There are two types of requests to AWS:
Anonymous requests—Requests to free services can be made anonymously
Though a valid Access Key ID must be included in all requests to AWS, no attempt is made to confirm that the request originated from the party responsible for the AWS account associated with the Access Key ID. In other words, no authentication is necessary for the request to succeed.
Services to which anonymous requests can be made include: Amazon E-Commerce Service (ECS) 4.0 and Amazon Simple Queue Service (SQS).
Authenticated requests—Services that want to track service usage, either for the purpose of calculating usage statistics or to bill for usage, must be able to verify that the identity of the sender of a request is the person or party responsible for the AWS account
The identity of the sender is verified by confirming that the Secret Access Key used in the request signature is the Secret Access Key associated with the Access Key ID included in the request.
Services to which authenticated requests must be made include: Amazon Mechanical Turk Service, Alexa Web Information Service (AWIS).
To use a service that requires authenticated requests, a signature for each request must be calculated and included as the value of the Signature parameter in requests to those services.
Requests to AWS are authenticated by verifying information contained within the request. This verification is performed using the following information:
| Parameter | Description |
|---|---|
AWSAccessKeyId | The sender’s AWS account is identified by the Access Key ID. The Access Key ID is used to look up the Secret Access Key. |
Signature | Each request to a web service that requires authenticated requests must contain a valid request signature, or the request is rejected. A request signature is calculated using the Secret Access Key assigned to the developer's account by AWS, which is a shared secret known only to AWS and the developer. |
Timestamp | The date and time the request was created, represented as a string in UTC. The format of the value of this parameter must match the format of the XML Schema dateTime data type. |
Following are the basic tasks used in authenticating requests to AWS. It is assumed that the developer has already registered with AWS and received an Access Key ID and Secret Access Key.
Authenticating Requests
1 | The sender constructs a request to AWS. |
2 |
The sender calculates a Keyed-Hashing for Message Authentication code (HMAC), the request signature
using the his or her Secret Access Key and the values of the |
3 | The sender of the request sends the request data, the signature, and Access Key ID (the key-identifier of the Secret Access Key used) to AWS. |
4 | AWS uses the Access Key ID to look up the Secret Access Key. |
5 | AWS generates a signature from the request data and the Secret Access Key using the same algorithm used to calculate the signature in the request. |
6 | If the signature generated by AWS matches the one sent in the request, the request is considered to be authentic. If the comparison fails, the request is discarded, and AWS returns an error response. |
A request signature, an HMAC, is calculated by concatenating the values of the Service, Operation, and Timestamp parameters, in that order, and then calculating an RFC 2104-compliant HMAC, using the Secret Access Key as the "key." The computed HMAC value should be base64 encoded, and is passed as the value of the Signature request parameter. For more information, please see http://www.faqs.org/rfcs/rfc2104.html.
When a request is received, AWS verifies the request signature by computing an HMAC value for the request and comparing the value of that HMAC with the value in the request. If the computed HMAC value matches the HMAC value in the request, the identity of the sender is verified and the request is accepted. If the values do not match the request is rejected, and an error is returned.
Requests can be sent using REST (XML over HTTP) or SOAP. The contents of the request are the same, only the request format differs.
The result of the SHA-1 hash is binary data. An encoding must be specified to include this in either a SOAP or REST request. Both REST and SOAP requests should be Base64 encoded.
However, as the results of Base64 encoding can contain characters that are not legal in a URL, such as plus signs (+),slashes (/), and equal signs (=), results for REST requests should be URL encoded, as specified in RFC 1738, section 2.2.
The following code sample demonstrates how to calculate a request signature to sign authenticated requests to AWS.
package amazon.webservices.common;
import java.security.SignatureException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
/**
* This class defines common routines for generating
* authentication signatures for AWS Platform requests.
*/
public class Signature {
private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";
/**
* Computes RFC 2104-compliant HMAC signature.
*
* @param data
* The data to be signed.
* @param key
* The signing key.
* @return
* The Base64-encoded RFC 2104-compliant HMAC signature.
* @throws
* java.security.SignatureException when signature generation fails
*/
public static String calculateRFC2104HMAC(String data, String key)
throws java.security.SignatureException
{
String result;
try {
// get an hmac_sha1 key from the raw key bytes
SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(),
HMAC_SHA1_ALGORITHM);
// get an hmac_sha1 Mac instance and initialize with the signing key
Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
mac.init(signingKey);
// compute the hmac on input data bytes
byte[] rawHmac = mac.doFinal(data.getBytes());
// base64-encode the hmac
result = Encoding.EncodeBase64(rawHmac);
}
catch (Exception e) {
throw new SignatureException("Failed to generate HMAC : " + e.getMessage());
}
return result;
}
}This sample, provided in support of the previous sample for calculating HMAC signatures, demonstrates how to perform Base64 encoding of input types in AWS requests.
package amazon.webservices.common;
/**
* This class defines common routines for encoding
* data in AWS Platform requests.
*/
public class Encoding {
/**
* Performs base64-encoding of input bytes.
*
* @param rawData
* Array of bytes to be encoded.
* @return
* The base64-encoded string representation of rawData.
*/
public static String EncodeBase64(byte[] rawData) {
return Base64.encodeBytes(rawData);
}
}This sample demonstrates how to encode and decode to and from Base64 notation. The code for this sample is not included in this document due to the length of the file. The code, which is public domain, can be accessed using this link: http://iharder.net/base64.