Compartir vía


Protección del punto de conexión de webhook

La protección de la entrega de mensajes de un extremo a otro es fundamental para garantizar la confidencialidad, la integridad y la confiabilidad de la información confidencial transmitida entre sistemas. Su capacidad y disposición a confiar en la información recibida de un sistema remoto se basa en el remitente que proporciona su identidad. La automatización de llamadas tiene dos maneras de comunicar eventos que se pueden proteger; el evento IncomingCall compartido enviado por Azure Event Grid y todos los demás eventos de llamada intermedia enviados por la plataforma automatización de llamadas a través de webhook.

Evento de llamada entrante

Azure Communication Services se basa en suscripciones de Azure Event Grid para entregar el evento IncomingCall. Puede consultar el equipo de Azure Event Grid para obtener su documentación sobre cómo proteger una suscripción de webhook.

Eventos de webhook de Call Automation

Los eventos de Automatización de llamadas se envían al URI de devolución de llamada de webhook especificado al responder a una llamada o a colocar una nueva llamada saliente. El URI de devolución de llamada debe ser un punto de conexión público con un certificado HTTPS, un nombre DNS y una dirección IP válidos con los puertos de firewall correctos abiertos para permitir que Call Automation llegue a él. Este servidor web público anónimo podría crear un riesgo de seguridad si no lleva a cabo los pasos necesarios para protegerlo del acceso no autorizado.

Una manera común de mejorar esta seguridad es implementar un mecanismo de CLAVE de API. El servidor web puede generar la clave en tiempo de ejecución y proporcionarla en el URI de devolución de llamada como parámetro de consulta cuando responda o cree una llamada. El servidor web puede comprobar la clave en la devolución de llamada de webhook desde Automatización de llamadas antes de permitir el acceso. Algunos clientes requieren más medidas de seguridad. En estos casos, un dispositivo de red perimetral puede comprobar el webhook de entrada, independiente del propio servidor web o de la propia aplicación. Es posible que el mecanismo de clave de API por sí solo no sea suficiente.

Mejora de la seguridad de devolución de llamada del webhook de Automatización de llamadas

Cada devolución de llamada de webhook de llamada media enviada por La automatización de llamadas usa un token web JSON (JWT) firmado en el encabezado De autenticación de la solicitud HTTPS entrante. Puede usar técnicas de validación estándar de JWT de JWT de open ID Conectar (OIDC) para garantizar la integridad del token como se indica a continuación. La duración del JWT es de cinco (5) minutos y se crea un nuevo token para cada evento enviado al URI de devolución de llamada.

  1. Obtenga la dirección URL de configuración de Open ID: https://acscallautomation.communication.azure.com/calling/.well-known/acsopenidconfiguration
  2. Instale el paquete NuGet Microsoft.AspNetCore.Authentication.JwtBearer.
  3. Configure la aplicación para validar el JWT mediante el paquete NuGet y la configuración del recurso de Azure Communication Services. Necesita los audience valores tal como están presentes en la carga de JWT.
  4. Valide el emisor, la audiencia y el token JWT.
    • La audiencia es el identificador de recurso de Azure Communication Services que usó para configurar el cliente de Automatización de llamadas. Consulte aquí sobre cómo obtenerlo.
    • El punto de conexión del conjunto de claves web JSON (JWKS) de la configuración de OpenId contiene las claves usadas para validar el token JWT. Cuando la firma es válida y el token no ha expirado (en un plazo de 5 minutos de generación), el cliente puede usar el token para la autorización.

En este código de ejemplo se muestra cómo usar Microsoft.IdentityModel.Protocols.OpenIdConnect para validar la carga del webhook

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Protocols;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// Add Azure Communication Services CallAutomation OpenID configuration
var configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(
            builder.Configuration["OpenIdConfigUrl"],
            new OpenIdConnectConfigurationRetriever());
var configuration = configurationManager.GetConfigurationAsync().Result;

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.Configuration = configuration;
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidAudience = builder.Configuration["AllowedAudience"]
        };
    });

builder.Services.AddAuthorization();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.MapPost("/api/callback", (CloudEvent[] events) =>
{
    // Your implemenation on the callback event
    return Results.Ok();
})
.RequireAuthorization()
.WithOpenApi();

app.UseAuthentication();
app.UseAuthorization();

app.Run();

Mejora de la seguridad de devolución de llamada del webhook de Automatización de llamadas

Cada devolución de llamada de webhook de llamada media enviada por La automatización de llamadas usa un token web JSON (JWT) firmado en el encabezado De autenticación de la solicitud HTTPS entrante. Puede usar técnicas de validación estándar de JWT de JWT de open ID Conectar (OIDC) para garantizar la integridad del token como se indica a continuación. La duración del JWT es de cinco (5) minutos y se crea un nuevo token para cada evento enviado al URI de devolución de llamada.

  1. Obtenga la dirección URL de configuración de Open ID: https://acscallautomation.communication.azure.com/calling/.well-known/acsopenidconfiguration
  2. En el ejemplo siguiente se usa spring framework, creado con spring initializr con Maven como herramienta de compilación de proyectos.
  3. Agregue las siguientes dependencias en pom.xml:
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-security</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.security</groupId>
   <artifactId>spring-security-oauth2-jose</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.security</groupId>
   <artifactId>spring-security-oauth2-resource-server</artifactId>
  </dependency>
  1. Configure la aplicación para validar el JWT y la configuración del recurso de Azure Communication Services. Necesita los audience valores tal como están presentes en la carga de JWT.
  2. Valide el emisor, la audiencia y el token JWT.
    • La audiencia es el identificador de recurso de Azure Communication Services que usó para configurar el cliente de Automatización de llamadas. Consulte aquí sobre cómo obtenerlo.
    • El punto de conexión del conjunto de claves web JSON (JWKS) de la configuración de OpenId contiene las claves usadas para validar el token JWT. Cuando la firma es válida y el token no ha expirado (en un plazo de 5 minutos de generación), el cliente puede usar el token para la autorización.

Este código de ejemplo muestra cómo configurar el cliente OIDC para validar la carga de webhook mediante JWT

package callautomation.example.security;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
import org.springframework.security.oauth2.jwt.*;

@EnableWebSecurity
public class TokenValidationConfiguration {
    @Value("ACS resource ID")
    private String audience;

    @Value("https://acscallautomation.communication.azure.com")
    private String issuer;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .mvcMatchers("/api/callbacks").permitAll()
                .anyRequest()
                .and()
                .oauth2ResourceServer()
                .jwt()
                .decoder(jwtDecoder());

        return http.build();
    }

    class AudienceValidator implements OAuth2TokenValidator<Jwt> {
        private String audience;

        OAuth2Error error = new OAuth2Error("invalid_token", "The required audience is missing", null);

        public AudienceValidator(String audience) {
            this.audience = audience;
        }

        @Override
        public OAuth2TokenValidatorResult validate(Jwt token) {
            if (token.getAudience().contains(audience)) {
                return OAuth2TokenValidatorResult.success();
            } else {
                return OAuth2TokenValidatorResult.failure(error);
            }
        }
    }

    JwtDecoder jwtDecoder() {
        OAuth2TokenValidator<Jwt> withAudience = new AudienceValidator(audience);
        OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuer);
        OAuth2TokenValidator<Jwt> validator = new DelegatingOAuth2TokenValidator<>(withAudience, withIssuer);

        NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder) JwtDecoders.fromOidcIssuerLocation(issuer);
        jwtDecoder.setJwtValidator(validator);

        return jwtDecoder;
    }
}

Mejora de la seguridad de devolución de llamada del webhook de Automatización de llamadas

Cada devolución de llamada de webhook de llamada media enviada por La automatización de llamadas usa un token web JSON (JWT) firmado en el encabezado De autenticación de la solicitud HTTPS entrante. Puede usar técnicas de validación estándar de JWT de JWT de open ID Conectar (OIDC) para garantizar la integridad del token como se indica a continuación. La duración del JWT es de cinco (5) minutos y se crea un nuevo token para cada evento enviado al URI de devolución de llamada.

  1. Obtenga la dirección URL de configuración de Open ID: https://acscallautomation.communication.azure.com/calling/.well-known/acsopenidconfiguration
  2. Instale los siguientes paquetes:
npm install express jwks-rsa jsonwebtoken
  1. Configure la aplicación para validar el JWT y la configuración del recurso de Azure Communication Services. Necesita los audience valores tal como están presentes en la carga de JWT.
  2. Valide el emisor, la audiencia y el token JWT.
    • La audiencia es el identificador de recurso de Azure Communication Services que usó para configurar el cliente de Automatización de llamadas. Consulte aquí sobre cómo obtenerlo.
    • El punto de conexión del conjunto de claves web JSON (JWKS) de la configuración de OpenId contiene las claves usadas para validar el token JWT. Cuando la firma es válida y el token no ha expirado (en un plazo de 5 minutos de generación), el cliente puede usar el token para la autorización.

Este código de ejemplo muestra cómo configurar el cliente OIDC para validar la carga de webhook mediante JWT

import express from "express";
import { JwksClient } from "jwks-rsa";
import { verify } from "jsonwebtoken";

const app = express();
const port = 3000;
const audience = "ACS resource ID";
const issuer = "https://acscallautomation.communication.azure.com";

app.use(express.json());

app.post("/api/callback", (req, res) => {
    const token = req?.headers?.authorization?.split(" ")[1] || "";

    if (!token) {
        res.sendStatus(401);

        return;
    }

    try {
        verify(
            token,
            (header, callback) => {
                const client = new JwksClient({
                    jwksUri: "https://acscallautomation.communication.azure.com/calling/keys",
                });

                client.getSigningKey(header.kid, (err, key) => {
                    const signingKey = key?.publicKey || key?.rsaPublicKey;

                    callback(err, signingKey);
                });
            },
            {
                audience,
                issuer,
                algorithms: ["RS256"],
            });
        // Your implementation on the callback event
        res.sendStatus(200);
    } catch (error) {
        res.sendStatus(401);
    }
});

app.listen(port, () => {
    console.log(`Server running on port ${port}`);
});

Mejora de la seguridad de devolución de llamada del webhook de Automatización de llamadas

Cada devolución de llamada de webhook de llamada media enviada por La automatización de llamadas usa un token web JSON (JWT) firmado en el encabezado De autenticación de la solicitud HTTPS entrante. Puede usar técnicas de validación estándar de JWT de JWT de open ID Conectar (OIDC) para garantizar la integridad del token como se indica a continuación. La duración del JWT es de cinco (5) minutos y se crea un nuevo token para cada evento enviado al URI de devolución de llamada.

  1. Obtenga la dirección URL de configuración de Open ID: https://acscallautomation.communication.azure.com/calling/.well-known/acsopenidconfiguration
  2. Instale los siguientes paquetes:
pip install flask pyjwt
  1. Configure la aplicación para validar el JWT y la configuración del recurso de Azure Communication Services. Necesita los audience valores tal como están presentes en la carga de JWT.
  2. Valide el emisor, la audiencia y el token JWT.
    • La audiencia es el identificador de recurso de Azure Communication Services que usó para configurar el cliente de Automatización de llamadas. Consulte aquí sobre cómo obtenerlo.
    • El punto de conexión del conjunto de claves web JSON (JWKS) de la configuración de OpenId contiene las claves usadas para validar el token JWT. Cuando la firma es válida y el token no ha expirado (en un plazo de 5 minutos de generación), el cliente puede usar el token para la autorización.

Este código de ejemplo muestra cómo configurar el cliente OIDC para validar la carga de webhook mediante JWT

from flask import Flask, jsonify, abort, request
import jwt

app = Flask(__name__)


@app.route("/api/callback", methods=["POST"])
def handle_callback_event():
    token = request.headers.get("authorization").split()[1]

    if not token:
        abort(401)

    try:
        jwks_client = jwt.PyJWKClient(
            "https://acscallautomation.communication.azure.com/calling/keys"
        )
        jwt.decode(
            token,
            jwks_client.get_signing_key_from_jwt(token).key,
            algorithms=["RS256"],
            issuer="https://acscallautomation.communication.azure.com",
            audience="ACS resource ID",
        )
        # Your implementation on the callback event
        return jsonify(success=True)
    except jwt.InvalidTokenError:
        print("Token is invalid")
        abort(401)
    except Exception as e:
        print("uncaught exception" + e)
        abort(500)


if __name__ == "__main__":
    app.run()

Pasos siguientes