Udostępnij za pośrednictwem


Jak zabezpieczyć punkt końcowy elementu webhook

Zabezpieczenie dostarczania wiadomości od końca ma kluczowe znaczenie dla zapewnienia poufności, integralności i wiarygodności poufnych informacji przesyłanych między systemami. Twoja zdolność i gotowość do zaufania informacji otrzymanych z systemu zdalnego zależy od nadawcy dostarczającego swoją tożsamość. Usługa Call Automation ma dwa sposoby komunikowania się zdarzeń, które można zabezpieczyć; udostępnione zdarzenie IncomingCall wysłane przez usługę Azure Event Grid i wszystkie inne zdarzenia w połowie wywołania wysyłane przez platformę Call Automation za pośrednictwem elementu webhook.

Zdarzenie połączenia przychodzącego

Usługi Azure Communication Services korzystają z subskrypcji usługi Azure Event Grid w celu dostarczenia zdarzenia IncomingCall. Aby uzyskać dokumentację dotyczącą zabezpieczania subskrypcji elementu webhook, możesz zapoznać się z zespołem usługi Azure Event Grid.

Wywoływanie zdarzeń elementu webhook usługi Automation

Zdarzenia automatyzacji wywołań są wysyłane do identyfikatora URI wywołania zwrotnego elementu webhook określonego podczas odbierania połączenia lub umieszczenia nowego wywołania wychodzącego. Identyfikator URI wywołania zwrotnego musi być publicznym punktem końcowym z prawidłowym certyfikatem HTTPS, nazwą DNS i adresem IP z otwartymi odpowiednimi portami zapory, aby umożliwić usłudze Call Automation dotarcie do niego. Ten anonimowy publiczny serwer sieci Web może stanowić zagrożenie bezpieczeństwa, jeśli nie podejmiesz niezbędnych kroków w celu zabezpieczenia go przed nieautoryzowanym dostępem.

Typowym sposobem poprawy bezpieczeństwa jest zaimplementowanie mechanizmu KEY interfejsu API. Serwer internetowy może wygenerować klucz w czasie wykonywania i podać go w identyfikatorze URI wywołania zwrotnego jako parametr zapytania podczas odpowiadania lub tworzenia wywołania. Serwer internetowy może zweryfikować klucz w wywołaniu zwrotnym elementu webhook z poziomu automatyzacji wywołań przed zezwoleniem na dostęp. Niektórzy klienci wymagają większej liczby środków bezpieczeństwa. W takich przypadkach urządzenie sieciowe obwodowe może zweryfikować przychodzący element webhook niezależnie od serwera internetowego lub samej aplikacji. Sam mechanizm klucza interfejsu API może nie być wystarczający.

Ulepszanie zabezpieczeń wywołania zwrotnego elementu webhook usługi Call Automation

Każde wywołanie zwrotne elementu webhook w połowie wywołania wysyłane przez usługę Call Automation używa podpisanego tokenu internetowego JSON (JWT) w nagłówku Uwierzytelniania przychodzącego żądania HTTPS. Możesz użyć standardowych technik weryfikacji JWT JWT open ID Połączenie (OIDC), aby zapewnić integralność tokenu w następujący sposób. Okres istnienia JWT wynosi pięć (5) minut, a dla każdego zdarzenia wysyłanego do identyfikatora URI wywołania zwrotnego jest tworzony nowy token.

  1. Uzyskaj adres URL konfiguracji open ID: https://acscallautomation.communication.azure.com/calling/.well-known/acsopenidconfiguration
  2. Zainstaluj pakiet NuGet Microsoft.AspNetCore.Authentication.JwtBearer.
  3. Skonfiguruj aplikację, aby zweryfikować JWT przy użyciu pakietu NuGet i konfiguracji zasobu usług Azure Communication Services. Potrzebne audience są wartości obecne w ładunku JWT.
  4. Zweryfikuj wystawcę, odbiorców i token JWT.
    • Odbiorcy to identyfikator zasobu usług Azure Communication Services użyty do skonfigurowania klienta usługi Call Automation. Zobacz tutaj , jak to zrobić.
    • Punkt końcowy zestawu kluczy sieci Web JSON (JWKS) w konfiguracji OpenId zawiera klucze używane do sprawdzania poprawności tokenu JWT. Gdy podpis jest prawidłowy i token nie wygasł (w ciągu 5 minut od wygenerowania), klient może użyć tokenu do autoryzacji.

Ten przykładowy kod demonstruje sposób sprawdzania Microsoft.IdentityModel.Protocols.OpenIdConnect poprawności ładunku elementu 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();

Ulepszanie zabezpieczeń wywołania zwrotnego elementu webhook usługi Call Automation

Każde wywołanie zwrotne elementu webhook w połowie wywołania wysyłane przez usługę Call Automation używa podpisanego tokenu internetowego JSON (JWT) w nagłówku Uwierzytelniania przychodzącego żądania HTTPS. Możesz użyć standardowych technik weryfikacji JWT JWT open ID Połączenie (OIDC), aby zapewnić integralność tokenu w następujący sposób. Okres istnienia JWT wynosi pięć (5) minut, a dla każdego zdarzenia wysyłanego do identyfikatora URI wywołania zwrotnego jest tworzony nowy token.

  1. Uzyskaj adres URL konfiguracji open ID: https://acscallautomation.communication.azure.com/calling/.well-known/acsopenidconfiguration
  2. W poniższym przykładzie użyto platformy Spring utworzonej przy użyciu narzędzia spring initializr z narzędziem maven do kompilowania projektu.
  3. Dodaj następujące zależności w pliku 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. Skonfiguruj aplikację, aby zweryfikować JWT i konfigurację zasobu usług Azure Communication Services. Potrzebne audience są wartości obecne w ładunku JWT.
  2. Zweryfikuj wystawcę, odbiorców i token JWT.
    • Odbiorcy to identyfikator zasobu usług Azure Communication Services użyty do skonfigurowania klienta usługi Call Automation. Zobacz tutaj , jak to zrobić.
    • Punkt końcowy zestawu kluczy sieci Web JSON (JWKS) w konfiguracji OpenId zawiera klucze używane do sprawdzania poprawności tokenu JWT. Gdy podpis jest prawidłowy i token nie wygasł (w ciągu 5 minut od wygenerowania), klient może użyć tokenu do autoryzacji.

Ten przykładowy kod pokazuje, jak skonfigurować klienta OIDC w celu zweryfikowania ładunku elementu webhook przy użyciu 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;
    }
}

Ulepszanie zabezpieczeń wywołania zwrotnego elementu webhook usługi Call Automation

Każde wywołanie zwrotne elementu webhook w połowie wywołania wysyłane przez usługę Call Automation używa podpisanego tokenu internetowego JSON (JWT) w nagłówku Uwierzytelniania przychodzącego żądania HTTPS. Możesz użyć standardowych technik weryfikacji JWT JWT open ID Połączenie (OIDC), aby zapewnić integralność tokenu w następujący sposób. Okres istnienia JWT wynosi pięć (5) minut, a dla każdego zdarzenia wysyłanego do identyfikatora URI wywołania zwrotnego jest tworzony nowy token.

  1. Uzyskaj adres URL konfiguracji open ID: https://acscallautomation.communication.azure.com/calling/.well-known/acsopenidconfiguration
  2. Zainstaluj następujące pakiety:
npm install express jwks-rsa jsonwebtoken
  1. Skonfiguruj aplikację, aby zweryfikować JWT i konfigurację zasobu usług Azure Communication Services. Potrzebne audience są wartości obecne w ładunku JWT.
  2. Zweryfikuj wystawcę, odbiorców i token JWT.
    • Odbiorcy to identyfikator zasobu usług Azure Communication Services użyty do skonfigurowania klienta usługi Call Automation. Zobacz tutaj , jak to zrobić.
    • Punkt końcowy zestawu kluczy sieci Web JSON (JWKS) w konfiguracji OpenId zawiera klucze używane do sprawdzania poprawności tokenu JWT. Gdy podpis jest prawidłowy i token nie wygasł (w ciągu 5 minut od wygenerowania), klient może użyć tokenu do autoryzacji.

Ten przykładowy kod pokazuje, jak skonfigurować klienta OIDC w celu zweryfikowania ładunku elementu webhook przy użyciu 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}`);
});

Ulepszanie zabezpieczeń wywołania zwrotnego elementu webhook usługi Call Automation

Każde wywołanie zwrotne elementu webhook w połowie wywołania wysyłane przez usługę Call Automation używa podpisanego tokenu internetowego JSON (JWT) w nagłówku Uwierzytelniania przychodzącego żądania HTTPS. Możesz użyć standardowych technik weryfikacji JWT JWT open ID Połączenie (OIDC), aby zapewnić integralność tokenu w następujący sposób. Okres istnienia JWT wynosi pięć (5) minut, a dla każdego zdarzenia wysyłanego do identyfikatora URI wywołania zwrotnego jest tworzony nowy token.

  1. Uzyskaj adres URL konfiguracji open ID: https://acscallautomation.communication.azure.com/calling/.well-known/acsopenidconfiguration
  2. Zainstaluj następujące pakiety:
pip install flask pyjwt
  1. Skonfiguruj aplikację, aby zweryfikować JWT i konfigurację zasobu usług Azure Communication Services. Potrzebne audience są wartości obecne w ładunku JWT.
  2. Zweryfikuj wystawcę, odbiorców i token JWT.
    • Odbiorcy to identyfikator zasobu usług Azure Communication Services użyty do skonfigurowania klienta usługi Call Automation. Zobacz tutaj , jak to zrobić.
    • Punkt końcowy zestawu kluczy sieci Web JSON (JWKS) w konfiguracji OpenId zawiera klucze używane do sprawdzania poprawności tokenu JWT. Gdy podpis jest prawidłowy i token nie wygasł (w ciągu 5 minut od wygenerowania), klient może użyć tokenu do autoryzacji.

Ten przykładowy kod pokazuje, jak skonfigurować klienta OIDC w celu zweryfikowania ładunku elementu webhook przy użyciu 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()

Następne kroki