Ejercicio: Protección de las cargas de webhook con un secreto

Completado

En este ejercicio, protegerá la carga de webhook con un secreto y aprenderá a validar que las cargas de GitHub son realmente de GitHub mediante una función de Azure Functions.

Obtención de la clave para la función de Azure

  1. En Azure Portal, vuelva a la aplicación de funciones que creó en el primer ejercicio del módulo.

  2. En el panel de menús de la izquierda, en Funciones, seleccione Funciones. Aparece el panel Funciones de la aplicación de funciones.

  3. Seleccione la instancia de HttpTrigger1 que ha creado. Aparecerá el panel HtttpTrigger1 de la función.

  4. En el panel de menús izquierdo, en Desarrollador, seleccione Código y prueba. Aparece el panel Código y prueba de la función.

  5. En el archivo de JavaScript index.js de la función, agregue una referencia a la biblioteca crypto-js al inicio del archivo, encima de la instrucción module.exports.

    const Crypto = require('crypto');
    
  6. En la barra de menús superior, seleccione Guardar. En la parte inferior del panel aparece el panel Registros.

  7. En el panel de menús de la izquierda, en Desarrollador, seleccione Claves de función. Aparece el panel Claves de función correspondiente a la función.

  8. En la columna Valor, seleccione el vínculo Mostrar valor.

  9. Seleccione el icono Copiar en el Portapapeles y guarde esta clave para usarla en el próximo paso.

  10. En el panel de menús izquierdo, en Desarrollador, seleccione Código y prueba. Aparece el panel Código y prueba de la función.

  11. En el bloque de código, después de la instrucción context.log, agregue el código siguiente. Reemplace <default key> por la clave predeterminada que acaba de copiar en el Portapapeles:

    const hmac = Crypto.createHmac("sha1", "<default key>");
    const signature = hmac.update(JSON.stringify(req.body)).digest('hex');
    

    Este código calcula el hash de la clave utilizando el mismo mecanismo que GitHub.

  12. Agregue otro const que anteceda a sha1= al principio de la clave, para que coincida con el formato de x-hub-signature en el encabezado de solicitud. Agregue el siguiente código a la función.

    const shaSignature = `sha1=${signature}`;
    
  13. Agregue el código siguiente para recuperar la firma de GitHub del encabezado de solicitud:

    const gitHubSignature = req.headers['x-hub-signature'];
    
  14. Compare las dos cadenas. Si coinciden, procese la solicitud del modo siguiente:

    if (!shaSignature.localeCompare(gitHubSignature)) {
        // Existing code
        if (req.body.pages[0].title) {
            ...
        }
        else {
            ...
        }
    }
    
  15. Si las cadenas no coinciden, se devuelve una respuesta HTTP 401 (no autorizado), con un mensaje que indica al emisor que las firmas no coinciden.

    if (!shaSignature.localeCompare(gitHubSignature))
    {
        ...
    }
    else {
        context.res = {
            status: 401,
            body: "Signatures don't match"
        };
    }
    
    

    Este es el aspecto que debería tener la función completada:

    const Crypto = require('crypto');
    
    module.exports = async function (context, req) {
        context.log('JavaScript HTTP trigger function processed a request.');
    
        const hmac = Crypto.createHmac("sha1", "<default key>");
        const signature = hmac.update(JSON.stringify(req.body)).digest('hex');
        const shaSignature =  `sha1=${signature}`;
        const gitHubSignature = req.headers['x-hub-signature'];
    
        if (!shaSignature.localeCompare(gitHubSignature)) {
            if (req.body.pages[0].title) {
                context.res = {
                    body: "Page is " + req.body.pages[0].title + ", Action is " + req.body.pages[0].action + ", Event Type is " + req.headers['x-github-event']
                };
            }
            else {
                context.res = {
                    status: 400,
                    body: ("Invalid payload for Wiki event")
                }
            }
        }
        else {
            context.res = {
                status: 401,
                body: "Signatures don't match"
            };
        }
    };
    
  16. En la barra de menús superior, seleccione Guardar. Se abre el panel Registros con una instrucción Conectado.

Actualización del secreto del webhook

  1. Cambie a la cuenta de GitHub en el portal de GitHub.

  2. Seleccione el repositorio.

  3. En la barra de menús superior, seleccione Configuración. Aparecerá el panel Configuración.

  4. En la barra lateral, seleccione Webhooks. Aparece el panel Webhooks.

  5. Seleccione Editar junto al webhook.

  6. En el cuadro de texto Secreto, escriba la clave predeterminada de la función que ha guardado antes en este ejercicio.

  7. Desplácese hasta la parte inferior de la página y seleccione Actualizar webhook. Se abre el panel Webhooks/Manage webhooks (Webhooks/Administrar webhooks).

Prueba del webhook y la función de Azure

  1. Seleccione la pestaña Recent Deliveries (Entregas recientes).

  2. Seleccione la entrada de entrega más reciente mediante la selección del botón de puntos suspensivos (...).

  3. Seleccione Volver a entregar. En el cuadro de diálogo Redeliver payload? (¿Volver a entregar la carga) que se abre, seleccione Yes, redeliver this payload (Sí, volver a entregar esta carga).

    Esta acción simula que edita de nuevo la página de wiki.

  4. Seleccione la entrada de entrega más reciente mediante la selección del botón de puntos suspensivos (...).

  5. En la sección Encabezados, verá x-hub-signature. También verá que el código de respuesta es 200, lo que indica que la solicitud se procesó correctamente.

    Request URL: https://testwh123456.azurewebsites.net/api/HttpTrigger1?code=aUjXIpqdJ0ZHPQuB0SzFegxGJu0nAXmsQBnmkCpJ6RYxleRaoxJ8cQ%3D%3D
    Request method: POST
    content-type: application/json
    Expect:
    User-Agent: GitHub-Hookshot/16496cb
    X-GitHub-Delivery: ce122460-6aae-11e9-99d4-de6a298a424a
    X-GitHub-Event: gollum
    X-Hub-Signature: sha1=<hash of default key>
    

Prueba de una firma no válida

  1. En el portal de GitHub, en la página webhooks, seleccione la pestaña Settings (Configuración).

  2. En el cuadro de prueba Secret (Secreto), seleccione Change Secret (Cambiar secreto).

  3. Escriba una cadena aleatoria, desplácese hacia abajo y luego seleccione Actualizar webhook.

    La clave utilizada por el webhook ya no debe coincidir con lo esperado por la función de Azure.

  4. Seleccione la pestaña Recent Deliveries (Entregas recientes).

  5. Seleccione la entrada de entrega más reciente mediante la selección del botón de puntos suspensivos (...).

  6. Seleccione Redeliver (Volver a entregar) y, en el cuadro de diálogo Redeliver payload (Volver a entregar la carga) que se abre, seleccione Yes, redeliver this payload (Sí, volver a entregar esta carga).

  7. Esta vez, verá que el código de respuesta es 401, lo que indica que la solicitud no se ha autorizado.

  8. Seleccione la entrada de entrega más reciente (redelivery) por medio del botón de puntos suspensivos (...).

  9. Seleccione la pestaña Respuesta y, en la sección Cuerpo, compruebe que se muestra el mensaje "Las firmas no coinciden".