In Object Storage Service (OSS), the most common identity verification method is to include a signature in the Authorization header of an HTTP request. With the exception of POST and URL signatures, all OSS operations must be authenticated using the Authorization header. This topic describes how to use the V1 signature algorithm to include a signature in the header.
OSS supports the V4 signature algorithm, which provides better security. We recommend that you use the V4 signature. For more information, see V4 signature.
SDK signature implementation
OSS SDKs automatically handle V1 signatures. You do not need to manually calculate the signature when you use an SDK. To understand the implementation for a specific language, you can view the SDK's source code. The following table lists the signature implementation files for each SDK.
|
SDK |
Signature implementation |
|
Java |
|
|
PHP |
|
|
Node.js |
|
|
Browser.js |
|
|
Python |
|
|
.Net |
|
|
Android |
|
|
Go |
|
|
iOS |
|
|
C++ |
|
|
C |
|
|
Ruby |
How to calculate the Authorization field
Calculation method
Authorization = "OSS " + AccessKeyId + ":" + Signature
Signature = base64(hmac-sha1(AccessKeySecret,
VERB + "\n"
+ Content-MD5 + "\n"
+ Content-Type + "\n"
+ Date + "\n"
+ CanonicalizedOSSHeaders
+ CanonicalizedResource))
Parameters
|
Parameter |
Type |
Required |
Example |
Description |
|
AccessKeyId |
String |
Yes |
LTAI******************** |
Your AccessKey pair, which consists of an AccessKey ID and an AccessKey secret.
|
|
AccessKeySecret |
String |
Yes |
yourAccessKeySecret |
|
|
x-oss-security-token |
String |
No |
CAIS******************************** |
The Security Token Service (STS) token. This parameter is required only when you use STS to construct the signature for the header. For more information about how to obtain a security token, see AssumeRole. |
|
VERB |
Enumeration |
Yes |
PUT |
The HTTP request method, such as PUT, GET, POST, HEAD, DELETE, or OPTIONS. |
|
\n |
String |
No |
\n |
The line feed character. |
|
Content-MD5 |
String |
No |
eB5e******************** |
The MD5 hash of the request body. To calculate this value, compute the 128-bit MD5 hash of the message body (excluding headers), and then Base64-encode the result. For more information, see RFC2616 Content-MD5. This request header can be used to check message integrity. The message is valid if the received content is the same as the sent content. This parameter can be empty. For more information about how to calculate the Content-MD5 value, see How to calculate Content-MD5. |
|
Content-Type |
String |
No |
application/octet-stream |
The type of the request content. This parameter can be empty. Note
If you do not set Content-Type when you generate the signature, you do not need to set this parameter when you use the signature to upload a file. |
|
Date |
String |
Yes |
Sun, 22 Nov 2015 08:16:38 GMT |
The time of the operation. The value must be in GMT format and cannot be empty. The value is taken from the Date or x-oss-date field in the request header. If both fields exist, x-oss-date takes precedence. Important
If the time specified in the Date header of a request differs from the OSS server time by more than 15 minutes, OSS rejects the request and returns an HTTP 403 error. |
|
CanonicalizedOSSHeaders |
String |
No |
x-oss-meta-a:a\nx-oss-meta-b:b\nx-oss-meta-c:c\n |
The HTTP headers that are prefixed with
For more information about how to construct this string, see How to construct CanonicalizedOSSHeaders. |
|
CanonicalizedResource |
String |
Yes |
examplebucket |
The OSS resource that you want to access. This string cannot be empty. For more information about how to construct this string, see How to construct CanonicalizedResource. |
Signature examples
-
Example 1 (includes all parameters)
Request
Formula for the string to be signed
String to be signed
PUT /nelson HTTP/1.0 Content-MD5: eB5e******************** Content-Type: text/html Date: Wed, 28 Dec 2022 10:27:41 GMT Host: examplebucket.oss-cn-hangzhou.aliyuncs.com x-oss-meta-author: alice x-oss-meta-magic: abracadabra
Signature = base64(hmac-sha1(AccessKeySecret, VERB + "\n" + Content-MD5 + "\n" + Content-Type + "\n" + Date + "\n" + CanonicalizedOSSHeaders + CanonicalizedResource))
PUT\n eB5e********************\n text/html\n Wed, 28 Dec 2022 10:27:41 GMT\n x-oss-meta-magic:abracadabra\nx-oss-meta-author:alice\n/examplebucket/nelson
If the AccessKey ID is LTAI**************** and the AccessKey secret is yourAccessKeySecret, you can use the following Python code to calculate the signature.
import hmac import hashlib import base64 h = hmac.new("yourAccessKeySecret".encode('utf-8'), "PUT\nODBGOERFMDMzQTczRUY3NUE3NzA5QzdFNUYzMDQxNEM\ntext/html\nWed, 28 Dec 2022 10:27:41 GMT\nx-oss-meta-magic:abracadabra\nx-oss-meta-author:alice\n/oss-example/nelson".encode('utf-8'), hashlib.sha1) signature = base64.encodebytes(h.digest()) print(signature)The calculated signature is
J9Nl************************. The final request is structured as follows.PUT /nelson HTTP/1.0 Authorization:OSS LTAI****************:J9Nl************************ Content-Md5: eB5e******************** Content-Type: text/html Date: Wed, 28 Dec 2022 10:27:41 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com x-oss-meta-author: alice x-oss-meta-magic: abracadabra -
Example 2 (excludes the optional parameters Content-MD5 and Content-Type)
Request
Formula for the string to be signed
String to be signed
PUT /nelson HTTP/1.0 Date: Wed, 28 Dec 2022 09:56:32 GMT Host: examplebucket.oss-cn-hangzhou.aliyuncs.com x-oss-meta-author: alice x-oss-meta-magic: abracadabra
Signature = base64(hmac-sha1(AccessKeySecret, VERB + "\n" + "\n" + "\n" + Date + "\n" + CanonicalizedOSSHeaders + CanonicalizedResource))
PUT\n\n\nWed, 28 Dec 2022 09:56:32 GMT\n x-oss-meta-magic:abracadabra\nx-oss-meta-author:alice\n/examplebucket/nelson
In this example, the AccessKey ID is LTAI**************** and the AccessKey secret is yourAccessKeySecret. The following Python code shows how to calculate the signature.
import hmac import hashlib import base64 h = hmac.new("yourAccessKeySecret".encode('utf-8'), "PUT\n\n\nWed, 28 Dec 2022 09:56:32 GMT\nx-oss-meta-magic:abracadabra\nx-oss-meta-author:alice\n/oss-example/nelson".encode('utf-8'), hashlib.sha1) signature = base64.encodebytes(h.digest()) print(signature)The calculated signature is
Mhb1************************. The final request is structured as follows.PUT /nelson HTTP/1.0 Authorization:OSS LTAI****************:Mhb1************************ Date: Wed, 28 Dec 2022 09:56:32 GMT Host: oss-example.oss-cn-hangzhou.aliyuncs.com x-oss-meta-author: alice x-oss-meta-magic: abracadabra
Additional information
-
If the provided AccessKey ID does not exist or is inactive, OSS returns a 403 Forbidden error with the error code InvalidAccessKeyId. If the AccessKey ID is active but OSS detects a signature error in the request, OSS returns a 403 Forbidden error. The response includes the correct string to be signed, which you can use to verify your signing process.
The following code shows a sample response:
<?xml version="1.0" ?> <Error> <Code> SignatureDoesNotMatch </Code> <Message> The request signature we calculated does not match the signature you provided. Check your key and signing method. </Message> <StringToSignBytes> 47 45 54 0a 0a 0a 57 65 64 2c 20 31 31 20 4d 61 79 20 32 30 31 31 20 30 37 3a 35 39 3a 32 35 20 47 4d 54 0a 2f 75 73 72 65 61 6c 74 65 73 74 3f 61 63 6c </StringToSignBytes> <RequestId> 1E446260FF9B**** </RequestId> <HostId> oss-cn-hangzhou.aliyuncs.*** </HostId> <SignatureProvided> y5H7************************ </SignatureProvided> <StringToSign> GET Wed, 11 May 2011 07:59:25 GMT /examplebucket?acl </StringToSign> <OSSAccessKeyId> AKIA**************** </OSSAccessKeyId> </Error> -
If the format of the Authorization value in the request header is incorrect, OSS returns a 400 Bad Request error with the error code InvalidArgument.
-
All requests sent to OSS must use the GMT date format specified in HTTP 1.1. The date format is as follows:
date1 = 2DIGIT SP month SP 4DIGIT; day month year (e.g., 02 Jun 1982)NoteIn the preceding date format,
dayis a two-digit number. Therefore,Jun 2,2 Jun 1982, and2-Jun-1982are all invalid date formats.-
If the Date header is missing from a signed request or is in an invalid format, OSS returns a 403 Forbidden error with the error code AccessDenied.
-
The time in the request must be within 15 minutes of the current OSS server time. Otherwise, OSS returns a 403 Forbidden error with the error code RequestTimeTooSkewed.
-
How to construct CanonicalizedOSSHeaders
All HTTP headers that are prefixed with x-oss- are known as canonicalized OSS headers. To construct the CanonicalizedOSSHeaders string, follow these steps:
-
Convert the names of all HTTP request headers that are prefixed with
x-oss-to lowercase. For example, convertX-OSS-Meta-Name: TaoBaotox-oss-meta-name: TaoBao. -
If you send a request using temporary access credentials from Security Token Service (STS), you must add the security token to the string to be signed in the format
x-oss-security-token:security-token.NoteFor more information about how to configure STS, see Use temporary credentials provided by STS to access OSS. You can call the AssumeRole operation or use STS SDKs for various programming languages to obtain temporary access credentials. Temporary access credentials contain a security token and a temporary AccessKey pair. An AccessKey pair consists of an AccessKey ID and an AccessKey secret.
-
Sort all retrieved HTTP request headers in lexicographical order by header name.
-
Remove any whitespace on either side of the colon that separates the header name and value. For example, convert
x-oss-meta-name: TaoBaotox-oss-meta-name:TaoBao. -
Concatenate the processed headers. Separate each header with a line feed character (
\n) to create the CanonicalizedOSSHeaders string.
How to construct CanonicalizedResource
The target OSS resource that you want to access in a request is known as the canonicalized resource. To construct the CanonicalizedResource string, follow these rules:
-
If the resource includes a bucket and an object, set CanonicalizedResource to /BucketName/ObjectName.
-
If the resource includes only a bucket, set CanonicalizedResource to /BucketName/.
-
If the resource does not include a bucket or an object, set CanonicalizedResource to a forward slash (/).
-
If the request includes subresources, sort all subresources in lexicographical order and join them with an ampersand (
&) to create a subresource string. Append a question mark (?) and the subresource string to the end of the CanonicalizedResource string. The resulting CanonicalizedResource string is in the format/BucketName/ObjectName?acl&uploadId=UploadId.OSS supports the following four types of subresources:
-
Resource identifiers, such as acl, uploads, location, cors, logging, website, referer, lifecycle, delete, append, tagging, objectMeta, uploadId, partNumber, security-token, position, img, style, styleName, replication, replicationProgress, replicationLocation, cname, bucketInfo, comp, qos, live, status, vod, startTime, endTime, symlink, x-oss-process, callback, and callback-var. For more information, see Bucket operations and Object operations.
ImportantResource identifiers are case-sensitive.
-
Response header fields, such as response-content-language, response-expires, response-cache-control, response-content-disposition, and response-content-encoding. For more information, see GetObject.
-
Image processing methods, such as
x-oss-process. For more information, see Image processing. -
Access control fields that start with
x-oss-ac-*, such as x-oss-ac-source-ip, x-oss-ac-subnet-mask, x-oss-ac-vpc-id, and x-oss-ac-forward-allow. For more information, see Signature version 1.NoteAfter you generate a signature using a CanonicalizedResource string that contains the x-oss-ac-source-ip parameter, remove x-oss-ac-source-ip from the query parameters of the request to protect the IP address.
-
Signature calculation rules
-
The string to be signed must be in
UTF-8format. A string that contains Chinese characters must first be encoded inUTF-8before it is used with theAccessKeySecretto calculate the signature. -
The signature is calculated using the HMAC-SHA1 method as defined in RFC 2104. The key for the calculation is your AccessKey secret.
-
Content-TypeandContent-MD5are not required in a request. If these headers are absent from a request that requires signature verification, you must still include a line feed character (\n) for each in the string to be signed. -
Only non-standard HTTP headers that start with
x-oss-must be included in the string to be signed. For example, the x-oss-meta-magic header in the signature examples must be included. Other non-standard HTTP headers are ignored by OSS.NoteHeaders that start with
x-oss-must be processed according to the following rules before signature verification:-
The header names must be in lowercase.
-
The headers must be sorted in lexicographical order by name.
-
There must be no space before or after the colon that separates the header name and value.
-
Each header must be separated by a line feed character (\n). If no such headers are specified, the CanonicalizedOSSHeaders string is empty.
-
How to calculate Content-MD5
This section uses the message content "0123456789" as an example to show the correct and incorrect ways to calculate the Content-MD5 value.
-
Correct calculation
-
First, calculate the MD5 hash, which is a 128-bit binary array.
-
Base64-encode the binary array, not the 32-character hexadecimal string.
The following example uses Python:
>>> import base64,hashlib >>> hash = hashlib.md5() >>> hash.update("0123456789") # In Python 3, change this to hash.update(b"0123456789"). >>> base64.b64encode(hash.digest()) 'eB5e********************'The hash.digest() method returns the 128-bit binary array.
>>> hash.digest() 'x\x1e^$]i\xb5f\x97\x9b\x86\xe2\x8d#\xf2\xc7' -
-
Example of an incorrect calculation
NoteA common mistake is to directly Base64-encode the 32-character hexadecimal string.
# The hash.hexdigest() method calculates the visible 32-character hexadecimal string. >>> hash.hexdigest() '781e****************************' # The result of Base64-encoding the incorrect MD5 hash. >>> base64.b64encode(hash.hexdigest()) 'Nzgx****************************************'