常见签名认证错误排查

生成签名注意事项

  1. 检查HTTP Method是否正确

  2. CanonicalURI部分

    • 注意前面不需要加host,必须以“/”开头,不以“/”开头的需要补充上,空路径为“/”;
    • 注意结尾不该有“/”;
    • 注意要做uriEncodeExceptSlash编码。
  3. CanonicalQueryString部分

    • 注意要按字典序进行排序;
    • 没有value的key,是否也保留了“=”;
    • 没有queryString时,也要在最终的CanonicalRequest中拼接一个\n。
  4. CanonicalHeaders部分

    • 百度智能云默认的signedHeaders:Host、Content-Length、Content-Type、Content-MD5、所有以 x-bce- 开头的Header;
    • 注意这里的header内容,要与实际请求中的header内容完全一致,尤其注意host是否有端口号,x-bce-date是否有变化;
    • 实际发出请求中,是否有header被第三方库删除了?
    • 如果请求中{signedHeaders}字段留空,那么是否完全按照百度智能云默认的signedHeaders计算的?
  5. 签名前缀信息

    • timestamp是认证字符串创建时间,不能过早或过晚;
    • 输入的SK与AK要对应

常见case

不能正确区分URL中的URI部分和QueryString部分

假设请求的URL是/v1/settings/region/list?type=public,此处URI应该为/v1/settings/region/list,type=public是querystring。但是客户端并没有正确区分它们,计算签名时:

# 客户端请求的CanonicalRequest:
GET
/v1/settings/region/list%3ftype%3dpublic
host:settings.bce-internal.baidu.com
x-bce-date:2017-02-15T08%3A52%3A48Z

服务端向IAM构造验签请求时,传递的是正确的URI和QueryString部分:

{
  "auth" : {
    "authorization" : "bce-auth-v1/f3e1f5c2ef9c4d25b7f8b936861cd175/2017-04-05T08:29:50Z/3600/host;x-bce-date/9a48ec83ffb6c486892c4985df7dc6bc20f7c7bebb483f8f355592b8503a3f59",
    "request" : {
      "method" : "GET",
      "uri" : "/v1/settings/region/list",
      "headers" : {
        "host" : "settings.bce-internal.baidu.com",
        "x-bce-date": "2017-02-15T08:52:48Z"
      },
      "params": {
        "type": "public"
      }
    }
  }

进而,IAM基于服务提供的请求信息,演算签名时URI与客户端不一致,得到的签名必然与请求值不一致。

URI尾部的"/"不一致

客户端请求:

# 客户端请求的CanonicalRequest:
GET
/v1/settings/region/list
host:settings.bce-internal.baidu.com
x-bce-date:2017-02-15T08%3A52%3A48Z

服务端向IAM构造验签请求时,误将URI多写了个尾部的"/":

{
  "auth" : {
    "authorization" : "bce-auth-v1/f3e1f5c2ef9c4d25b7f8b936861cd175/2017-04-05T08:29:50Z/3600/host;x-bce-date/9a48ec83ffb6c486892c4985df7dc6bc20f7c7bebb483f8f355592b8503a3f59",
    "request" : {
      "method" : "GET",
      "uri" : "/v1/settings/region/list/", #尾部多了个'/'
      "headers" : {
        "host" : "settings.bce-internal.baidu.com",
        "x-bce-date": "2017-02-15T08:52:48Z"
      }
    }
  }

进而,IAM基于服务提供的请求信息,演算签名时URI与客户端不一致,得到的签名必然与请求值不一致。

Host头域端口不一致

客户端请求:

# 客户端请求的CanonicalRequest:
GET
/v1/settings/region/list
host:settings.bce-internal.baidu.com%3A80
x-bce-date:2017-02-15T08%3A52%3A48Z

服务端向IAM构造验签请求时,host字段并没有加上端口:

{
  "auth" : {
    "authorization" : "bce-auth-v1/f3e1f5c2ef9c4d25b7f8b936861cd175/2017-04-05T08:29:50Z/3600/host;x-bce-date/2671990529b9c46c95e688f1a2809db185c608ee3716a731a8fdde6bb2028d84",
    "request" : {
      "method" : "GET",
      "uri" : "/v1/settings/region/list/",
      "headers" : {
        "host" : "settings.bce-internal.baidu.com", #host并没带端口
        "x-bce-date": "2017-02-15T08:52:48Z"
      }
    }
  }

host不一致,得到的签名必然与请求值不一致。

x-bce-date头的问题

默认情况(authorization中未指明SignedHeaders时)x-bce-date会参与签名。客户端需要保证:计算签名时的此域,与最终发出请求时的此域,二者保持一致。

如,计算签名时使用的时间是 2017-02-15T08:52:48Z

GET
/v1/settings/region/list
host:settings.bce-internal.baidu.com
x-bce-date:2017-02-15T08%3A52%3A48Z

但发出请求时,x-bce-date 变成了 2017-02-15T08:52:49Z

GET /v1/settings/region/list HTTP/1.1
User-Agent: curl/7.33.0
Host: settings.bce-internal.baidu.com
Accept: */*
authorization: bce-auth-v1/f3e1f5c2ef9c4d25b7f8b936861cd175/2017-04-05T08:29:50Z/3600/host;x-bce-date;x-bce-request-id/9a48ec83ffb6c486892c4985df7dc6bc20f7c7bebb483f8f355592b8503a3f59
x-bce-date: 2017-02-15T08:52:49Z

IAM演算签名时x-bce-date域与客户端不一致,得到的签名必然与请求值不一致。

用错了ak/sk

以下两种情况容易出现低级的错误导致签名不通过:

  • 基于配置的程序,配置中ak对了,但sk却存在错误。这种情况IAM并不会返回ak不存在,而是签名错误。一个特点是signningKey与IAM演算的不一致。
  • 自动从API拿到的ak/sk,但是构造业务client时却传错了,比如构造参数可能分别是ak和sk,但代码调用时两个参数都使用了ak。

客户基于StsCredential来请求但服务未正确传递security_token

客户端请求:

# 客户端请求的CanonicalRequest:
GET
/v1/settings/region/list
host:settings.bce-internal.baidu.com
x-bce-date:2017-02-15T08%3A52%3A48Z
x-bce-security-token: ZGZiM2M3MmU4Mjk4NGQ2MGEzYTNhYTAyMDE3NTZmZmV8AAAA...

服务端向IAM构造验签请求时,没有将security_token提取出来,放到专门的字段,用于周知IAM客户使用了临时credential:

{
  "auth" : {
    "authorization" : "bce-auth-v1/f3e1f5c2ef9c4d25b7f8b936861cd175/2017-04-05T08:29:50Z/3600/host;x-bce-date/9a48ec83ffb6c486892c4985df7dc6bc20f7c7bebb483f8f355592b8503a3f59",
    "request" : {
      "method" : "GET",
      "uri" : "/v1/settings/region/list",
      "headers" : {
        "host" : "settings.bce-internal.baidu.com",
        "x-bce-date": "2017-02-15T08:52:48Z",
        "x-bce-security-token": "ZGZiM2M3MmU4Mjk4NGQ2MGEzYTNhYTAyMDE3NTZmZmV8AAAA..."
      }
    }
  }

IAM不知道签名为临时ak/sk签出,从长效ak/sk表中查找不到相应的ak,于是会报"Could not find credential"。

公共错误码

错误返回码 错误消息 状态码 说明
AccessDenied Access denied. 403 Forbidden 无权限访问对应的资源。
InappropriateJSON The JSON you provided was well-formed and valid, but not appropriate forthis operation. 400 Bad Request 请求中的JSON格式正确,但语义上不符合要求。如缺少某个必需项,或值类型不匹配等。出于兼容性考虑,对于所有无法识别的项应直接忽略,不应该返回这个错误。
InternalError We encountered an internal error Please try again. 500 Internal Server Error 所有未定义的其他错误。在有明确对应的其他类型的错误时(包括通用的和服务自定义的)不应该使用。
InvalidAccessKeyId The Access Key ID you provided doesnot exist in our records. 403 Forbidden Access Key ID不存在。
InvalidHTTPAuthHeader The Access Key ID you provided does notexist in our records. 400 BadRequest Authorization头域格式错误。
InvalidHTTPRequest There was an error in the body of your HTTP request. 400 Bad Request HTTP body格式错误。例如不符合指定的Encoding等。
InvalidURI Could not parse the specified URI. 400 Bad Request URI形式不正确。例如一些服务定义的关键词不匹配等。对于ID不匹配的问题,应定义更加具体的错误码,如NoSuchKey。
MalformedJSON The JSON you provided was not well-formed. 400 BadRequest JSON格式不合法。
InvalidVersion The API version specified was invalid. 404 NotFound URI的版本号不合法。
OptInRequired A subscription for the service is required. 403 Forbidden 没有开通对应的服务。
PreconditionFailed The specified If-Match header doesn’tmatch the ETag header. 412 PreconditionFailed 详见Etag。
RequestExpired Request has expired. Timestamp date is <Data>. 400 BadRequest 请求超时。要改成x-bce-date。若请求中只有Date,需将Date转成datetime。
IdempotentParameterMismatch The request uses the same client token asa previous, but non-identical request. 403 Forbidden clientToken对应的API参数不一样。
SignatureDoesNotMatch The request signature we calculated does not match the signature you provided. Check yourSecret Access Key and signing method. Consultthe service documentation for details. 400 Bad Request Authorization头域中附带的签名和服务端验证不一致。