在支付宝开放平台的应用体系中,应用私钥是最核心的安全要素,使用密钥管理服务KMS(Key Management Service)保护私钥,可以极大的提高支付宝应用和小程序的安全性,帮助应用开发者保障业务和资金安全。
背景信息
支付宝开放平台的应用管理体系采用公私钥的机制,以保障商户应用和支付宝交互的安全性。这一机制包括以下两部分:
- 商户应用使用自己的私钥对消息加签后,将消息和签名传递给支付宝,支付宝则使用应用的公钥验证消息的真实性(来自于合法应用的真实消息)。
- 对于支付宝返回消息给商户应用的情形,应用则使用支付宝的平台公钥来验证返回消息的真实性。
该机制的前提是:商户应用必须保障应用私钥的安全性,从而保障应用和和支付宝交互的安全性。反之,一旦私钥发生泄露,商户会面临较大的安全风险。如果应用和支付宝的交互涉及到资金类接口则风险更大。
产品价值
相比于在应用中使用应用私钥的明文来对消息进行加签,KMS存在以下优势:
- 保障私钥安全性:用户可以将签名私钥安全存放在KMS托管密码机内。用户通过KMS的OpenAPI使用私钥加签时,私钥会在密码机的硬件安全边界之内,完成运算后返回签名值,从而防止私钥的泄露。托管密码机详情,请参见托管密码机概述。
- 控制私钥使用者:用户可以通过阿里云访问控制RAM(Resource Access Management),集中管控KMS密钥使用成员,用于应用加签。
- 审计对私钥的调用日志:通过阿里云操作审计(ActionTrail)可以查看每一次调用KMS的记录;而商家应用自行保管私钥则很难产生客观的审计事件。
- 灵活响应安全事件:在应用系统遭遇恶意者攻击等情形下,可以通过多种手段阻止恶意者对私钥的非法使用。例如:用户可以通过RAM撤销对私钥的使用权限,或者通过KMS禁用私钥等。

使用KMS控制台为支付宝应用或小程序加签
使用支付宝SDK调用KMS为支付宝应用或小程序加签
支付宝开放平台新版SDK(EasySDK)集成了KMS作为加签提供器(Sign Provider),以简化加签操作。以Java SDK为例,您需要在支付宝应用中引用EasySDK 2.0.1以及之后的版本。
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-easysdk</artifactId>
<version>2.0.1</version>
</dependency>
说明 如果遵循支付宝开放API的签名规则,也可以不使用EasySDK,通过调用阿里云KMS的AsymmetricSign接口自行实现签名。
代码示例:普通公钥方式
package com.aliyun.kms.samples;
import com.alipay.easysdk.base.qrcode.models.AlipayOpenAppQrcodeCreateResponse;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kms.aliyun.AliyunKMSConfig;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Map;
/**
* Alipay-easysdk使用KMS签名示例,本示例展示了公钥方式调用。
*/
public class KmsAlipayEasySDKPublicKeyDemo {
public static void main(String[] args) {
Factory.setOptions(getOptions());
try {
AlipayOpenAppQrcodeCreateResponse response = Factory.Base.Qrcode().create("page/component/component-pages/view/view", "x=1", "二维码描述");
if ("10000".equals(response.code)) {
System.out.println("调用成功");
} else {
System.err.println("调用失败,原因:" + response.msg + "," + response.subMsg);
}
} catch (Exception e) {
System.err.println("调用遭遇异常,原因:" + e.getMessage());
throw new RuntimeException(e.getMessage(), e);
}
}
private static AliyunKMSConfig getOptions() {
AliyunKMSConfig config = new AliyunKMSConfig();
config.protocol = "https";
config.gatewayHost = "openapi.alipay.com";
config.signType = "RSA2";
//请更换为您的AppID。
config.appId = "202100****";
//请修改如下的支付宝公钥字符串为自己的支付宝公钥。
config.alipayPublicKey = "MIIBIjANB...";
//如果使用阿里云KMS签名,则需要指定签名提供方名称,阿里云KMS的名称为"AliyunKMS"。
config.signProvider = "AliyunKMS";
//如果使用阿里云KMS签名,请更换为您的阿里云AccessKey ID。
config.aliyunAccessKeyId = getAliyunAccessKey("AccessKeyId");
//如果使用阿里云KMS签名,请更换为您的阿里云AccessKey Secret。
config.aliyunAccessKeySecret = getAliyunAccessKey("AccessKeySecret");
//如果使用阿里云KMS签名,请更换为您的KMS服务密钥ID。
config.kmsKeyId = "4358f298-8e30-4849-9791-****";
//如果使用阿里云KMS签名,请更换为您的KMS服务密钥版本ID。
config.kmsKeyVersionId = "e71daa69-c321-4014-b0c4-****";
//如果使用阿里云KMS签名,需要更换为您的KMS服务地址。
//KMS服务地址列表详情,请参考:
//https://help.aliyun.com/document_detail/69006.html
config.kmsEndpoint = "kms.cn-hangzhou.aliyuncs.com";
return config;
}
/**
* 从文件中读取阿里云AccessKey配置信息。
* 此处为了测试执行的环境普适性,AccessKey信息配置在resources资源下,实际过程中请不要这样配置。
*
* @param key AccessKey配置对应的key。
* @return AccessKey配置字符串。
*/
private static String getAliyunAccessKey(String key) {
InputStream stream = KmsAlipayEasySDKPublicKeyDemo.class.getResourceAsStream("/fixture/aliyunAccessKey.json");
Map<String, String> result = new Gson().fromJson(new InputStreamReader(stream), new TypeToken<Map<String, String>>() {
}.getType());
return result.get(key);
}
}
代码示例:公钥证书方式
使用公钥证书方式时,EasySDK的使用方式和上述示例类似,区别主要在于配置了商户应用和支付宝平台的公钥证书。更多信息,请参见阿里云KMS Github代码样例库。