2017-10-17 74 views
0

我使用下面的代碼做一個簡單的PUT請求AWS S3做錯了使用版本4簽名:以上我所用S3 PUT請求使用AWS簽名版本4

from collections import OrderedDict 
from dateutil import parser 
import datetime 
import hashlib 
import hmac 
import requests 

key_id = "REDACTED" 
secret = "REDACTED" 
bucket_name = "REDACTED" 

def hashb16(message): 
    return hashlib.sha256(message).hexdigest() 

def HMAC(key, message): 
    return hmac.new(key, message, hashlib.sha256) 

current_time = datetime.datetime.utcnow() 

url = "https://s3-eu-west-2.amazonaws.com/{}/sometest.txt".format(bucket_name) 
payload = "Welcome to Amazon S3." 
headers = { 
    'date': current_time.strftime("%a, %d %b %Y %H:%m:%S GMT"), 
    'host': "s3-eu-west-2.amazonaws.com", 
    'x-amz-content-sha256': hashb16(payload), 
    'x-amz-date': current_time.strftime('%Y%m%dT%H%M%SZ'), 
    'x-amz-storage-class': 'REDUCED_REDUNDANCY' 
} 
sorted_headers = sorted([k for k in headers]) 
region = "eu-west-2" 
service = "s3" 

# step 1 
HTTPRequestMethod = "PUT" 
CanonicalURI = "/sometest.txt" 
CanonicalQueryString = "" 
CanonicalHeaders = "" 
for key in sorted_headers: 
    CanonicalHeaders += "{}:{}\n".format(key.lower(), headers[key]) 
SignedHeaders = "{}".format(";".join(sorted_headers)) 
HexEncondeHashRequestPayload = hashb16(payload) 
CanonicalRequest = "{}\n{}\n{}\n{}{}\n{}".format(HTTPRequestMethod, CanonicalURI, CanonicalQueryString, CanonicalHeaders, SignedHeaders, HexEncondeHashRequestPayload) 

# step 2 
Algorithm = "AWS4-HMAC-SHA256" 
RequestDateTime = current_time.strftime('%Y%m%dT%H%M%SZ') 
CredentialScope = "{}/{}/{}/{}".format(current_time.strftime("%Y%m%d"), region, service, "aws4_request") 
HashedCanonicalRequest = hashb16(CanonicalRequest) 
StringToSign = "{}\n{}\n{}\n{}".format(Algorithm, RequestDateTime, CredentialScope, HashedCanonicalRequest) 

#step 3 
kDate = HMAC("AWS4" + secret,  current_time.strftime("%Y%m%d")).digest() 
kRegion = HMAC(kDate, region).digest() 
kService = HMAC(kRegion, service).digest() 
kSigning = HMAC(kService, "aws4_request").digest() 
signature = HMAC(kSigning, StringToSign).hexdigest() 

#step 4 
Authorization = "AWS4-HMAC-SHA256 Credential={}/{},SignedHeaders={},Signature={}".format(key_id, CredentialScope, ";".join(sorted_headers), signature) 
headers["Authorization"] = Authorization 

response = requests.request("PUT", url, headers=headers) 

print response.status_code 
print response.text 

的步驟是每AWS documentation。我使用this page中的示例測試了散列函數,他們結算。

不幸的是,當執行實際的請求時,我得到一個帶有通常的無效簽名消息的403狀態碼。我在上面的代碼中錯過了什麼?

回答

1

您的StringToSign不正確。特別是HashedCanonicalRequest是不正確的。

亞馬遜錯誤響應將顯示確切的StringToSign。這將幫助你弄清楚什麼是錯的。

[編輯 - 我修改你的代碼工作。注意:我刪除了有效負載計算並將其更改爲UNSIGNED-PAYLOAD。有兩個小問題:

1)在StringToSign桶名稱未在指定的URL(後線CURRENT_TIME)

2)你是缺少一個CanonicalRequest \ n。

from collections import OrderedDict 
from dateutil import parser 
import datetime 
import hashlib 
import hmac 
import requests 

key_id = "" 
secret = "/N6VFTasQCJic3CqL9tj80UGB6Ba1B" 
region = "" 
bucket_name = "" 
service = "s3" 

def hashb16(message): 
    return hashlib.sha256(message).hexdigest() 

def HMAC(key, message): 
    return hmac.new(key, message, hashlib.sha256) 

current_time = datetime.datetime.utcnow() 

url = "https://s3-us-west-2.amazonaws.com/{}/sometest.txt".format(bucket_name) 
payload = "Welcome to Amazon S3." 
headers = { 
    'date': current_time.strftime("%a, %d %b %Y %H:%m:%S GMT"), 
    'host': "s3-us-west-2.amazonaws.com", 
    'x-amz-content-sha256': 'UNSIGNED-PAYLOAD', 
    'x-amz-date': current_time.strftime('%Y%m%dT%H%M%SZ'), 
    'x-amz-storage-class': 'REDUCED_REDUNDANCY' 
} 
sorted_headers = sorted([k for k in headers]) 

# step 1 
HTTPRequestMethod = "PUT" 
CanonicalURI = "/{}/sometest.txt".format(bucket_name) 
CanonicalQueryString = "" 
CanonicalHeaders = "" 
for key in sorted_headers: 
    CanonicalHeaders += "{}:{}\n".format(key.lower(), headers[key]) 
SignedHeaders = "{}".format(";".join(sorted_headers)) 
HexEncondeHashRequestPayload = hashb16(payload) 
CanonicalRequest = "{}\n{}\n{}\n{}\n{}\n{}".format(HTTPRequestMethod, CanonicalURI, CanonicalQueryString, CanonicalHeaders, SignedHeaders, 'UNSIGNED-PAYLOAD') 

# step 2 
Algorithm = "AWS4-HMAC-SHA256" 
RequestDateTime = current_time.strftime('%Y%m%dT%H%M%SZ') 
CredentialScope = "{}/{}/{}/{}".format(current_time.strftime("%Y%m%d"), region, service, "aws4_request") 
HashedCanonicalRequest = hashb16(CanonicalRequest) 
StringToSign = "{}\n{}\n{}\n{}".format(Algorithm, RequestDateTime, CredentialScope, HashedCanonicalRequest) 

#step 3 
kDate = HMAC("AWS4" + secret,  current_time.strftime("%Y%m%d")).digest() 
kRegion = HMAC(kDate, region).digest() 
kService = HMAC(kRegion, service).digest() 
kSigning = HMAC(kService, "aws4_request").digest() 
signature = HMAC(kSigning, StringToSign).hexdigest() 

#step 4 
Authorization = "AWS4-HMAC-SHA256 Credential={}/{},SignedHeaders={},Signature={}".format(key_id, CredentialScope, ";".join(sorted_headers), signature) 
headers["Authorization"] = Authorization 

response = requests.request("PUT", url, headers=headers) 

print response.status_code 
print response.text 
相關問題