我想通過 Python 驗證 S3(托管在 digitalocean)預簽名 URL 的簽名。據我所知,簽名由完整的 URL 和密鑰組成。
我已經嘗試過諸如AWS S3 presigned urls with boto3 - Signature mismatch 之類的東西,但這會導致不同的簽名。
我想通過使用散列演算法重新創建 URL 中給出的簽名(例如影像)來檢查它。
我該怎么做呢?
uj5u.com熱心網友回復:
我遇到了同樣的問題,并希望該boto軟體包能夠提供一種簡單的方法來做到這一點,但不幸的是它沒有。
我也嘗試使用boto基于url創建相同的簽名,但問題是時間戳(X-Amz-Date在url中)要獲得完全相同的簽名,需要使用url中提供的時間戳來生成。我陷入了兔子洞,試圖“覆寫”日期時間,但這似乎是不可能的。
所以剩下的就是從頭開始生成簽名,就像你說你試過的那樣。您鏈接的問題中的代碼確實有效,但并不簡單。
受該鏈接和boto3源代碼的啟發,這就是我創建的并且似乎有效:
from urllib.parse import urlparse, parse_qs, urlencode, quote
import hashlib
import hmac
from django.conf import settings
def validate_s3_url(url, method='GET'):
"""
This check whether the signature in the given S3 url is valid,
considering the other parts of the url.
This requires that we have access to the (secret) access key
that was used to sign the request (the access key ID is
available in the url).
"""
parts = urlparse(url)
querydict = parse_qs(parts.query)
# get relevant query parameters
url_signature = querydict['X-Amz-Signature'][0]
credentials = querydict['X-Amz-Credential'][0]
algorithm = querydict['X-Amz-Algorithm'][0]
timestamp = querydict['X-Amz-Date'][0]
signed_headers = querydict['X-Amz-SignedHeaders'][0]
# if we have multiple access keys we could use access_key_id to get the right one
access_key_id, credential_scope = credentials.split("/", maxsplit=1)
host = parts.netloc
# important: in Python 3 this dict is sorted which is essential
canonical_querydict = {
'X-Amz-Algorithm': [algorithm],
'X-Amz-Credential': [credentials],
'X-Amz-Date': [timestamp],
'X-Amz-Expires': querydict['X-Amz-Expires'],
'X-Amz-SignedHeaders': [signed_headers],
}
# this is optional (to force download with specific name)
# if used, it's passed in as 'ResponseContentDisposition' Param when signing.
if 'response-content-disposition' in querydict:
canonical_querydict['response-content-disposition'] = querydict['response-content-disposition']
canonical_querystring = urlencode(canonical_querydict, doseq=True, quote_via=quote)
# build the request, hash it and build the string to sign
canonical_request = f"{method}\n{parts.path}\n{canonical_querystring}\nhost:{host}\n\n{signed_headers}\nUNSIGNED-PAYLOAD"
hashed_request = hashlib.sha256(canonical_request.encode('utf-8')).hexdigest()
string_to_sign = f"{algorithm}\n{timestamp}\n{credential_scope}\n{hashed_request}"
# generate signing key from credential scope.
signing_key = f"AWS4{settings.AWS_SECRET_ACCESS_KEY}".encode('utf-8')
for message in credential_scope.split("/"):
signing_key = hmac.new(signing_key, message.encode('utf-8'), hashlib.sha256).digest()
# sign the string with the key and check if it's the same as the one provided in the url
signature = hmac.new(signing_key, string_to_sign.encode('utf-8'), hashlib.sha256).hexdigest()
return url_signature == signature
這使用 django 設定來獲取密鑰,但實際上它可能來自任何地方。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/490253.html
標籤:python-3.x 亚马逊-s3
上一篇:EvaporateJS:恢復上傳后總是得到403SignatureDoesNotMatch錯誤
下一篇:來自S3訪問的AWS備份被拒絕
