前言
请求S3接口时,S3服务会对接口进行鉴权,目前鉴权算法分v2和v4版本,对于 AWS S3 来讲,v4 签名是 v2签名的增强型扩展,目前很多线上服务还是使用的v2签名,很多服务继续使用v2签名算法的一个很大原因可能就是v4签名算法最大签名失效只有7天,而v2版本签名可以支持7天以上。下面着重介绍下如何构造使用v2签名过程:
V2签名过程
整个过程大致分为下面3个部分。
1、生成签名字符串
1、把请求方法(GET、POST等)、请求header里面的指定字段(比如content-md5、content-type)全部拼接起来;
- 把请求header里面的以x-amz-开头的指定字段全部拼接起来;
1 |
将每个 HTTP 标头名称转换为小写。例如,“X-Amz-Date”改为“x-amz-date”。 |
2 |
根据标头名称按字典顺序排列标头集。 |
3 |
将相同名称的标头字段合并为一个“header-name:comma-separated-value-list”对,并按照 RFC 2616 中第 4.2 节中的规定,两个值之间不留空格。例如,可以将元数据标头“x-amz-meta-username: fred”和“x-amz-meta-username: barney”合并为单个标头“x-amz-meta-username: fred,barney”。 |
4 |
通过将折叠空格(包括新建行)替换为单个空格,“展开”跨多个行的长标头(按照 RFC 2616 中第 4.2 节允许的方式)。 |
5 |
删除标头中冒号周围的空格。例如,标头“x-amz-meta-username: fred,barney”改为“x-amz-meta-username:fred,barney”。 |
6 |
最后,请向生成的列表中的每个标准化标头附加换行字符 (U+000A)。通过将此列表中所有的标头规范化为单个字符串,构建 CanonicalizedResource 元素。 |
3、把请求uri和请求参数全部拼接起来;
4、最后生成的签名字符串像这样:’GET\n\n\n\nx-amz-date:Fri, 29 Nov 2019 09:01:14 +0000\n/‘,有效的时间戳对于经身份验证的请求是必须的 (使用 HTTP Date 标头或 x-amz-date 替代项)。此外,经身份验证的请求随附的客户端时间戳必须处于收到请求时的 Amazon S3 系统时间的 15 分钟之内。否则,请求将失败并出现 RequestTimeTooSkewed 错误代码。施加这些限制的目的是为了防止对方重新使用已拦截的请求。要更好地防范窃听,请对经身份验证的请求使用 HTTPS 传输。
2、对第1步中生成的签名字符串加密处理
处理过程大致如下(string_to_sign表示第一步里面生成的签名字符串):
1、从配置文件里面获取用户的密钥secret_key。
2、把secret_key转为utf-8编码格式。
3、使用secret_key对string_to_sign加密处理得到签名字符串。
4、最后把签名字符串转为unicode编码格式,类似这样:
vjbyPxybdZaNmGa%2ByT272YEAiv4%3D
注意:必须使用 Base64 编码 HMAC 请求签名。Base64 编码将签名转换为可附加到请求的简单 ASCII 字符串。如果要在 URI 中使用诸如加号 (+)、正斜杠 (/) 和等号 (=) 等可在签名中显示的字符,必须对它们进行编码。例如,如果身份验证代码包括一个加号 (+) 标志,请在请求中将其编码为 %2B。将正斜杠编码为 %2F,并将等号编码为 %3D。
3、拼接相关的信息,生成最后的签名字符串
最后的签名字符串为:”AWS “ + 用户的access_key + “:” + 第2步中生成的加密签名字符串。类似这样:
AWS test:vjbyPxybdZaNmGa%2ByT272YEAiv4%3D
4、 示例使用代码构造签名获取对象
使用脚本语言构造签名下载对象
objname="single-file-01.txt"
bucket="admin-bucket-002"
url="127.0.0.1:8770"
resource="/${bucket}/${objname}"
contentType="application/text"
dateValue=`date -u -R`
stringToSign="GET\n\n${contentType}\n${dateValue}\n${resource}"
s3Key="xxx"
s3Secret="xxxx"
echo "$dateValue"
signature=`echo -en ${stringToSign} | openssl sha1 -hmac ${s3Secret} -binary | base64`
echo $signature
curl -X GET \
-H "Host: ${bucket}.${url}" \
-H "Date: ${dateValue}" \
-H "Content-Type: ${contentType}" \
-H "Authorization: AWS ${s3Key}:${signature}" \
"${url}/${bucket}/${objname}"
java s3 sdk默认使用v4签名算法,可以指定签名算法使用v2签名,示例代码如下:
AWSCredentials credentials = new BasicAWSCredentials(ak, sk);
ClientConfiguration clientConfiguration = new ClientConfiguration();
clientConfiguration.setProtocol(Protocol.HTTP);
clientConfiguration.setSignerOverride("SignerType");