常见签名认证错误排查
签名认证中常见以下问题,你可以配合签名排查工具在线排查签名问题,或者通过如下的排查说明进行一一排查:
- 不能正确区分URL中的URI部分和QueryString部分
- URI尾部的"/"不一致
- Host头域端口不一致
- x-bce-date头的问题
- 用错了ak/sk
- 客户基于StsCredential来请求但服务未正确传递security_token
- 生成签名过程中注意事项
不能正确区分URL中的URI部分和QueryString部分
假设请求的URL是/v1/settings/region/list?type=public
,此处URI应该为/v1/settings/region/list
,type=public
是querystring。但是客户端并没有正确区分它们,在计算签名时把/v1/settings/region/list?type=public
都当成了PATH,进而得到的CanonicalRequest,因此传送的签名也有问题。 而服务端在验证签名使用的
# 客户端请求的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"。
生成签名过程中注意事项
- 检查HTTP Method是否正确
-
CanonicalURI部分
- 注意前面不需要加host,必须以“/”开头,不以“/”开头的需要补充上,空路径为“/”;
- 注意结尾不该有“/”;
- 注意要做uriEncodeExceptSlash编码。
-
CanonicalQueryString部分
- 注意要按字典序进行排序;
- 没有value的key,是否也保留了“=”;
- 没有queryString时,也要在最终的CanonicalRequest中拼接一个\n。
-
CanonicalHeaders部分
- 百度智能云默认的signedHeaders:Host、Content-Length、Content-Type、Content-MD5、所有以 x-bce- 开头的Header;
- 注意这里的header内容,要与实际请求中的header内容完全一致,尤其注意host是否有端口号,x-bce-date是否有变化;
- 实际发出请求中,是否有header被第三方库删除了?
- 如果请求中{signedHeaders}字段留空,那么是否完全按照百度智能云默认的signedHeaders计算的?
-
签名前缀信息
- timestamp是认证字符串创建时间,不能过早或过晚;
- 输入的SK与AK要对应