腾讯云 API 会对每个请求进行身份验证,用户需要使用安全凭证,经过特定的步骤对请求进行签名(Signature),每个请求都需要在公共参数中指定该签名结果并以指定的方式和格式发送请求。
新版签名v3计算过程非常复杂,读者朋友可以参考官方文档签名方法v3一节。文档中提供了多种常见服务端语言的签名代码,但是并没有shell版本,这就导致一些开源项目(如 acme.sh、dnspod-shell)无法使用腾讯新版接口交互数据。
实现签名算法
经过一夜的试错,最终完成了该签名的shell实现。其中难点是sha256
和hmac_sha256
加密过程中对换行和二进制密钥的处理。
- 这里处理换行不使用
echo -e
的原因是其不能兼容POSIX
环境,且会在末尾添加一个换行,所以使用printf
来替代。 - 官方示例中四次
hmac_sha256
的入参和返回值中有二进制、ASCII和HEX字符串多种类型的数据,在shell中处理不便、且容易出错。所以我均转为使用HEX字符串完成输入输出操作,以解决此问题。
此签名实现使用了openssl
、printf
、sed
处理加解密信息,兼容POSIX
环境。示例代码使用curl
请求接口,若系统版本非常老旧(比如CentOS7),请注意更新ca证书链(处于安全原因,不推荐忽略证书验证)。
###############################################
# shell client for tencent cloud api v3
#
# @author: rehiy
# @url: https://www.rehiy.com/post/534/
###############################################
qcloud_sha256() {
printf "%b" "$@" | openssl dgst -sha256 -hex | sed 's/^.* //'
}
qcloud_hmac_sha256() {
k=$1
shift
printf "%b" "$@" | openssl dgst -sha256 -hmac "$k" | sed 's/^.* //'
}
qcloud_hmac_sha256_hexkey() {
k=$1
shift
printf "%b" "$@" | openssl dgst -sha256 -mac HMAC -macopt "hexkey:$k" | sed 's/^.* //'
}
qcloud_signature_v3() {
service=$1
action=$(echo $2 | tr '[:upper:]' '[:lower:]')
payload=${3:-'{}'}
timestamp=${4:-$(date +%s)}
domain="$service.tencentcloudapi.com"
secretId=${QCLOUD_SECRET_ID:-'tencent-cloud-secret-id'}
secretKey=${QCLOUD_SECRET_KEY:-'tencent-cloud-secret-key'}
algorithm='TC3-HMAC-SHA256'
date=$(date -u -d "@$timestamp" +%Y-%m-%d 2>/dev/null)
[ -z "$date" ] && date=$(date -u -r "$timestamp" +%Y-%m-%d)
canonicalUri='/'
canonicalQuery=''
canonicalHeaders="content-type:application/jsonnhost:$domainnx-tc-action:$actionn"
signedHeaders='content-type;host;x-tc-action'
canonicalRequest="POSTn$canonicalUrin$canonicalQueryn$canonicalHeadersn$signedHeadersn$(qcloud_sha256 $payload)"
credentialScope="$date/$service/tc3_request"
stringToSign="$algorithmn$timestampn$credentialScopen$(qcloud_sha256 $canonicalRequest)"
secretDate=$(qcloud_hmac_sha256 "TC3$secretKey" "$date")
secretService=$(qcloud_hmac_sha256_hexkey "$secretDate" "$service")
secretSigning=$(qcloud_hmac_sha256_hexkey "$secretService" 'tc3_request')
signature=$(qcloud_hmac_sha256_hexkey "$secretSigning" "$stringToSign")
echo "$algorithm Credential=$secretId/$credentialScope, SignedHeaders=$signedHeaders, Signature=$signature"
}
qcloud_api_request() {
service=$1
version=$2
action=$3
payload=${4:-'{}'}
timestamp=${5:-$(date +%s)}
token=$(qcloud_signature_v3 "$service" "$action" "$payload" "$timestamp")
curl
-H "Host: $service.tencentcloudapi.com"
-H "Content-Type: application/json"
-H "Authorization: $token"
-H "X-TC-Version: $version"
-H "X-TC-Timestamp: $timestamp"
-H "X-TC-Language: zh-CN"
-H "X-TC-RequestClient: RehiyShellClient"
-H "X-TC-Action: $action"
-d "$payload"
"https://$service.tencentcloudapi.com/"
}
Linux 格式化时间戳使用
date=$(date -u -d "@$timestamp" +%Y-%m-%d)
Macos 格式化时间戳使用date=$(date -u -r "$timestamp" +%Y-%m-%d)
测试签名算法
这里设置了一组虚拟的密钥来测试,可以和官方API Explorer中的签名串生成互相印证。
export QCLOUD_SECRET_ID="sfsdfasdfasdfasdfsdfewsdfdddg"
export QCLOUD_SECRET_KEY="234wewer23weffddf232wefsfff2sf"
qcloud_signature_v3 cvm DescribeRegions '{}' 1693406195
输出结果如下:
TC3-HMAC-SHA256 Credential=sfsdfasdfasdfasdfsdfewsdfdddg/2023-08-30/cvm/tc3_request, SignedHeaders=content-type;host;x-tc-action, Signature=b36086cea43ac1a8025017535821a7240cd0895f5e768193e5b0952e2e56bc8b
测试接口请求
这里设置了一组虚拟的密钥来测试,将获得cvm服务器可用地域信息。
注意:传入json参数,需要使用引号将其作为单个参数传入,否则将无法正确计算签名。
export QCLOUD_SECRET_ID="sfsdfasdfasdfasdfsdfewsdfdddg"
export QCLOUD_SECRET_KEY="234wewer23weffddf232wefsfff2sf"
qcloud_api_request cvm 2017-03-12 DescribeRegions '{}'
附录
- API Explorer 签名截图
须知:本文同步自若海の技术写真,如有错漏请到原文下留言反馈。