Sign a request and validate the signature
Before calling an API, you must sign all HTTP or HTTPS API requests to ensure security and then need to validate the response signature accordingly.
Sign a request
See the following figure for an overview of the signature creation process:
Figure 1. Signature creation process
Procedure
- Obtain your private key, represented by
privateKey
, which is used to sign a request. - Construct the content to be signed (
Content_To_Be_Signed
). - Calculate and generate the signature.
- Add the generated signature to the request header.
For details of each step, see the following examples.
Example
1. Obtain your private key to sign the request
You can create asymmetric keys in your own way or by using the tool provided in the Alipay Developer Center. You can set up and then exchange keys for the sandbox and production environments respectively with the provided tool. The following figure shows where you can obtain the key generation tool and configure the key.
Besides using the tool to generate RSA2 key pair, you can also generate the RSA2 key pairs manually, for example:
# 1. Generating the private key
openssl genrsa -out client_private_key_php_dotnet.pem
# 2. If you are a Java developer, convert the private key to PKCS8 format
openssl pkcs8 -topk8 -inform PEM -in client_private_key_php_dotnet.pem -outform PEM -nocrypt -out client_private_key_pkcs8.pem
# 3. Generate the public key
openssl rsa -in client_private_key_php_dotnet.pem -pubout -out client_public_key_php_dotnet.pem
# 4. Generate the private key that can be used in Java
cat client_private_key_pkcs8.pem | grep -v "^\-" | tr -d "\n" | sed 's/%$//' > client_private_key_java.pem
# 5. Generate the public key that can be used in Java
cat client_public_key_php_dotnet.pem | grep -v "^\-" | tr -d "\n" | sed 's/%$//' > client_public_key_java.pem
2. Construct the content to be signed
Create the string to sign. The string to be signed is:
<HTTP Method> <HTTP-URI-with-query-string>
<Client-Id>.<Request-Time|Response-Time>.<HTTP body>
HTTP_method
: POSTHTTP_URI_with_query_string
: For example, if the HTTP URL is https://xxx/openapi/transfer/transfer, this field is/openapi/transfer/transfer
.client-Id
: is used to identify a client, and is associated with the keys that are used for signature and encryption. You can get this field from the request header.request-time
: Specifies the time when a request is sent, as defined by RFC3339. This field must be accurate to milliseconds. For example,2019-05-28T12:12:12+08:00
. You can get this field from the request header.HTTP_BODY
: the data body of the request.
3. Calculate and generate the signature
Generate the signature. Use the algorithm and private key obtained in step1 to generate the signature. The following example assumes that RSA256 algorithm is used to generate the signature, the string-to-sign
var is obtained from step 2:
signature=base64UrlEncode(sha256withrsa(<unsignedContent>), <privateKey>))
The content to be signed is <unsignedContent
>, the algorithm used is RSA 256, and the private key value is <privateKey>
.
Demo code:
/**
*
* @param requestURI // domain part excluded, sample: /ams/api/v1/payments/pay
* @param clientId
* @param requestTime
* @param privateKey
* @param requestBody
* @return
*/
public static String sign(String requestURI, String clientId, String requestTime,
String privateKey, String requestBody) {
String content = String.format("POST %s\n%s.%s.%s", requestURI, clientId, requestTime,
requestBody);
try {
java.security.Signature signature = java.security.Signature
.getInstance("SHA256withRSA");
PrivateKey priKey = KeyFactory.getInstance("RSA").generatePrivate(
new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey.getBytes("UTF-8"))));
signature.initSign(priKey);
signature.update(content.getBytes("UTF-8"));
byte[] signed = signature.sign();
return URLEncoder.encode(new String(Base64.encodeBase64(signed), "UTF-8"), "UTF-8");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
4. Add the generated signature to the request header
Add the signature to header. Assemble the signature algorithm, the key version used for the signature, and the signature into Signature header. The following example shows a finished Signature header, the signature
var is obtained from step 2:
key: Signature ;
value:algorithm=<algorithm>,keyVersion=<key-version>,signature=<signature>
algorithm
,keyVersion
: see the header of the Message structure chapter.signature
: the signature that is generated in step 3.
Handle a response
See the following figure for an overview of the signature validation process:
Figure 2. Signature validation process
Validate a signature
- Obtain the platform public key.
- Construct the content to be validated (
Content_To_Be_Validated
). - Extract the signature from the response header.
- Validate the signature.
For details of each step, see the following examples.
Example
1. Obtain the platform public key
Obtain the public key, see Obtain your private key to sign the request for details. Obtain Client-Id and algorithm from header.
2. Construct the content to be validated
Create the string to be validated. The string to be signed is:
<HTTP Method> <HTTP-URI-with-query-string>
<Client-Id>.<Request-Time|Response-Time>.<HTTP body>
HTTP_METHOD
: POSTHTTP_URI_WITH_QUERY_STRING
: For example, if the HTTP URL is https://xxx/openapi/transfer/transfer, this field is/openapi/transfer/transfer
.Client-Id
: is used to identify a client, and is associated with the keys that are used for signature and encryption. You can get this field from the request header.response-Time
: Specifies the time when a request is sent, as defined by RFC3339. This field must be accurate to milliseconds. For example,2019-05-28T12:12:14+08:00
. You can get this field from the response header.HTTP_BODY
: the data body of the response.
3. Get the signature from the response header and validate the signature
Use the algorithm obtained in step 1 to calculate a digest of the string you created in step 2. Then, decrypt the signature by using the public key to get a digest. Compare two digests, if the digests match the signature is verified. For example, assume RSA256 algorithm is used, base64url decode the signature content to obtain the original signature, and then validate the signature by using the sender's public key and sha256withrsa algorithm.
sha256withrsa_verify(base64UrlDecode(<signature>), <content_to_be_verified>, <serverPublicKey>)
sha256withrsa_verify
: the method to verify the signature.base64UrlDecode
: the method to decode the signature.signature
: Signature string from the response.content_to_be_verified
: The content to be validated that is created from step2.serverPublicKey
: the platform public key that is obtained from step1.
Demo code: