VMRack
首页
产品
解决方案
定价
支持
推广联盟
开发者中心
OpenApi签名规则
地域和Endpoint
队列管理
删除队列
创建队列
修改队列
队列列表
转码任务
创建任务
重试任务
任务详情
删除任务
任务列表
批量删除任务
获取可选择的任务处理类型
批量重试任务
预设管理
创建预设
预设详情
删除预设
更新预设
预设列表
工作流管理
创建工作流
复制工作流
查询工作流
删除工作流
修改工作流
工作流列表
域名管理
查询域名列表
对象信息管理
Object - 获取对象信息
Object - 删除对象
Object - 中断分片上传、复制、移动、修改存储类型任务
Object - 完成分片复制、移动、修改存储类型任务
Object - 复制对象
Object - 创建分片复制、移动、修改存储类型任务
Object - 创建目录
Object - 删除目录
Object - 获取对象列表
Object - 获取元数据
Object - 更新元数据
Object - 移动对象
Object - 执行分片复制、移动、修改存储类型
Object - 完成分片上传任务
Object - 创建分片上传任务
Object - 预下载
Object - 预签
Object - 修改对象存储类型
桶信息管理
Bucket - 清空所有桶数据
Bucket - 查询桶信息
Bucket - 创建桶
Bucket - 删除桶(包括桶内数据)
Bucket - 修改桶访问控制权限
Bucket - 获取跨域配置
Bucket - 更新跨域配置
Bucket - 创建跨域配置
Bucket - 删除跨域配置
Bucket - 获取跨域配置列表
Bucket - 查询桶生命周期列表
Bucket - 更新桶生命周期
Bucket - 创建桶生命周期
Bucket - 删除桶生命周期
Bucket - 查询桶列表
Bucket - 修改客户端缓存Maxage
Bucket - 获取防盗链配置
Bucket - 编辑防盗链配置
版本说明
  1. 开发者中心
  2. /
  3. OpenApi签名规则

OpenApi签名规则

VM 模式 API 签名鉴权开发文档 (VM4-HMAC-SHA256)

本接口采用 VM4-HMAC-SHA256 签名算法,用于确保请求的来源合法性、数据完整性及防重放攻击。所有请求必须在 Header 中携带签名信息。

1. 签名参数概览

参数

值

说明

Header 前缀

x-vm-

所有自定义头均以此开头

Service Name

v3

签名 Scope 中的服务标识

算法标识前缀

VM4

Authorization 头的起始标识

Scope 后缀

vm4_request

派生密钥计算的结尾字符

2. 必须携带的 Header 字段

Header 键

示例值

说明

x-vm-date

20260326T113306Z

请求发出的 UTC 时间,格式:YYYYMMDDTHHMMSSZ

x-vm-content-sha256

e3b0c442...

请求体 (Body) 的 SHA256 哈希值(小写十六进制)

Authorization

VM4-HMAC-SHA256 ...

完整的签名凭证字符串

注意:服务器会校验 x-vm-date,如果与服务器时间偏差超过 15分钟,请求将被拒绝

3. 签名计算步骤

步骤 1:构建规范请求 (Canonical Request)

按顺序拼接以下字符串(以 \n 分隔):

  • HTTPMethod: 如 GET, POST。

  • CanonicalURI: 编码后的路径(如 /api/v1/instances)。若为空则使用 /。

  • CanonicalQueryString: 参数按 ASCII 码升序排列并 URL 编码后的字符串。若无参数则为空。 CanonicalHeaders: 必须包含 host、x-vm-content-sha256、x-vm-date。格式为:key:value\n(注意 key 必须小写)。

  • 空行: 在 Headers 拼接完成后,必须多加一个换行符。

  • SignedHeaders: 参与签名的 Header 键名列表,小写并以分号分隔。

  • PayloadHash: x-vm-content-sha256 的值(即 Body 的 SHA256 十六进制字符串)。

示例

GET
/v1/instances
Limit=10&status=running
host:api.example.com
x-vm-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
x-vm-date:20260326T113306Z

host;x-vm-content-sha256;x-vm-date
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

步骤 2:构建待签名字符串 (String To Sign)

将元数据与步骤一生成的规范请求哈希值按以下顺序拼接(以 \n 分隔):

  • Algorithm: 固定值 VM4-HMAC-SHA256。

  • RequestDateTime: x-vm-date 的值(例如 20260326T113306Z)。

  • CredentialScope: 包含日期、区域和服务标识的字符串。格式为:{DateStamp}/{Region}/v3/vm4_request。

  • DateStamp: 格式为 YYYYMMDD(如 20260326)。

  • Region: 请求的目标区域ID或名称,非必填(如 1965717130594750464 或 cn-north-1 )。 HashedCanonicalRequest: 将步骤 1中构建的 Canonical Request 整个字符串进行 SHA256 哈希计算,并转换为小写十六进制字符串。

示例

VM4-HMAC-SHA256
20260326T113306Z
20260326/cn-north-1/v3/vm4_request
765e92d7b1d12c8a3e8a4d2f9b8c7a6e5d4c3b2a1f0e9d8c7b6a5f4e3d2c1b0a

步骤 3:生成派生密钥 (Signing Key)

派生密钥是通过对 SecretKey 进行多次哈希计算得到的。请按以下顺序执行 HMAC-SHA256 操作(伪代码逻辑):

  kDate: 使用 VM4 + SecretKey 作为 Key,对 DateStamp(YYYYMMDD)进行哈希。  HMAC-SHA256("VM4" + SecretKey, "20260326")
kRegion: 使用上一步得到的 kDate 作为 Key,对 Region(如 cn-north-1)进行哈希。 HMAC-SHA256(kDate, "cn-north-1")

  kService: 使用上一步得到的 kRegion 作为 Key,对 ServiceName(固定为 v3)进行哈希。  HMAC-SHA256(kRegion, "v3")

kSigning: 使用上一步得到的 kService 作为 Key,对 Suffix(固定为 vm4_request)进行哈希。  HMAC-SHA256(kService, "vm4_request")

使用您的 SecretKey 依次进行 HMAC-SHA256 计算:

// 注意:VM4 是作为 SecretKey 的前缀使用的
kDate    := hmacSha256([]byte("VM4" + secretKey), "20260326")
kRegion  := hmacSha256(kDate, "cn-north-1")
kService := hmacSha256(kRegion, "v3")
kSigning := hmacSha256(kService, "vm4_request") // 最终得到的 kSigning 用于步骤 4

步骤 4:计算最终签名 (Signature)

使用生成的派生密钥(Signing Key)对偏移量和请求元数据进行最后的完整性签名。

  Key: 使用 步骤 3 中计算出的最后一个二进制字节数组 kSigning。

  Data: 使用 步骤 2 中构建的完整 String To Sign 字符串。

HMAC 计算:  使用 HMAC-SHA256 算法,以 kSigning 为密钥,对 String To Sign 进行哈希计算。

十六进制转换:  将上一步得到的二进制结果转换为 小写十六进制(Lowercase Hex) 字符串。这就是最终的 Signature。

// 使用步骤 3 的结果 kSigning 和步骤 2 的结果 stringToSign
signatureBytes := hmacSha256(kSigning, stringToSign)
signature := hex.EncodeToString(signatureBytes) 

4. Authorization 头部示例

 Authorization: VM4-HMAC-SHA256 Credential=AK_EXAMPLE/20260326/region-1/v3/vm4_request, SignedHeaders=host;x-vm-content-sha256;x-vm-date, Signature=fe5f...

5. 开发者代码参考 (Go)

以下示例演示了如何在不依赖外部框架的情况下,为 HTTP 请求手动计算并添加 VM 模式签名。

package main
 
import (
    "bytes"
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "fmt"
    "net/http"
    "time"
)
 
// HmacSha256 辅助工具
func hmacSha256(key []byte, data string) []byte {
    h := hmac.New(sha256.New, key)
    h.Write([]byte(data))
    return h.Sum(nil)
}
 
// 计算派生密钥 (Signing Key)
func getVM4SigningKey(secretKey, dateStamp, regionName string) []byte {
    kDate := hmacSha256([]byte("VM4"+secretKey), dateStamp)
    kRegion := hmacSha256(kDate, regionName)
    kService := hmacSha256(kRegion, "v3") // ServiceName 为 v3
    kSigning := hmacSha256(kService, "vm4_request")
    return kSigning
}
 
func signVMRequest(req *http.Request, ak, sk, region, payloadHash string) {
    now := time.Now().UTC()
    amzDate := now.Format("20060102T150405Z")
    dateStamp := now.Format("20060102")
 
    // 1. 设置必要 Header
    req.Header.Set("x-vm-date", amzDate)
 
    // 计算 Payload Hash (假设无 Body 或已处理)
    if payloadHash == "" {
        payloadHash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
    }
    req.Header.Set("x-vm-content-sha256", payloadHash)
 
    // 2. 构建 Canonical Request
    signedHeaders := "host;x-vm-content-sha256;x-vm-date"
    canonicalRequest := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s",
        req.Method,
        req.URL.Path,
        req.URL.RawQuery,
        "host:"+req.Host,
        "x-vm-content-sha256:"+payloadHash,
        "x-vm-date:"+amzDate+"\n",
        signedHeaders,
        payloadHash,
    )
 
    // 3. 构建 StringToSign
    credentialScope := fmt.Sprintf("%s/%s/v3/vm4_request", dateStamp, region)
    hash := sha256.Sum256([]byte(canonicalRequest))
    stringToSign := fmt.Sprintf("VM4-HMAC-SHA256\n%s\n%s\n%s",
        amzDate,
        credentialScope,
        hex.EncodeToString(hash[:]),
    )
    fmt.Println("StringToSign:", stringToSign)
 
    // 4. 计算签名
    signingKey := getVM4SigningKey(sk, dateStamp, region)
    signature := hex.EncodeToString(hmacSha256(signingKey, stringToSign))
 
    // 5. 设置 Authorization Header
    authHeader := fmt.Sprintf("VM4-HMAC-SHA256 Credential=%s/%s, SignedHeaders=%s, Signature=%s",
        ak, credentialScope, signedHeaders, signature)
    req.Header.Set("Authorization", authHeader)
}
 
func main() {
    var body = []byte(`{"offset":1,"limit":1}`)
    // 计算 Payload Hash
    hash := sha256.Sum256(body)
    payloadHash := hex.EncodeToString(hash[:])
    req, _ := http.NewRequest("GET", "http://127.0.0.1:8080/aaa-2100002392/?delimiter=%2F&encoding-type=url&fetch-owner=true&list-type=2&prefix=", bytes.NewReader(body))
    req.Host = "127.0.0.1:8080"
 
    ak := "CUS1****SVTK"
    sk := "OPD3****E27G"
    region := "la"
 
    signVMRequest(req, ak, sk, region, payloadHash)
 
    fmt.Println("Authorization Header:", req.Header.Get("Authorization"))
}

6. 签名调试步骤

为了确保对接成功,请按以下顺序检查:

  •   路径编码:CanonicalURI 必须以 / 开头。如果路径为空,请使用 /。

  •   参数排序:CanonicalQueryString 中的参数必须按键名的 ASCII 码升序排列。

  • 小写转换:SignedHeaders 中的所有键名必须转换为小写。哈希一致性:x-vm-content-sha256 必须与请求体实际内容的 SHA256 值完全一致。

7. 常见错误码

错误码

说明

UNAUTHORIZED: Signature mismatch

签名计算不一致,请检查密钥及 Canonical Request 构建逻辑。

UNAUTHORIZED: x-amz-date skew too large

客户端时间偏差超过 15 分钟。请同步 NTP 时间。

UNAUTHORIZED: Missing x-vm-date

缺少 x-vm-date 或格式不正确。

VMRack
  • 产品
  • 云服务器
  • 云服务器
    无限流量
  • 裸金属
  • GPU算力租用
  • CDN
    公测
  • 定制CDN
  • 对象存储
    公测
  • 云转码
    公测
  • 解决方案
  • BYOIP自有IP
  • 硬件定制
  • 服务器托管
  • 资源
  • 定价
  • 帮助文档
  • 专题文章
  • 开发者中心
  • 推广联盟
  • 联系销售
  • 公司
  • 关于我们
  • 服务协议
  • 用户协议
  • 隐私政策
  • 服务等级