Condividi tramite


Come proteggere l'endpoint del webhook

La protezione del recapito dei messaggi dalla fine alla fine è fondamentale per garantire la riservatezza, l'integrità e l'attendibilità delle informazioni riservate trasmesse tra i sistemi. La capacità e la disponibilità a considerare attendibili le informazioni ricevute da un sistema remoto si basano sul mittente che fornisce la propria identità. L'automazione delle chiamate offre due modi per comunicare gli eventi che possono essere protetti; l'evento IncomingCall condiviso inviato da Griglia di eventi di Azure e tutti gli altri eventi di chiamata mid-call inviati dalla piattaforma di automazione delle chiamate tramite webhook.

Evento di chiamata in arrivo

Servizi di comunicazione di Azure si basa su sottoscrizioni Griglia di eventi di Azure per recapitare l'evento IncomingCall. È possibile fare riferimento al team di Griglia di eventi di Azure per la documentazione su come proteggere una sottoscrizione webhook.

Chiamare eventi webhook di Automazione

Gli eventi di Automazione chiamata vengono inviati all'URI di callback del webhook specificato quando si risponde a una chiamata o si effettua una nuova chiamata in uscita. L'URI di callback deve essere un endpoint pubblico con un certificato HTTPS valido, un nome DNS e un indirizzo IP con le porte del firewall corrette aperte per consentire all'automazione delle chiamate di raggiungerlo. Questo server Web pubblico anonimo potrebbe creare un rischio per la sicurezza se non si esesse la procedura necessaria per proteggerlo dall'accesso non autorizzato.

Un modo comune per migliorare questa sicurezza consiste nell'implementare un meccanismo API KEY. Il server Web può generare la chiave in fase di esecuzione e specificarla nell'URI di callback come parametro di query quando si risponde o si crea una chiamata. Il server Web può verificare la chiave nel callback del webhook da Automazione chiamate prima di consentire l'accesso. Alcuni clienti richiedono più misure di sicurezza. In questi casi, un dispositivo di rete perimetrale può verificare il webhook in ingresso, separato dal server Web o dall'applicazione stessa. Il meccanismo di chiave API da solo potrebbe non essere sufficiente.

Miglioramento della sicurezza del callback del webhook di Automazione delle chiamate

Ogni callback webhook mid-call inviato da Automazione chiamate usa un token JSON Web (JWT) firmato nell'intestazione Di autenticazione della richiesta HTTPS in ingresso. È possibile usare tecniche di convalida JWT (Open ID Connessione) OIDC standard per garantire l'integrità del token come indicato di seguito. La durata del token JWT è di cinque (5) minuti e viene creato un nuovo token per ogni evento inviato all'URI di callback.

  1. Ottenere l'URL di configurazione open ID: https://acscallautomation.communication.azure.com/calling/.well-known/acsopenidconfiguration
  2. Installare il pacchetto NuGet Microsoft.AspNetCore.Authentication.JwtBearer.
  3. Configurare l'applicazione per convalidare il token JWT usando il pacchetto NuGet e la configurazione della risorsa Servizi di comunicazione di Azure. Sono necessari i audience valori così come sono presenti nel payload JWT.
  4. Convalidare l'autorità di certificazione, il gruppo di destinatari e il token JWT.
    • Il gruppo di destinatari è l'ID risorsa Servizi di comunicazione di Azure usato per configurare il client di automazione delle chiamate. Fare riferimento qui per informazioni su come ottenerlo.
    • L'endpoint JWKS (JSON Web Key Set) nella configurazione OpenId contiene le chiavi usate per convalidare il token JWT. Quando la firma è valida e il token non è scaduto (entro 5 minuti dalla generazione), il client può usare il token per l'autorizzazione.

Questo codice di esempio illustra come usare Microsoft.IdentityModel.Protocols.OpenIdConnect per convalidare il payload 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();

Miglioramento della sicurezza del callback del webhook di Automazione delle chiamate

Ogni callback webhook mid-call inviato da Automazione chiamate usa un token JSON Web (JWT) firmato nell'intestazione Di autenticazione della richiesta HTTPS in ingresso. È possibile usare tecniche di convalida JWT (Open ID Connessione) OIDC standard per garantire l'integrità del token come indicato di seguito. La durata del token JWT è di cinque (5) minuti e viene creato un nuovo token per ogni evento inviato all'URI di callback.

  1. Ottenere l'URL di configurazione open ID: https://acscallautomation.communication.azure.com/calling/.well-known/acsopenidconfiguration
  2. L'esempio seguente usa Spring Framework, creato usando spring initializr con Maven come strumento di compilazione del progetto.
  3. Aggiungere le dipendenze seguenti in 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. Configurare l'applicazione per convalidare il token JWT e la configurazione della risorsa Servizi di comunicazione di Azure. Sono necessari i audience valori così come sono presenti nel payload JWT.
  2. Convalidare l'autorità di certificazione, il gruppo di destinatari e il token JWT.
    • Il gruppo di destinatari è l'ID risorsa Servizi di comunicazione di Azure usato per configurare il client di automazione delle chiamate. Fare riferimento qui per informazioni su come ottenerlo.
    • L'endpoint JWKS (JSON Web Key Set) nella configurazione OpenId contiene le chiavi usate per convalidare il token JWT. Quando la firma è valida e il token non è scaduto (entro 5 minuti dalla generazione), il client può usare il token per l'autorizzazione.

Questo codice di esempio illustra come configurare il client OIDC per convalidare il payload del webhook usando 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;
    }
}

Miglioramento della sicurezza del callback del webhook di Automazione delle chiamate

Ogni callback webhook mid-call inviato da Automazione chiamate usa un token JSON Web (JWT) firmato nell'intestazione Di autenticazione della richiesta HTTPS in ingresso. È possibile usare tecniche di convalida JWT (Open ID Connessione) OIDC standard per garantire l'integrità del token come indicato di seguito. La durata del token JWT è di cinque (5) minuti e viene creato un nuovo token per ogni evento inviato all'URI di callback.

  1. Ottenere l'URL di configurazione open ID: https://acscallautomation.communication.azure.com/calling/.well-known/acsopenidconfiguration
  2. Installare i pacchetti seguenti:
npm install express jwks-rsa jsonwebtoken
  1. Configurare l'applicazione per convalidare il token JWT e la configurazione della risorsa Servizi di comunicazione di Azure. Sono necessari i audience valori così come sono presenti nel payload JWT.
  2. Convalidare l'autorità di certificazione, il gruppo di destinatari e il token JWT.
    • Il gruppo di destinatari è l'ID risorsa Servizi di comunicazione di Azure usato per configurare il client di automazione delle chiamate. Fare riferimento qui per informazioni su come ottenerlo.
    • L'endpoint JWKS (JSON Web Key Set) nella configurazione OpenId contiene le chiavi usate per convalidare il token JWT. Quando la firma è valida e il token non è scaduto (entro 5 minuti dalla generazione), il client può usare il token per l'autorizzazione.

Questo codice di esempio illustra come configurare il client OIDC per convalidare il payload del webhook usando 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}`);
});

Miglioramento della sicurezza del callback del webhook di Automazione delle chiamate

Ogni callback webhook mid-call inviato da Automazione chiamate usa un token JSON Web (JWT) firmato nell'intestazione Di autenticazione della richiesta HTTPS in ingresso. È possibile usare tecniche di convalida JWT (Open ID Connessione) OIDC standard per garantire l'integrità del token come indicato di seguito. La durata del token JWT è di cinque (5) minuti e viene creato un nuovo token per ogni evento inviato all'URI di callback.

  1. Ottenere l'URL di configurazione open ID: https://acscallautomation.communication.azure.com/calling/.well-known/acsopenidconfiguration
  2. Installare i pacchetti seguenti:
pip install flask pyjwt
  1. Configurare l'applicazione per convalidare il token JWT e la configurazione della risorsa Servizi di comunicazione di Azure. Sono necessari i audience valori così come sono presenti nel payload JWT.
  2. Convalidare l'autorità di certificazione, il gruppo di destinatari e il token JWT.
    • Il gruppo di destinatari è l'ID risorsa Servizi di comunicazione di Azure usato per configurare il client di automazione delle chiamate. Fare riferimento qui per informazioni su come ottenerlo.
    • L'endpoint JWKS (JSON Web Key Set) nella configurazione OpenId contiene le chiavi usate per convalidare il token JWT. Quando la firma è valida e il token non è scaduto (entro 5 minuti dalla generazione), il client può usare il token per l'autorizzazione.

Questo codice di esempio illustra come configurare il client OIDC per convalidare il payload del webhook usando 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()

Passaggi successivi