前言
請求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");