Cara mengamankan titik akhir webhook

Mengamankan pengiriman pesan dari ujung ke ujung sangat penting untuk memastikan kerahasiaan, integritas, dan kepercayaan informasi sensitif yang dikirimkan antar sistem. Kemampuan dan kesediaan Anda untuk mempercayai informasi yang diterima dari sistem jarak jauh bergantung pada pengirim yang memberikan identitas mereka. Automasi Panggilan memiliki dua cara untuk mengomunikasikan peristiwa yang dapat diamankan; peristiwa IncomingCall bersama yang dikirim oleh Azure Event Grid, dan semua peristiwa tengah panggilan lainnya yang dikirim oleh platform Automation Panggilan melalui webhook.

Peristiwa Panggilan Masuk

Azure Communication Services mengandalkan langganan Azure Event Grid untuk mengirimkan peristiwa IncomingCall. Anda dapat merujuk ke tim Azure Event Grid untuk dokumentasi mereka tentang cara mengamankan langganan webhook.

Memanggil peristiwa webhook Automation

Peristiwa Automation panggilan dikirim ke URI panggilan balik webhook yang ditentukan saat Anda menjawab panggilan, atau melakukan panggilan keluar baru. URI panggilan balik Anda harus menjadi titik akhir publik dengan sertifikat HTTPS, nama DNS, dan alamat IP yang valid dengan port firewall yang benar terbuka untuk mengaktifkan Automasi Panggilan untuk menjangkaunya. Server web publik anonim ini dapat membuat risiko keamanan jika Anda tidak mengambil langkah-langkah yang diperlukan untuk mengamankannya dari akses yang tidak sah.

Cara umum Anda dapat meningkatkan keamanan ini adalah dengan menerapkan mekanisme API KEY. Server web Anda dapat menghasilkan kunci pada runtime dan menyediakannya di URI panggilan balik sebagai parameter kueri saat Anda menjawab atau membuat panggilan. Server web Anda dapat memverifikasi kunci di panggilan balik webhook dari Automasi Panggilan sebelum mengizinkan akses. Beberapa pelanggan memerlukan lebih banyak langkah-langkah keamanan. Dalam kasus ini, perangkat jaringan perimeter dapat memverifikasi webhook masuk, terpisah dari webserver atau aplikasi itu sendiri. Mekanisme kunci API saja mungkin tidak cukup.

Meningkatkan keamanan panggilan balik webhook Automation Panggilan

Setiap panggilan balik webhook tengah panggilan yang dikirim oleh Automation Panggilan menggunakan JSON Web Token (JWT) yang ditandatangani di header Autentikasi permintaan HTTPS masuk. Anda dapat menggunakan teknik validasi JWT Open ID Koneksi (OIDC) standar untuk memastikan integritas token sebagai berikut. Masa pakai JWT adalah lima (5) menit dan token baru dibuat untuk setiap peristiwa yang dikirim ke URI panggilan balik.

  1. Dapatkan URL konfigurasi Open ID: https://acscallautomation.communication.azure.com/calling/.well-known/acsopenidconfiguration
  2. Instal paket NuGet Microsoft.AspNetCore.Authentication.JwtBearer.
  3. Konfigurasikan aplikasi Anda untuk memvalidasi JWT menggunakan paket NuGet dan konfigurasi sumber daya Azure Communication Services Anda. Anda memerlukan audience nilai seperti yang ada di payload JWT.
  4. Validasi penerbit, audiens, dan token JWT.
    • Audiens adalah ID sumber daya Azure Communication Services yang Anda gunakan untuk menyiapkan klien Automation Panggilan Anda. Lihat di sini tentang cara mendapatkannya.
    • Titik akhir JSON Web Key Set (JWKS) dalam konfigurasi OpenId berisi kunci yang digunakan untuk memvalidasi token JWT. Ketika tanda tangan valid dan token belum kedaluwarsa (dalam waktu 5 menit setelah pembuatan), klien dapat menggunakan token untuk otorisasi.

Kode sampel ini menunjukkan cara menggunakan Microsoft.IdentityModel.Protocols.OpenIdConnect untuk memvalidasi payload 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();

Meningkatkan keamanan panggilan balik webhook Automation Panggilan

Setiap panggilan balik webhook tengah panggilan yang dikirim oleh Automation Panggilan menggunakan JSON Web Token (JWT) yang ditandatangani di header Autentikasi permintaan HTTPS masuk. Anda dapat menggunakan teknik validasi JWT Open ID Koneksi (OIDC) standar untuk memastikan integritas token sebagai berikut. Masa pakai JWT adalah lima (5) menit dan token baru dibuat untuk setiap peristiwa yang dikirim ke URI panggilan balik.

  1. Dapatkan URL konfigurasi Open ID: https://acscallautomation.communication.azure.com/calling/.well-known/acsopenidconfiguration
  2. Sampel berikut menggunakan kerangka kerja Spring, dibuat menggunakan spring initializr dengan Maven sebagai alat build proyek.
  3. Tambahkan dependensi berikut di 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. Konfigurasikan aplikasi Anda untuk memvalidasi JWT dan konfigurasi sumber daya Azure Communication Services Anda. Anda memerlukan audience nilai seperti yang ada di payload JWT.
  2. Validasi penerbit, audiens, dan token JWT.
    • Audiens adalah ID sumber daya Azure Communication Services yang Anda gunakan untuk menyiapkan klien Automation Panggilan Anda. Lihat di sini tentang cara mendapatkannya.
    • Titik akhir JSON Web Key Set (JWKS) dalam konfigurasi OpenId berisi kunci yang digunakan untuk memvalidasi token JWT. Ketika tanda tangan valid dan token belum kedaluwarsa (dalam waktu 5 menit setelah pembuatan), klien dapat menggunakan token untuk otorisasi.

Kode sampel ini menunjukkan cara mengonfigurasi klien OIDC untuk memvalidasi payload webhook menggunakan 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;
    }
}

Meningkatkan keamanan panggilan balik webhook Automation Panggilan

Setiap panggilan balik webhook tengah panggilan yang dikirim oleh Automation Panggilan menggunakan JSON Web Token (JWT) yang ditandatangani di header Autentikasi permintaan HTTPS masuk. Anda dapat menggunakan teknik validasi JWT Open ID Koneksi (OIDC) standar untuk memastikan integritas token sebagai berikut. Masa pakai JWT adalah lima (5) menit dan token baru dibuat untuk setiap peristiwa yang dikirim ke URI panggilan balik.

  1. Dapatkan URL konfigurasi Open ID: https://acscallautomation.communication.azure.com/calling/.well-known/acsopenidconfiguration
  2. Instal paket berikut:
npm install express jwks-rsa jsonwebtoken
  1. Konfigurasikan aplikasi Anda untuk memvalidasi JWT dan konfigurasi sumber daya Azure Communication Services Anda. Anda memerlukan audience nilai seperti yang ada di payload JWT.
  2. Validasi penerbit, audiens, dan token JWT.
    • Audiens adalah ID sumber daya Azure Communication Services yang Anda gunakan untuk menyiapkan klien Automation Panggilan Anda. Lihat di sini tentang cara mendapatkannya.
    • Titik akhir JSON Web Key Set (JWKS) dalam konfigurasi OpenId berisi kunci yang digunakan untuk memvalidasi token JWT. Ketika tanda tangan valid dan token belum kedaluwarsa (dalam waktu 5 menit setelah pembuatan), klien dapat menggunakan token untuk otorisasi.

Kode sampel ini menunjukkan cara mengonfigurasi klien OIDC untuk memvalidasi payload webhook menggunakan 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}`);
});

Meningkatkan keamanan panggilan balik webhook Automation Panggilan

Setiap panggilan balik webhook tengah panggilan yang dikirim oleh Automation Panggilan menggunakan JSON Web Token (JWT) yang ditandatangani di header Autentikasi permintaan HTTPS masuk. Anda dapat menggunakan teknik validasi JWT Open ID Koneksi (OIDC) standar untuk memastikan integritas token sebagai berikut. Masa pakai JWT adalah lima (5) menit dan token baru dibuat untuk setiap peristiwa yang dikirim ke URI panggilan balik.

  1. Dapatkan URL konfigurasi Open ID: https://acscallautomation.communication.azure.com/calling/.well-known/acsopenidconfiguration
  2. Instal paket berikut:
pip install flask pyjwt
  1. Konfigurasikan aplikasi Anda untuk memvalidasi JWT dan konfigurasi sumber daya Azure Communication Services Anda. Anda memerlukan audience nilai seperti yang ada di payload JWT.
  2. Validasi penerbit, audiens, dan token JWT.
    • Audiens adalah ID sumber daya Azure Communication Services yang Anda gunakan untuk menyiapkan klien Automation Panggilan Anda. Lihat di sini tentang cara mendapatkannya.
    • Titik akhir JSON Web Key Set (JWKS) dalam konfigurasi OpenId berisi kunci yang digunakan untuk memvalidasi token JWT. Ketika tanda tangan valid dan token belum kedaluwarsa (dalam waktu 5 menit setelah pembuatan), klien dapat menggunakan token untuk otorisasi.

Kode sampel ini menunjukkan cara mengonfigurasi klien OIDC untuk memvalidasi payload webhook menggunakan 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()

Langkah berikutnya