AWS s3 V4签名算法
原創,轉載請注明:http://www.jianshu.com/p/a6a02309190f
一、開篇說明:
以下思考方向,是以Android端為出發點(IOS同理)
AWS:Amazon Web Services (亞馬遜云服務)
AWS s3 API文檔:https://aws.amazon.com/cn/documentation/s3/
Minio :(具體的解釋自行百度吧)一個基于 golang 語言開發的 AWS S3 存儲協議的開源實現,并附帶 web ui 界面,可以通過 Minio 搭建私人的兼容 AWS S3 協議的存儲服務器。
二、需求分析
項目需求:最近公司需要搭建一個文件服務器,讓移動端(Android、ios)用來存儲圖片等文件。這個文件服務器后臺使用minio搭建的。由于minio是基于AWS S3 存儲協議,所以我們移動端也需要實現相同的協議來上傳。移動端,我們確定了三種可行方案(方案優劣僅是基于對APK打包大小的影響程度來確定的):
方案一:基于AWS S3 存儲協議自己實現文件上傳(最佳方案,最后項目引入文件最小----大約100K,不影響apk大小)
方案二:使用AWS SDK 實現文件上傳(中間方案,需要引入項目的jar包1.5M文件略大)
方案三:使用minio SDK 實現文件上傳(最差方案,需要引入6M jar包)
三、代碼實現
由于項目需求不同,供大家自行選擇,我將這三種方案實現一一說明。
方案三:
demo下載:https://github.com/Nergal1/minio-demo
1.Android端引入minio SDK jar包會和原生的發生沖突,會報一些安全錯誤。
引入時,去除沖突的包,com.fasterxml.jackson.core和com.google.code.findbugs:
2.上傳代碼:
提醒:別忘了開啟網絡權限
3.簡易源碼流程圖,數字代表行號:
minio上傳源碼簡易流程圖
方案二:
demo下載:https://github.com/Nergal1/AWS-S3-demo
1.由于AWS SDK源碼中是開啟Service,然后創建線程池實現異步上傳、下載功能。
清單文件要注冊service:
權限:
2.引入jar包:
aws-android-sdk-core-2.4.2.jar
aws-android-sdk-s3-2.4.2.jar
3.先配置Constants.java中的ENDPOINT、ACCESSKEY、SecretKey、BUCKET_NAME
上傳代碼見UploadActivity.java(下載請自行查看DownloadActivity):
?
//監聽類 private class UploadListener implements TransferListener { // Simply updates the UI list when notified. 上傳失敗監聽 @Override public voidonError(intid,Exception e) { Log.e(TAG,"Error during upload: "+ id,e); updateList(); } //上傳進度監聽 @Override public voidonProgressChanged(intid, longbytesCurrent, longbytesTotal) { Log.d(TAG,String.format("onProgressChanged: %d, total: %d, current: %d", id,bytesTotal,bytesCurrent)); updateList(); } //上傳狀態監聽 @Override public voidonStateChanged(intid,TransferState newState) { Log.d(TAG,"onStateChanged: "+ id +", "+ newState);//例如:UploadActivity: onStateChanged: 9, FAILD 失敗狀態 // ? ? ? ? ? ?//根據id 查詢文件路徑 // ? ? ? ? ? ?TransferObserver transferObserver = transferUtility.getTransferById(id); // ? ? ? ? ? ?Log.d(TAG, "文件地址---"+transferObserver.getAbsoluteFilePath()); updateList(); } }
4.源碼簡易流程圖,數字代表行號:
aws sdk上傳源碼簡易流程圖
3.實現原理分析:
實際上AWS S3 存儲協議只不過是添加一些跟服務端協商的請求頭,請求頭的value是用AWS s3 V4簽名算法算出來的。所以,上傳時帶上指定的請求頭,以及合法的簽名算法,其他地方跟普通上傳沒區別。服務端拿到請求頭后,根據合法的簽名算法,計算簽名值,然后跟客戶端請求頭里的簽名進行校驗,成功后,服務端才允許上傳。
首先我們要解決兩個問題:
(1)指定的請求頭有哪些?
首先我們來看一個文件上傳的請求:
?
--------------------------------------請求體-------------- 20000;chunk-signature=0cfa38451a889b866dbf43907ce3a72ee85f6b176168fb875903e8353366628e 。。。二進制文件流。。。
一大堆請求頭,實際上根據 S3 API 文檔,Authorization請求頭才是必要的
而Authorization的value中SignedHeaders是規定了使用哪些請求頭來計算本次請求的簽名值。
注意:SignedHeaders還規定了請求頭的順序。后面計算簽名流程圖中Canonical Request拼接請求頭的順序與SignedHeaders必須保持一致。
也就是說content-md5;host;x-amz-content-sha256;x-amz-date;x-amz-decoded-content-length這些請求頭計算出來Signature的值。根據S3 API 文檔,SignedHeaders中host;x-amz-content-sha256;x-amz-date是必須存在的。
那為什么本次請求還要加上content-md5,x-amz-decoded-content-length這兩個值?
我們來想想簽名的作用:
- a.驗證請求身份
ACCESSKEY、SecretKey就是用來驗證身份的,這兩個參數也是計算Authorization的value中Signature的值所必須的。
- b.防止篡改
SignedHeaders就是用來設置防止篡改的請求頭的,content-md5是防止篡改請求內容(body),x-amz-decoded-content-length防止篡改請求內容長度的。
官方文檔中,SignedHeaders必須的host;x-amz-content-sha256;x-amz-date這幾個也就可以理解了,防止篡改請求地址,請求內容的sha256值,請求時間戳
- c.防止請求簽名被盜用
根據AWS S3 存儲協議,時間戳(x-amz-date或Date請求頭)15分鐘內有效,沒有權限的用戶t通過截獲已簽名的request,可以篡改SignedHeaders中沒有包含的部分,所以官方建議,簽名所有請求頭和請求體(也就是說SignedHeaders要盡量包含所有),還有最好用Https.
- 總結:
啰嗦一大堆,必要的請求頭有哪些:Authorization、SignedHeaders中包含的(必須包含的有host;x-amz-content-sha256;x-amz-date),host,x-amz-content-sha256,x-amz-date這些請求頭是服務端校驗簽名必須的。
(2)簽名算法是如何計算的?(即Authorization中的Signature)
有兩種簽名算法:
- 第一種,單塊傳輸(本人demo中使用的這種方式)
文件內存讀取兩次(一次計算文件sha256時,一次文件上傳時)
單塊上傳請求頭:
x-amz-content-sha256: 32e820d03db121caf97206f8cbcc6202cf25bf59246e8d6b0e8f6e3502d68f66
或:x-amz-content-sha256: UNSIGNED-PAYLOAD(這種是單塊不進行簽名內容的寫法)
a.
單塊上傳簽名計算流程
功能函數說明:
Lowercase():字符串轉成小寫.
Hex():base 16編碼(全部小寫).
SHA256Hash():計算請求體body(上傳文件時,body中只有文件,即計算文件的SHA256)的SHA256,然后base64.
HMAC-SHA256():通過將key使用SHA256計算 HMAC
Trim():去空格.
UriEncode():
a.保持'A'-'Z','a'-'z', '0'-'9', '-', '.', '_', '~'不變
b.空格字符必須轉成"%20" (而不是 "+")
c.byte編譯成“%”后面跟兩位的十六進制(字母大寫)
d.如果文件名(object name)類似“photos/Jan/sample.jpg”,其中包含“/”,不進行轉義。
?
- 第二種,多塊傳輸
多塊上傳請求頭:
x-amz-content-sha256: STREAMING-AWS4-HMAC-SHA256-PAYLOAD
把有效荷載(請求body)分成幾塊,固定或可變大小的塊。通過上傳塊,避免讀取整個文件的有效荷載來計算簽名.
- a.第一塊,計算所有的請求頭的簽名,空body請求
- b.第二塊,將第一個塊的簽名和有效載荷一起計算簽名
- c.第n塊,將第n-1塊的簽名和有效載荷一起計算簽名
- d.最后,發送0 bytes的塊包含第n塊的簽名。
請求頭Authorization中的Signature計算同單塊上傳:
多塊上傳簽名計算流程圖
請求體中塊簽名計算:
請求體中比單塊上傳多了這些
chunk-signature的簽名計算流程圖
終于,說完了,第一次寫這么長,講的有不清楚的多多包涵,有什么問題可以給我留言,也可以發我郵箱18514689920@163.com.
---------------------?
作者:nergal_?
來源:CSDN?
原文:https://blog.csdn.net/e491288767/article/details/72819606?
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!
總結
以上是生活随笔為你收集整理的AWS s3 V4签名算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 音视频开发相关工具整理
- 下一篇: 【推荐】Nginx基础知识之————多模