[英]AWS S3 - send a signed requests fails
使用 header 方法适用于常规(AKA 永久)凭证和临时凭证。 使用查询字符串(AKS 将所有标头作为 uri 的一部分),使用永久凭据,但对于临时凭据失败,并出现以下错误:
The request signature we calculated does not match the signature you provided. Check your key and signing method.
它与任何时钟差异无关,而且我知道临时凭证适用于这个 S3 存储桶。
临时凭证的格式如下
[default]
aws_access_key_id = A********
aws_secret_access_key = U*******
aws_session_token = F******
我正在编写一个代码片段,需要处理来自私有 S3 存储桶的获取请求。 我有一个使用标头作为永久和临时凭证的工作代码
我现在的目标是使用查询字符串来实现相同的目标,但我无法让它用于临时凭据,它与永久凭据一起工作得很好,所以我很确定问题在 canonical_querystring 某处中继,但是我尝试过的任何东西似乎都不起作用
我不能使用 boto3,因为它需要独立于任何外部 package (请求 package 仅用于调试它不会成为最终代码的一部分)如果有人能告诉我我做错了什么,那将是高度赞赏
她是我使用查询字符串的尝试
import datetime
import hashlib
import hmac
import re
try:
import httplib
except ImportError:
import http.client as httplib
import requests
import urllib
def get_region(url, host):
conn = httplib.HTTPConnection(url)
headers = {'Host': host}
conn.request('HEAD', '/', headers=headers)
res = conn.getresponse()
status = res.status
if 400 <= status:
return None
return res.getheader('x-amz-bucket-region')
def _sign(key, msg):
return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()
def _get_signature_key(key, date_stamp, region_name, service_name):
k_date = _sign(('AWS4' + key).encode('utf-8'), date_stamp)
k_region = _sign(k_date, region_name)
k_service = _sign(k_region, service_name)
k_signing = _sign(k_service, 'aws4_request')
return k_signing
def get_sign_headers(access_key, secret_key, url, session_token=None, method='GET', request_parameters=''):
regex = r"^(https://)(([a-zA-z0-9\-]+)\.)((\w+.*)\.amazonaws\.com)([^:^/]*)?(.*)$"
matches = re.match(regex, url, re.MULTILINE)
service = 's3'
host = matches.group(2) + matches.group(4)
canonical_uri = matches.group(7)
region = get_region('s3.us-east-2.amazonaws.com', host)
if matches.group(3) == 's3':
if not region:
region = matches.group(5)
host = service + '.' + region + '.amazonaws.com'
endpoint = 'https://' + host + matches.group(7)
t = datetime.datetime.utcnow()
amz_date = t.strftime('%Y%m%dT%H%M%SZ') # Format date as YYYYMMDD'T'HHMMSS'Z'
datestamp = t.strftime('%Y%m%d') # Date w/o time, used in credential scope
canonical_headers = 'host:' + host + '\n'
signed_headers = 'host'
if session_token:
canonical_headers += 'x-amz-security-token:' + session_token + '\n'
signed_headers += ';x-amz-security-token'
algorithm = 'AWS4-HMAC-SHA256'
credential_scope = datestamp + '/' + region + '/' + service + '/' + 'aws4_request'
canonical_querystring = 'X-Amz-Algorithm=AWS4-HMAC-SHA256'
try:
credential = urllib.quote_plus(access_key + '/' + credential_scope)
except AttributeError:
credential = urllib.parse.quote_plus(access_key + '/' + credential_scope)
canonical_querystring += '&X-Amz-Credential=' + credential
canonical_querystring += '&X-Amz-Date=' + amz_date
canonical_querystring += '&X-Amz-Expires=30'
canonical_querystring += '&X-Amz-SignedHeaders=' + signed_headers
payload_hash = 'UNSIGNED-PAYLOAD'
canonical_request = method + '\n' + canonical_uri + '\n' + canonical_querystring + \
'\n' + canonical_headers + '\n' + signed_headers + '\n' + payload_hash
string_to_sign = algorithm + '\n' + amz_date + '\n' + credential_scope + '\n' + hashlib.sha256(
canonical_request.encode('utf-8')).hexdigest()
signing_key = _get_signature_key(secret_key, datestamp, region, service)
signature = hmac.new(signing_key, string_to_sign.encode("utf-8"), hashlib.sha256).hexdigest()
if session_token:
try:
session_token = urllib.quote_plus(session_token)
except AttributeError:
session_token = urllib.parse.quote_plus(session_token)
canonical_querystring += '&X-Amz-Security-Token={TOKEN}'.format(TOKEN=session_token)
canonical_querystring += '&X-Amz-Signature=' + signature
request_url = endpoint + "?" + canonical_querystring
print('\nBEGIN REQUEST++++++++++++++++++++++++++++++++++++')
print('Request URL = ' + request_url)
r = requests.get(request_url)
print('\nRESPONSE++++++++++++++++++++++++++++++++++++')
print('Response code: %d\n' % r.status_code)
print(r.text)
这是使用标头方法的代码(适用于两者):
import datetime
import hashlib
import hmac
import re
import requests
try:
import httplib
except ImportError:
import http.client as httplib
def get_region(url, host):
conn = httplib.HTTPConnection(url)
headers = {'Host': host}
conn.request('HEAD', '/', headers=headers)
res = conn.getresponse()
status = res.status
if 400 <= status:
return None
return res.getheader('x-amz-bucket-region')
def _sign(key, msg):
return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()
def _get_signature_key(key, date_stamp, region_name, service_name):
k_date = _sign(('AWS4' + key).encode('utf-8'), date_stamp)
k_region = _sign(k_date, region_name)
k_service = _sign(k_region, service_name)
k_signing = _sign(k_service, 'aws4_request')
return k_signing
def get_sign_headers(access_key, secret_key, url, session_token=None, method='GET', request_parameters=''):
regex = r"^(https://)(([a-zA-z0-9\-]+)\.)((\w+.*)\.amazonaws\.com)([^:^/]*)?(.*)$"
matches = re.match(regex, url, re.MULTILINE)
service = 's3'
host = matches.group(2) + matches.group(4)
canonical_uri = matches.group(7)
region = get_region('s3.us-east-2.amazonaws.com', host)
if matches.group(3) == 's3':
if not region:
region = matches.group(5)
host = service + '.' + region + '.amazonaws.com'
endpoint = 'https://' + host
t = datetime.datetime.utcnow()
amz_date = t.strftime('%Y%m%dT%H%M%SZ')
datestamp = t.strftime('%Y%m%d') # Date w/o time, used in credential scope
canonical_querystring = request_parameters
canonical_headers = 'host:' + host + '\n' + 'x-amz-content-sha256:UNSIGNED-PAYLOAD' + \
'\n' + 'x-amz-date:' + amz_date + '\n'
signed_headers = 'host;x-amz-content-sha256;x-amz-date'
if session_token:
signed_headers += ';x-amz-security-token'
canonical_headers += 'x-amz-security-token:' + session_token + '\n'
payload_hash = 'UNSIGNED-PAYLOAD'
canonical_request = method + '\n' + canonical_uri + '\n' + canonical_querystring + \
'\n' + canonical_headers + '\n' + signed_headers + '\n' + payload_hash
algorithm = 'AWS4-HMAC-SHA256'
credential_scope = datestamp + '/' + region + '/' + service + '/' + 'aws4_request'
string_to_sign = algorithm + '\n' + amz_date + '\n' + credential_scope + '\n' + hashlib.sha256(
canonical_request.encode('utf-8')).hexdigest()
signing_key = _get_signature_key(secret_key, datestamp, region, service)
signature = hmac.new(signing_key, string_to_sign.encode('utf-8'), hashlib.sha256).hexdigest()
authorization_header = algorithm + ' ' + 'Credential=' + access_key + '/' + credential_scope + ', ' + \
'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + signature
headers = {'x-amz-date': amz_date, 'x-amz-content-sha256': 'UNSIGNED-PAYLOAD',
'Authorization': authorization_header}
if session_token:
headers['x-amz-security-token'] = session_token
request_url = endpoint + canonical_uri
print('\nBEGIN REQUEST++++++++++++++++++++++++++++++++++++')
print('Request URL = ' + request_url)
print('Headers = {}'.format(headers))
r = requests.get(request_url, headers=headers)
print('\nRESPONSE++++++++++++++++++++++++++++++++++++')
print('Response code: %d\n' % r.status_code)
您是否验证过您的服务器时间是准确的。 即使是几分钟的差异也会导致签名失败。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.