

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Verificación de la firma de un mensaje de Amazon SNS cuando se utilizan solicitudes basadas en consultas HTTP
<a name="sns-verify-signature-of-message-verify-message-signature"></a>

Al verificar la firma de un mensaje de Amazon SNS cuando se utilizan solicitudes basadas en consultas HTTP se garantiza la autenticidad y la integridad del mensaje. Este proceso confirma que el mensaje proviene de Amazon SNS y no se ha manipulado durante el tránsito. Al analizar el mensaje, construir la cadena correcta para firmarlo y validar la firma con una clave pública de confianza, se protege el sistema contra la suplantación de identidad y las alteraciones no autorizadas de los mensajes.

1. Extraiga los **pares de clave-valor** del documento JSON en el cuerpo de la solicitud HTTP POST que envía Amazon SNS. Estos campos son necesarios para construir la **cadena que se va a firmar**.
   + `Message`
   + `Subject` (si está presente)
   + `MessageId`
   + `Timestamp`
   + `TopicArn`
   + `Type`

   Por ejemplo:

   ```
   MESSAGE_FILE="message.json"
   FIELDS=("Message" "MessageId" "Subject" "Timestamp" "TopicArn" "Type")
   ```
**nota**  
Si algún campo contiene caracteres de escape (por ejemplo,`\n`), conviértalos a su **formato original** para garantizar una coincidencia exacta.

1. Localice el campo `SigningCertURL` en el mensaje de Amazon SNS. Este certificado contiene la clave pública necesaria para verificar la firma del mensaje. Por ejemplo:

   ```
   SIGNING_CERT_URL=$(jq -r '.SigningCertURL' "$MESSAGE_FILE")
   ```

1. Asegúrese de que `SigningCertURL` sea de un AWS dominio de confianza (por ejemplo,https://sns.us-east-1.amazonaws.com). Rechaza cualquier ** AWS dominio URLs externo** por motivos de seguridad.

1. Descargue el **certificado X.509 **desde la URL proporcionada. Por ejemplo:

   ```
   curl -s "$SIGNING_CERT_URL" -o signing_cert.pem
   ```

1. Extraiga la **clave pública** del certificado X.509 descargado. La clave pública le permite descifrar la firma del mensaje y comprobar su integridad. Por ejemplo:

   ```
   openssl x509 -pubkey -noout -in signing_cert.pem > public_key.pem
   ```

1. Los diferentes tipos de mensajes requieren diferentes pares de clave-valor en la cadena para firmarlos. Identifique el **tipo de mensaje** (campo `Type` en el mensaje de Amazon SNS) para determinar qué **pares de clave-valor** incluir:
   + **Mensaje de notificación**: incluye `Message`, `MessageId`, `Subject` (si está presente), `Timestamp`, `TopicArn` y `Type`.
   + **SubscriptionConfirmation**o **UnsubscribeConfirmation mensaje**: incluye `Message``MessageId`,`SubscribeURL`, `Timestamp``Token`,`TopicArn`, y`Type`.

1. Amazon SNS requiere que la cadena se firme para seguir un orden de campos estricto y fijo para la verificación. **Solo se deben incluir los campos explícitamente obligatorios**; no se pueden añadir campos adicionales. Los campos opcionales, como `Subject`, deben incluirse solo si están presentes en el mensaje y deben aparecer en la posición exacta definida por el orden de los campos obligatorios. Por ejemplo:

   ```
   KeyNameOne\nValueOne\nKeyNameTwo\nValueTwo
   ```
**importante**  
No agregue un carácter de nueva línea al final de la cadena.

1. Organice los **pares de clave-valor** en orden de clasificación de bytes (alfabéticamente por nombre de clave).

1. Construya la **cadena para firmarla **con el siguiente ejemplo de formato:

   ```
   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
   ```

   **Ejemplo de mensaje de notificación:**

   ```
   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 ejemplo:**

   ```
   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
   ```

1. El campo `Signature` del mensaje está codificado en Base64. Debe **descodificarlo** para comparar su **formato binario sin procesar** con el **hash derivado**. Por ejemplo:

   ```
   SIGNATURE=$(jq -r '.Signature' "$MESSAGE_FILE")
   echo "$SIGNATURE" | base64 -d > signature.bin
   ```

1. Use el campo `SignatureVersion` para seleccionar el algoritmo de hash:
   + Para `SignatureVersion` **1**, utilice **SHA1**(por ejemplo,`-sha1`).
   + Para `SignatureVersion` **2**, utilice **SHA256**(por ejemplo,`-sha256`).

1. Para confirmar la autenticidad del mensaje de Amazon SNS, genere un **hash** de la cadena construida y verifique la firma con la **clave pública**.

   ```
   openssl dgst -sha256 -verify public_key.pem -signature signature.bin <<< "$STRING_TO_SIGN"
   ```

   Si la firma es válida, el resultado es `Verified OK`. En cualquier otro caso, el resultado es`Verification Failure`.

## Script de ejemplo con gestión de errores
<a name="sns-verify-signature-of-message-example"></a>

El siguiente script de ejemplo automatiza el proceso de verificación:

```
#!/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)
```