tencent cloud

操作审计

产品简介
产品概述
产品优势
产品功能
应用场景
支持审计的服务及接口列表
购买指南
快速入门
操作指南
查看操作记录事件详情
使用跟踪集投递日志
设置集团账号跨账号日志投递
敏感操作接口列表
API 文档
History
Introduction
API Category
Calling Method
CloudAudit APIs
数据结构
错误码
PHP SDK 文档
创建操作审计
开启日志采集
更新操作审计
关闭日志采集
拉取 COS 列表
拉取操作审计列表
获取操作审计信息
删除操作审计
检索日志
常见问题
联系我们
词汇表

签名方法

PDF
聚焦模式
字号
最后更新时间: 2021-11-16 15:24:53

签名方法 v1 简单易用,但是功能和安全性都不如签名方法 v3,推荐使用签名方法 v3。

首次接触,建议使用 API Explorer 中的“签名串生成”功能,选择签名版本为“API 3.0 签名 v1”,可以生成签名过程进行验证,并提供了部分编程语言的签名示例,也可直接生成 SDK 代码。推荐使用腾讯云 API 配套的 7 种常见的编程语言 SDK,已经封装了签名和请求过程,均已开源,支持 PythonJavaPHPGoNodeJS.NETC++

腾讯云 API 会对每个访问请求进行身份验证,即每个请求都需要在公共请求参数中包含签名信息(Signature)以验证请求者身份。
签名信息由安全凭证生成,安全凭证包括 SecretId 和 SecretKey;若用户还没有安全凭证,请前往 云API密钥页面 申请,否则无法调用云 API 接口。

1. 申请安全凭证

在第一次使用云 API 之前,请前往 云 API 密钥页面 申请安全凭证。
安全凭证包括 SecretId 和 SecretKey:

  • SecretId 用于标识 API 调用者身份
  • SecretKey 用于加密签名字符串和服务器端验证签名字符串的密钥。
  • 用户必须严格保管安全凭证,避免泄露。

申请安全凭证的具体步骤如下:

  1. 登录 腾讯云管理中心控制台
  2. 前往 云 API 密钥 的控制台页面
  3. 云 API 密钥 页面,单击【新建密钥】即可以创建一对 SecretId/SecretKey。

注意:每个账号最多可以拥有两对 SecretId/SecretKey。

2. 生成签名串

有了安全凭证SecretId 和 SecretKey后,就可以生成签名串了。以下是生成签名串的详细过程:

假设用户的 SecretId 和 SecretKey 分别是:

  • SecretId: AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE
  • SecretKey: Gu5t9xGARNpq86cd98joQYCN3EXAMPLE

注意:这里只是示例,请根据用户实际申请的 SecretId 和 SecretKey 进行后续操作!

以云服务器查看实例列表(DescribeInstances)请求为例,当用户调用这一接口时,其请求参数可能如下:

参数名称 中文 参数值
Action 方法名 DescribeInstances
SecretId 密钥 ID AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE
Timestamp 当前时间戳 1465185768
Nonce 随机正整数 11886
Region 实例所在区域 ap-guangzhou
InstanceIds.0 待查询的实例 ID ins-09dx96dg
Offset 偏移量 0
Limit 最大允许输出 20
Version 接口版本号 2017-03-12

2.1. 对参数排序

首先对所有请求参数按参数名的字典序( ASCII 码)升序排序。注意:1)只按参数名进行排序,参数值保持对应即可,不参与比大小;2)按 ASCII 码比大小,如 InstanceIds.2 要排在 InstanceIds.12 后面,不是按字母表,也不是按数值。用户可以借助编程语言中的相关排序函数来实现这一功能,如 PHP 中的 ksort 函数。上述示例参数的排序结果如下:

{
  'Action' : 'DescribeInstances',
  'InstanceIds.0' : 'ins-09dx96dg',
  'Limit' : 20,
  'Nonce' : 11886,
  'Offset' : 0,
  'Region' : 'ap-guangzhou',
  'SecretId' : 'AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE',
  'Timestamp' : 1465185768,
  'Version': '2017-03-12',
}

使用其它程序设计语言开发时,可对上面示例中的参数进行排序,得到的结果一致即可。

2.2. 拼接请求字符串

此步骤生成请求字符串。
将把上一步排序好的请求参数格式化成“参数名称=参数值”的形式,如对 Action 参数,其参数名称为 "Action" ,参数值为 "DescribeInstances" ,因此格式化后就为 Action=DescribeInstances 。
注意:“参数值”为原始值而非 url 编码后的值。

然后将格式化后的各个参数用"&"拼接在一起,最终生成的请求字符串为:

Action=DescribeInstances&InstanceIds.0=ins-09dx96dg&Limit=20&Nonce=11886&Offset=0&Region=ap-guangzhou&SecretId=AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE&Timestamp=1465185768&Version=2017-03-12

2.3. 拼接签名原文字符串

此步骤生成签名原文字符串。
签名原文字符串由以下几个参数构成:

  1. 请求方法: 支持 POST 和 GET 方式,这里使用 GET 请求,注意方法为全大写。
  2. 请求主机:查看实例列表(DescribeInstances)的请求域名为:cvm.tencentcloudapi.com。实际的请求域名根据接口所属模块的不同而不同,详见各接口说明。
  3. 请求路径: 当前版本云API的请求路径固定为 / 。
  4. 请求字符串: 即上一步生成的请求字符串。

签名原文串的拼接规则为:请求方法 + 请求主机 +请求路径 + ? + 请求字符串

示例的拼接结果为:

GETcvm.tencentcloudapi.com/?Action=DescribeInstances&InstanceIds.0=ins-09dx96dg&Limit=20&Nonce=11886&Offset=0&Region=ap-guangzhou&SecretId=AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE&Timestamp=1465185768&Version=2017-03-12

2.4. 生成签名串

此步骤生成签名串。
首先使用 HMAC-SHA1 算法对上一步中获得的签名原文字符串进行签名,然后将生成的签名串使用 Base64 进行编码,即可获得最终的签名串。

具体代码如下,以 PHP 语言为例:

$secretKey = 'Gu5t9xGARNpq86cd98joQYCN3EXAMPLE';
$srcStr = 'GETcvm.tencentcloudapi.com/?Action=DescribeInstances&InstanceIds.0=ins-09dx96dg&Limit=20&Nonce=11886&Offset=0&Region=ap-guangzhou&SecretId=AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE&Timestamp=1465185768&Version=2017-03-12';
$signStr = base64_encode(hash_hmac('sha1', $srcStr, $secretKey, true));
echo $signStr;

最终得到的签名串为:

EliP9YW3pW28FpsEdkXt/+WcGeI=

使用其它程序设计语言开发时,可用上面示例中的原文进行签名验证,得到的签名串与例子中的一致即可。

3. 签名串编码

生成的签名串并不能直接作为请求参数,需要对其进行 URL 编码。

如上一步生成的签名串为 EliP9YW3pW28FpsEdkXt/+WcGeI= ,最终得到的签名串请求参数(Signature)为:EliP9YW3pW28FpsEdkXt%2f%2bWcGeI%3d,它将用于生成最终的请求 URL。

注意:如果用户的请求方法是 GET,或者请求方法为 POST 同时 Content-Type 为 application/x-www-form-urlencoded,则发送请求时所有请求参数的值均需要做 URL 编码,参数键和=符号不需要编码。非 ASCII 字符在 URL 编码前需要先以 UTF-8 进行编码。

注意:有些编程语言的网络库会自动为所有参数进行 urlencode,在这种情况下,就不需要对签名串进行 URL 编码了,否则两次 URL 编码会导致签名失败。

注意:其他参数值也需要进行编码,编码采用 RFC 3986。使用 %XY 对特殊字符例如汉字进行百分比编码,其中“X”和“Y”为十六进制字符(0-9 和大写字母 A-F),使用小写将引发错误。

4. 签名失败

根据实际情况,存在以下签名失败的错误码,请根据实际情况处理。

错误代码 错误描述
AuthFailure.SignatureExpire 签名过期
AuthFailure.SecretIdNotFound 密钥不存在
AuthFailure.SignatureFailure 签名错误
AuthFailure.TokenFailure token 错误
AuthFailure.InvalidSecretId 密钥非法(不是云 API 密钥类型)

5. 签名演示

在实际调用 API 3.0 时,推荐使用配套的腾讯云 SDK 3.0 ,SDK 封装了签名的过程,开发时只关注产品提供的具体接口即可。详细信息参见 SDK 中心。当前支持的编程语言有:

为了更清楚的解释签名过程,下面以实际编程语言为例,将上述的签名过程具体实现。请求的域名、调用的接口和参数的取值都以上述签名过程为准,代码只为解释签名过程,并不具备通用性,实际开发请尽量使用 SDK 。

最终输出的 url 可能为:

https://cvm.tencentcloudapi.com/?Action=DescribeInstances&InstanceIds.0=ins-09dx96dg&Limit=20&Nonce=11886&Offset=0&Region=ap-guangzhou&SecretId=AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE&Signature=EliP9YW3pW28FpsEdkXt%2F%2BWcGeI%3D&Timestamp=1465185768&Version=2017-03-12

注意:由于示例中的密钥是虚构的,时间戳也不是系统当前时间,因此如果将此 url 在浏览器中打开或者用 curl 等命令调用时会返回鉴权错误:签名过期。为了得到一个可以正常返回的 url ,需要修改示例中的 SecretId 和 SecretKey 为真实的密钥,并使用系统当前时间戳作为 Timestamp 。

注意:在下面的示例中,不同编程语言,甚至同一语言每次执行得到的 url 可能都有所不同,表现为参数的顺序不同,但这并不影响正确性。只要所有参数都在,且签名计算正确即可。

注意:以下代码仅适用于 API 3.0,不能直接用于其他的签名流程,即使是旧版的 API ,由于存在细节差异也会导致签名计算错误,请以对应的实际文档为准。

Java

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Random;
import java.util.TreeMap;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
public class TencentCloudAPIDemo {
  private final static String CHARSET = "UTF-8";
   public static String sign(String s, String key, String method) throws Exception {
      Mac mac = Mac.getInstance(method);
      SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(CHARSET), mac.getAlgorithm());
      mac.init(secretKeySpec);
      byte[] hash = mac.doFinal(s.getBytes(CHARSET));
      return DatatypeConverter.printBase64Binary(hash);
  }
   public static String getStringToSign(TreeMap<String, Object> params) {
      StringBuilder s2s = new StringBuilder("GETcvm.tencentcloudapi.com/?");
      // 签名时要求对参数进行字典排序,此处用TreeMap保证顺序
      for (String k : params.keySet()) {
          s2s.append(k).append("=").append(params.get(k).toString()).append("&");
      }
      return s2s.toString().substring(0, s2s.length() - 1);
  }
   public static String getUrl(TreeMap<String, Object> params) throws UnsupportedEncodingException {
      StringBuilder url = new StringBuilder("https://cvm.tencentcloudapi.com/?");
      // 实际请求的url中对参数顺序没有要求
      for (String k : params.keySet()) {
          // 需要对请求串进行urlencode,由于key都是英文字母,故此处仅对其value进行urlencode
          url.append(k).append("=").append(URLEncoder.encode(params.get(k).toString(), CHARSET)).append("&");
      }
      return url.toString().substring(0, url.length() - 1);
  }
   public static void main(String[] args) throws Exception {
      TreeMap<String, Object> params = new TreeMap<String, Object>(); // TreeMap可以自动排序
      // 实际调用时应当使用随机数,例如:params.put("Nonce", new Random().nextInt(java.lang.Integer.MAX_VALUE));
      params.put("Nonce", 11886); // 公共参数
      // 实际调用时应当使用系统当前时间,例如:   params.put("Timestamp", System.currentTimeMillis() / 1000);
      params.put("Timestamp", 1465185768); // 公共参数
      params.put("SecretId", "AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE"); // 公共参数
      params.put("Action", "DescribeInstances"); // 公共参数
      params.put("Version", "2017-03-12"); // 公共参数
      params.put("Region", "ap-guangzhou"); // 公共参数
      params.put("Limit", 20); // 业务参数
      params.put("Offset", 0); // 业务参数
      params.put("InstanceIds.0", "ins-09dx96dg"); // 业务参数
      params.put("Signature", sign(getStringToSign(params), "Gu5t9xGARNpq86cd98joQYCN3EXAMPLE", "HmacSHA1")); // 公共参数
      System.out.println(getUrl(params));
  }
}

Python

注意:如果是在 Python 2 环境中运行,需要先安装 requests 依赖包: pip install requests

# -*- coding: utf8 -*-
import base64
import hashlib
import hmac
import time
import requests
secret_id = "AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE"
secret_key = "Gu5t9xGARNpq86cd98joQYCN3EXAMPLE"
def get_string_to_sign(method, endpoint, params):
  s = method + endpoint + "/?"
  query_str = "&".join("%s=%s" % (k, params[k]) for k in sorted(params))
  return s + query_str
def sign_str(key, s, method):
  hmac_str = hmac.new(key.encode("utf8"), s.encode("utf8"), method).digest()
  return base64.b64encode(hmac_str)
if __name__ == '__main__':
  endpoint = "cvm.tencentcloudapi.com"
  data = {
      'Action' : 'DescribeInstances',
      'InstanceIds.0' : 'ins-09dx96dg',
      'Limit' : 20,
      'Nonce' : 11886,
      'Offset' : 0,
      'Region' : 'ap-guangzhou',
      'SecretId' : secret_id,
      'Timestamp' : 1465185768, # int(time.time())
      'Version': '2017-03-12'
  }
  s = get_string_to_sign("GET", endpoint, data)
  data["Signature"] = sign_str(secret_key, s, hashlib.sha1)
  print(data["Signature"])
  # 此处会实际调用,成功后可能产生计费
  # resp = requests.get("https://" + endpoint, params=data)
  # print(resp.url)

Go

package main
import (
  "bytes"
  "crypto/hmac"
  "crypto/sha1"
  "encoding/base64"
  "fmt"
  "sort"
)
func main() {
  secretId := "AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE"
  secretKey := "Gu5t9xGARNpq86cd98joQYCN3EXAMPLE"
  params := map[string]string{
      "Nonce":         "11886",
      "Timestamp":     "1465185768",
      "Region":        "ap-guangzhou",
      "SecretId":      secretId,
      "Version":       "2017-03-12",
      "Action":        "DescribeInstances",
      "InstanceIds.0": "ins-09dx96dg",
      "Limit":         "20",
      "Offset":        "0",
  }
   var buf bytes.Buffer
  buf.WriteString("GET")
  buf.WriteString("cvm.tencentcloudapi.com")
  buf.WriteString("/")
  buf.WriteString("?")
   // sort keys by ascii asc order
  keys := make([]string, 0, len(params))
  for k, _ := range params {
      keys = append(keys, k)
  }
  sort.Strings(keys)
   for i := range keys {
      k := keys[i]
      buf.WriteString(k)
      buf.WriteString("=")
      buf.WriteString(params[k])
      buf.WriteString("&")
  }
  buf.Truncate(buf.Len() - 1)
   hashed := hmac.New(sha1.New, []byte(secretKey))
  hashed.Write(buf.Bytes())
   fmt.Println(base64.StdEncoding.EncodeToString(hashed.Sum(nil)))
}

PHP

<?php
$secretId = "AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE";
$secretKey = "Gu5t9xGARNpq86cd98joQYCN3EXAMPLE";
$param["Nonce"] = 11886;//rand();
$param["Timestamp"] = 1465185768;//time();
$param["Region"] = "ap-guangzhou";
$param["SecretId"] = $secretId;
$param["Version"] = "2017-03-12";
$param["Action"] = "DescribeInstances";
$param["InstanceIds.0"] = "ins-09dx96dg";
$param["Limit"] = 20;
$param["Offset"] = 0;
ksort($param);
$signStr = "GETcvm.tencentcloudapi.com/?";
foreach ( $param as $key => $value ) {
  $signStr = $signStr . $key . "=" . $value . "&";
}
$signStr = substr($signStr, 0, -1);
$signature = base64_encode(hash_hmac("sha1", $signStr, $secretKey, true));
echo $signature.PHP_EOL;
// need to install and enable curl extension in php.ini
// $param["Signature"] = $signature;
// $url = "https://cvm.tencentcloudapi.com/?".http_build_query($param);
// echo $url.PHP_EOL;
// $ch = curl_init();
// curl_setopt($ch, CURLOPT_URL, $url);
// $output = curl_exec($ch);
// curl_close($ch);
// echo json_decode($output);

帮助和支持

本页内容是否解决了您的问题?

填写满意度调查问卷,共创更好文档体验。

文档反馈