Cómo validar integridad de webhooks con HMAC

Clase 24 de 30Curso de Ciberseguridad para Desarrollo Web

Resumen

La validación de la integridad de los datos en webhooks de GitHub se resuelve con una firma HMAC SHA-256, un secret compartido y AWS Secrets Manager. Aquí verás cómo configurar el secret, dar permisos con Terraform, usar una variable de entorno en Lambda y validar la firma de forma segura en Go, sin exponer credenciales y con despliegue reproducible.

¿Cómo validar la integridad con el header firmado de GitHub?

GitHub envía un header con el body encriptado mediante una firma basada en el secret del webhook. Si calculas la firma localmente con el mismo secret y coincide con la del header, confirmas la integridad del payload.

  • Crea un secret robusto con caracteres especiales y números. Copia el valor y actualiza el webhook con Update webhook.
  • Acepta el aviso: no podrás volver a ver el secret; solo cambiarlo. Si lo cambias en GitHub, cambia también el que usas en AWS.
  • La validación usa el algoritmo SHA-256 y un signature prefix tipo "sha256="; lo que sigue al igual es el valor a comparar.

¿Qué secret y permisos necesitas en AWS Secrets Manager?

El secret se guarda como mapa clave-valor en AWS Secrets Manager y se accede con una política mínima de lectura desde el rol de ejecución.

  • Añade un nuevo secret en Secrets Manager como API key. Clave: "secret". Valor: el secret configurado en GitHub.
  • Asigna un nombre claro, por ejemplo "GitHub secret". La clave de encriptación es la gestionada por Secrets Manager.
  • La rotación de secrets es opcional; es una buena práctica para aplicaciones grandes, pero no se activó en este caso.
  • Identifica datos clave: encryption key, secret name y secret ARN.
  • Crea en Terraform una política IAM que permita obtener el secret. Nómbrala con intención, por ejemplo can get GitHub webhook secret.
  • En la política, define el resource con el secret ARN exacto.
  • Exporta el ARN vía output y pásalo como variable al módulo que ata la política al rol.
  • Ata la política al rol del servicio (por ejemplo, Repo Collector) usando la variable can get GitHub secret Arn.
  • En la Lambda handleGitHubWebhook, agrega la variable de entorno GITHUB_SECRET con el nombre del secret, no el ARN.

¿Cómo validar la firma HMAC SHA-256 en Lambda con Go?

La lógica en Go calcula la firma del payload con el secret y la compara, de forma segura, contra el header de GitHub.

¿Qué funciones de ayuda implementas en Go?

  • CalculateSignature: recibe el secret y el payload; usa la librería nativa de Go para HMAC con SHA-256 y devuelve la firma.
  • ValidateGitHubRequest: recibe el contexto y la request; retorna un booleano y un error. Pasos clave:
  • Leer el header de GitHub para la firma 256. Si no viene, se deniega.
  • Definir signaturePrefix = "sha256=" y retirar el prefijo del valor del header.
  • Obtener el secret desde Secrets Manager con el cliente; parsear a JSON como mapa y tomar la clave "secret".
  • Calcular la firma del body con CalculateSignature.
  • Comparar de forma segura con hmac.Equal y operar con bytes, no strings.
  • En el handler, si hay error, retornarlo; si no es válido, crear errors.New("Invalid GitHub Webhook"). Evita redeclaraciones de variables retirando := cuando ya exista.

Código orientativo en Go:

const signaturePrefix = "sha256="

func CalculateSignature(secret, payload []byte) []byte {
    // usar HMAC con SHA-256 y devolver la firma.
    return nil
}

func ValidateGitHubRequest(ctx context.Context, req Request) (bool, error) {
    // 1) leer header de la firma 256.
    // 2) quitar signaturePrefix.
    // 3) traer secret desde Secrets Manager.
    // 4) calcular firma y comparar con hmac.Equal usando bytes.
    return true, nil
}

¿Cómo compilar, desplegar y verificar el flujo?

  • En handleGitHubWebhook, ejecuta make publish para compilar y subir a S3; Terraform no compila el código.
  • En infraestructura, corre terraform plan: verás 2 ítems para añadir (política y attach) y 3 recursos para cambiar (tus Lambdas).
  • Aplica con terraform apply y confirma con "yes". Espera la finalización del despliegue.
  • Realiza un git commit con mensaje "add data integrity validation" y haz push.
  • En GitHub, revisa Recent deliveries: marcador verde y respuesta "ok".
  • En tu base de datos, ejecuta select all from commits: verás el nuevo commit "Add data integrity validation" insertado correctamente.

¿Te gustaría profundizar en más controles de seguridad o ampliar métricas con datos de GitHub? Comparte tus dudas y cuéntame qué extenderías a continuación.