Поделиться через


Как защитить конечную точку веб-перехватчика

Защита доставки сообщений от конца имеет решающее значение для обеспечения конфиденциальности, целостности и надежности конфиденциальной информации, передаваемой между системами. Ваша способность и готовность доверять информации, полученной из удаленной системы, зависит от отправителя, предоставляющего свое удостоверение. Служба автоматизации вызовов имеет два способа взаимодействия с событиями, которые можно защитить; общее событие ВходящегоCall, отправленное Сетка событий Azure, и все остальные события по середине вызова, отправленные платформой автоматизации вызовов через веб-перехватчик.

Событие входящего вызова

Службы коммуникации Azure использует подписки Сетка событий Azure для доставки события ВходящихCall. Вы можете обратиться к команде Сетка событий Azure по их документации о том, как защитить подписку на веб-перехватчик.

События веб-перехватчика службы автоматизации вызовов

События автоматизации вызовов отправляются в URI обратного вызова веб-перехватчика, указанный при ответе на вызов или помещают новый исходящий вызов. URI обратного вызова должен быть общедоступной конечной точкой с допустимым сертификатом HTTPS, DNS-именем и IP-адресом с правильными портами брандмауэра, чтобы включить автоматизацию вызовов для доступа к нему. Этот анонимный общедоступный веб-сервер может создать риск безопасности, если вы не выполните необходимые действия, чтобы защитить его от несанкционированного доступа.

Распространенный способ повышения безопасности заключается в реализации механизма API KEY. Веб-сервер может создать ключ во время выполнения и предоставить его в URI обратного вызова в качестве параметра запроса при ответе или создании вызова. Ваш веб-сервер может проверить ключ в обратном вызове веб-перехватчика из службы автоматизации вызовов, прежде чем разрешать доступ. Для некоторых клиентов требуются дополнительные меры безопасности. В таких случаях сетевое устройство периметра может проверить входящий веб-перехватчик отдельно от самого веб-сервера или приложения. Механизм ключа API может быть недостаточно.

Улучшение безопасности обратного вызова службы автоматизации звонков

Каждый обратный вызов веб-перехватчика, отправленный службой автоматизации вызовов, использует подписанный веб-маркер JSON (JWT) в заголовке проверки подлинности входящего HTTPS-запроса. Для обеспечения целостности маркера можно использовать стандартные методы проверки JWT Подключение с открытым идентификатором (OIDC). Время существования JWT составляет пять (5) минут, а для каждого события, отправленного в URI обратного вызова, создается новый маркер.

  1. Получите URL-адрес конфигурации Open ID: https://acscallautomation.communication.azure.com/calling/.well-known/acsopenidconfiguration
  2. Установите пакет NuGet Microsoft.AspNetCore.Authentication.JwtBearer.
  3. Настройте приложение для проверки JWT с помощью пакета NuGet и конфигурации ресурса Службы коммуникации Azure. Вам нужны значения, которые присутствуют audience в полезных данных JWT.
  4. Проверьте издателя, аудиторию и токен JWT.
    • Аудитория — это ваш Службы коммуникации Azure идентификатор ресурса, используемый для настройки клиента автоматизации вызовов. См. здесь о том, как получить его.
    • Конечная точка набора веб-ключей JSON (JWKS) в конфигурации OpenId содержит ключи, используемые для проверки маркера JWT. Если подпись действительна, и срок действия маркера не истек (в течение 5 минут после создания), клиент может использовать маркер для авторизации.

В этом примере кода показано, как использовать для Microsoft.IdentityModel.Protocols.OpenIdConnect проверки полезных данных веб-перехватчика

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();

Улучшение безопасности обратного вызова службы автоматизации звонков

Каждый обратный вызов веб-перехватчика, отправленный службой автоматизации вызовов, использует подписанный веб-маркер JSON (JWT) в заголовке проверки подлинности входящего HTTPS-запроса. Для обеспечения целостности маркера можно использовать стандартные методы проверки JWT Подключение с открытым идентификатором (OIDC). Время существования JWT составляет пять (5) минут, а для каждого события, отправленного в URI обратного вызова, создается новый маркер.

  1. Получите URL-адрес конфигурации Open ID: https://acscallautomation.communication.azure.com/calling/.well-known/acsopenidconfiguration
  2. В следующем примере используется платформа Spring, созданная с помощью spring initializr с Maven в качестве средства сборки проекта.
  3. Добавьте следующие зависимости в вашу 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. Настройте приложение для проверки JWT и конфигурации ресурса Службы коммуникации Azure. Вам нужны значения, которые присутствуют audience в полезных данных JWT.
  2. Проверьте издателя, аудиторию и токен JWT.
    • Аудитория — это ваш Службы коммуникации Azure идентификатор ресурса, используемый для настройки клиента автоматизации вызовов. См. здесь о том, как получить его.
    • Конечная точка набора веб-ключей JSON (JWKS) в конфигурации OpenId содержит ключи, используемые для проверки маркера JWT. Если подпись действительна, и срок действия маркера не истек (в течение 5 минут после создания), клиент может использовать маркер для авторизации.

В этом примере кода показано, как настроить клиент OIDC для проверки полезных данных веб-перехватчика с помощью 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;
    }
}

Улучшение безопасности обратного вызова службы автоматизации звонков

Каждый обратный вызов веб-перехватчика, отправленный службой автоматизации вызовов, использует подписанный веб-маркер JSON (JWT) в заголовке проверки подлинности входящего HTTPS-запроса. Для обеспечения целостности маркера можно использовать стандартные методы проверки JWT Подключение с открытым идентификатором (OIDC). Время существования JWT составляет пять (5) минут, а для каждого события, отправленного в URI обратного вызова, создается новый маркер.

  1. Получите URL-адрес конфигурации Open ID: https://acscallautomation.communication.azure.com/calling/.well-known/acsopenidconfiguration
  2. Установите следующие пакеты:
npm install express jwks-rsa jsonwebtoken
  1. Настройте приложение для проверки JWT и конфигурации ресурса Службы коммуникации Azure. Вам нужны значения, которые присутствуют audience в полезных данных JWT.
  2. Проверьте издателя, аудиторию и токен JWT.
    • Аудитория — это ваш Службы коммуникации Azure идентификатор ресурса, используемый для настройки клиента автоматизации вызовов. См. здесь о том, как получить его.
    • Конечная точка набора веб-ключей JSON (JWKS) в конфигурации OpenId содержит ключи, используемые для проверки маркера JWT. Если подпись действительна, и срок действия маркера не истек (в течение 5 минут после создания), клиент может использовать маркер для авторизации.

В этом примере кода показано, как настроить клиент OIDC для проверки полезных данных веб-перехватчика с помощью 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}`);
});

Улучшение безопасности обратного вызова службы автоматизации звонков

Каждый обратный вызов веб-перехватчика, отправленный службой автоматизации вызовов, использует подписанный веб-маркер JSON (JWT) в заголовке проверки подлинности входящего HTTPS-запроса. Для обеспечения целостности маркера можно использовать стандартные методы проверки JWT Подключение с открытым идентификатором (OIDC). Время существования JWT составляет пять (5) минут, а для каждого события, отправленного в URI обратного вызова, создается новый маркер.

  1. Получите URL-адрес конфигурации Open ID: https://acscallautomation.communication.azure.com/calling/.well-known/acsopenidconfiguration
  2. Установите следующие пакеты:
pip install flask pyjwt
  1. Настройте приложение для проверки JWT и конфигурации ресурса Службы коммуникации Azure. Вам нужны значения, которые присутствуют audience в полезных данных JWT.
  2. Проверьте издателя, аудиторию и токен JWT.
    • Аудитория — это ваш Службы коммуникации Azure идентификатор ресурса, используемый для настройки клиента автоматизации вызовов. См. здесь о том, как получить его.
    • Конечная точка набора веб-ключей JSON (JWKS) в конфигурации OpenId содержит ключи, используемые для проверки маркера JWT. Если подпись действительна, и срок действия маркера не истек (в течение 5 минут после создания), клиент может использовать маркер для авторизации.

В этом примере кода показано, как настроить клиент OIDC для проверки полезных данных веб-перехватчика с помощью 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()

Следующие шаги