本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
在使用 HTTP 查詢型請求時,驗證 Amazon SNS 訊息的簽章
在使用 HTTP 查詢型請求時,驗證 Amazon SNS 訊息的簽章可確保訊息的真實性和完整性。此程序會確認訊息來自 Amazon SNS,且未在傳輸期間遭到竄改。透過剖析訊息、建構正確的簽署字串,以及針對信任的公有金鑰驗證簽章,您可以保護您的系統免於詐騙和未經授權的訊息變更。
-
從 Amazon SNS 傳送的 HTTP POST 請求內文中的 JSON 文件擷取金鑰/值對。這些欄位是建構要簽署的字串的必要欄位。
-
Message -
Subject(如果有) -
MessageId -
Timestamp -
TopicArn -
Type
例如:
MESSAGE_FILE="message.json" FIELDS=("Message" "MessageId" "Subject" "Timestamp" "TopicArn" "Type")注意
如果任何欄位包含逸出字元 (例如
\n),請將它們轉換為原始格式,以確保完全相符。 -
-
在 Amazon SNS 訊息中尋找
SigningCertURL欄位。此憑證包含驗證訊息簽章所需的公有金鑰。例如:SIGNING_CERT_URL=$(jq -r '.SigningCertURL' "$MESSAGE_FILE") -
確定
SigningCertURL來自信任的 AWS 網域 (例如 https://sns.us-east-1.amazonaws.com)。基於安全考量,拒絕 AWS 網域外的任何 URLs。 -
從提供的 URL 下載 X.509 憑證。例如:
curl -s "$SIGNING_CERT_URL" -o signing_cert.pem -
從下載的 X.509 憑證中擷取公有金鑰。公有金鑰可讓您解密訊息的簽章並驗證其完整性。例如:
openssl x509 -pubkey -noout -in signing_cert.pem > public_key.pem -
不同的訊息類型需要字串中不同的鍵值對才能簽署。識別訊息類型 (
TypeAmazon SNS 訊息中的 欄位),以決定要包含哪些鍵值對:-
通知訊息 – 包括
Message、MessageId、Subject(如果有)TopicArn、、Timestamp和Type。 -
SubscriptionConfirmation 或 UnsubscribeConfirmation 訊息 – 包括
Message、MessageId、SubscribeURL、Token、Timestamp、TopicArn和Type。
-
-
Amazon SNS 需要字串簽署,以遵循嚴格的固定欄位順序進行驗證。僅必須包含明確的必要欄位,無法新增任何額外的欄位。只有在訊息中存在時
Subject,才會包含選用欄位,例如 ,且必須出現在必要欄位順序所定義的確切位置。例如:KeyNameOne\nValueOne\nKeyNameTwo\nValueTwo重要
請勿在字串結尾新增換行字元。
-
依位元組排序順序排列索引鍵/值對 (按索引鍵名稱的字母)。
-
使用下列格式範例建構字串以簽署:
STRING_TO_SIGN="" for FIELD in "${FIELDS[@]}"; do VALUE=$(jq -r --arg field "$FIELD" '.[$field]' "$MESSAGE_FILE") STRING_TO_SIGN+="$FIELD\n$VALUE" # Append a newline after each field except the last one if [[ "$FIELD" != "Type" ]]; then STRING_TO_SIGN+="\n" fi done通知訊息範例:
Message My Test Message MessageId 4d4dc071-ddbf-465d-bba8-08f81c89da64 Subject My subject Timestamp 2019-01-31T04:37:04.321Z TopicArn arn:aws:sns:us-east-2:123456789012:s4-MySNSTopic-1G1WEFCOXTC0P Type NotificationSubscriptionConfirmation 範例:
Message Please confirm your subscription MessageId 3d891288-136d-417f-bc05-901c108273ee SubscribeURL https://sns.us-east-2.amazonaws.com/... Timestamp 2024-01-01T00:00:00.000Z Token abc123... TopicArn arn:aws:sns:us-east-2:123456789012:MyTopic Type SubscriptionConfirmation -
訊息中的
Signature欄位以 Base64-encoded。您需要解碼它,將其原始二進位格式與衍生的雜湊進行比較。例如:SIGNATURE=$(jq -r '.Signature' "$MESSAGE_FILE") echo "$SIGNATURE" | base64 -d > signature.bin -
使用
SignatureVersion欄位來選取雜湊演算法:-
對於
SignatureVersion1,請使用 SHA1 (例如,-sha1)。 -
對於
SignatureVersion2,請使用 SHA256 (例如-sha256)。
-
-
若要確認 Amazon SNS 訊息的真實性,請產生建構字串的雜湊,並使用公有金鑰驗證簽章。
openssl dgst -sha256 -verify public_key.pem -signature signature.bin <<< "$STRING_TO_SIGN"如果簽章有效,則輸出為
Verified OK。否則,輸出為Verification Failure。
具有錯誤處理的範例指令碼
下列範例指令碼會自動執行驗證程序:
#!/bin/bash
# Path to the local message file
MESSAGE_FILE="message.json"
# Extract the SigningCertURL and Signature from the message
SIGNING_CERT_URL=$(jq -r '.SigningCertURL' "$MESSAGE_FILE")
SIGNATURE=$(jq -r '.Signature' "$MESSAGE_FILE")
# Fetch the X.509 certificate
curl -s "$SIGNING_CERT_URL" -o signing_cert.pem
# Extract the public key from the certificate
openssl x509 -pubkey -noout -in signing_cert.pem > public_key.pem
# Define the fields to include in the string to sign
FIELDS=("Message" "MessageId" "Subject" "Timestamp" "TopicArn" "Type")
# Initialize the string to sign
STRING_TO_SIGN=""
# Iterate over the fields to construct the string to sign
for FIELD in "${FIELDS[@]}"; do
VALUE=$(jq -r --arg field "$FIELD" '.[$field]' "$MESSAGE_FILE")
STRING_TO_SIGN+="$FIELD\n$VALUE"
# Append a newline after each field except the last one
if [[ "$FIELD" != "Type" ]]; then
STRING_TO_SIGN+="\n"
fi
done
# Verify the signature
echo -e "$STRING_TO_SIGN" | openssl dgst -sha256 -verify public_key.pem -signature <(echo "$SIGNATURE" | base64 -d)