View a markdown version of this page

HTTP クエリベースのリクエストの使用時に Amazon SNS メッセージの署名を確認する - Amazon Simple Notification Service

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

HTTP クエリベースのリクエストの使用時に Amazon SNS メッセージの署名を確認する

HTTP クエリベースのリクエストを使用する際に Amazon SNS メッセージの署名を検証すると、メッセージの信頼性と整合性が保証されます。このプロセスでは、メッセージが Amazon SNS から発信され、転送中に改ざんされていないことを確認します。メッセージの解析、署名用の正しい文字列の作成、信頼できるパブリックキーによる署名の検証を行うことで、なりすましや不正なメッセージ変更からシステムを保護できます。

  1. Amazon SNS から送信された HTTP POST リクエストの本文で、JSON ドキュメントからキーと値のペアを抽出します。これらのフィールドは、署名文字列を作成するために必要です。

    • Message

    • Subject (存在する場合)

    • MessageId

    • Timestamp

    • TopicArn

    • Type

    例えば、次のようになります。

    MESSAGE_FILE="message.json" FIELDS=("Message" "MessageId" "Subject" "Timestamp" "TopicArn" "Type")
    注記

    いずれかのフィールドにエスケープ文字 (\n など) が含まれている場合は、それらの文字を元の形式に変換して、正確な一致が確実に行われるようにします。

  2. Amazon SNS メッセージで SigningCertURL フィールドを見つけます。この証明書には、メッセージ署名の検証に必要なパブリックキーが含まれています。例えば、次のようになります。

    SIGNING_CERT_URL=$(jq -r '.SigningCertURL' "$MESSAGE_FILE")
  3. SigningCertURL が信頼された AWS ドメイン ( など) からのものであることを確認しますhttps://sns.us-east-1.amazonaws.com。セキュリティ上の理由から、 AWS ドメイン外の URLs。

  4. 指定された URL から X.509 証明書をダウンロードします。例えば、次のようになります。

    curl -s "$SIGNING_CERT_URL" -o signing_cert.pem
  5. ダウンロードした X.509 証明書からパブリックキーを抽出します。パブリックキーを使用すると、メッセージの署名を復号化して、その整合性を検証できます。例えば、次のようになります。

    openssl x509 -pubkey -noout -in signing_cert.pem > public_key.pem
  6. メッセージタイプが異なると、署名文字列に含めるキーと値のペアも異なります。メッセージタイプ (Amazon SNS メッセージ内の Type フィールド) を特定して、含めるキーと値のペアを決定します。

    • 通知メッセージMessageMessageIdSubject (存在する場合)、TimestampTopicArn、および Type が含まれます。

    • SubscriptionConfirmation または UnsubscribeConfirmation メッセージMessageMessageIdSubscribeURLTimestampTokenTopicArn、および Type が含まれます。

  7. Amazon SNS では、検証を行うために、署名文字列は厳格で固定されたフィールドの順序に従う必要があります。明示的な必須フィールドのみを含める必要があり、追加のフィールドを加えることはできません。Subject などのオプションフィールドは、そのフィールドがメッセージ内に存在する場合にのみ含める必要があり、必須フィールドの順序で定義された正確な位置に含める必要があります。例えば、次のようになります。

    KeyNameOne\nValueOne\nKeyNameTwo\nValueTwo
    重要

    文字列の末尾に改行文字を追加しないでください。

  8. キーと値のペアをバイト順でソートし、並べます (キー名に基づくアルファベット順)。

  9. 次の形式の例を使用して、署名文字列を作成します。

    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 Notification

    SubscriptionConfirmation の例:

    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
  10. メッセージ内の Signature フィールドは Base64 でエンコードされています。未加工のバイナリ形式と、派生したハッシュを比較するために、このフィールドをデコードする必要があります。例えば、次のようになります。

    SIGNATURE=$(jq -r '.Signature' "$MESSAGE_FILE") echo "$SIGNATURE" | base64 -d > signature.bin
  11. SignatureVersion フィールドを使用してハッシュアルゴリズムを選択します。

    • SignatureVersion1 の場合 SHA1 を使用します (例: -sha1)。

    • SignatureVersion2 の場合 SHA256 を使用します (例: -sha256)。

  12. 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)