Межпроцессное взаимодействие с помощью gRPC
Примечание.
Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 9 этой статьи.
Предупреждение
Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в политике поддержки .NET и .NET Core. В текущем выпуске см . версию .NET 9 этой статьи.
Внимание
Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
В текущем выпуске см . версию .NET 9 этой статьи.
Процессы, выполняемые на одном компьютере, могут быть разработаны для взаимодействия друг с другом. Операционные системы предоставляют технологии для быстрого и эффективного внутрипроцессного взаимодействия (IPC). Популярными примерами технологий IPC являются сокеты домена Unix и именованные каналы.
.NET обеспечивает поддержку внутрипроцессного взаимодействия с помощью gRPC.
Встроенная поддержка именованных каналов в ASP.NET Core требует .NET 8 или более поздней версии.
Начало работы
Вызовы IPC отправляются с клиента на сервер. Чтобы обеспечить обмен данными между приложениями на компьютере с gRPC, по крайней мере одно приложение должно размещать сервер gRPC ASP.NET Core.
Сервер ASP.NET Core gRPC обычно создается из шаблона gRPC. Файл проекта, созданный шаблоном, используется Microsoft.NET.SDK.Web
в качестве пакета SDK:
<Project Sdk="Microsoft.NET.Sdk.Web">
<ItemGroup>
<PackageReference Include="Grpc.AspNetCore" Version="2.47.0" />
<Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>
</Project>
Значение Microsoft.NET.SDK.Web
пакета SDK автоматически добавляет ссылку на платформу ASP.NET Core. Ссылка позволяет приложению использовать ASP.NET основные типы, необходимые для размещения сервера.
Кроме того, можно добавить сервер в существующие проекты non-ASP.NET Core, такие как службы Windows, приложения WPF или приложения WinForms. Дополнительные сведения см. в разделе "Узел gRPC" в non-ASP.NET основных проектах .
Транспорты обмена данными между процессами (IPC)
Вызовы gRPC между клиентом и сервером на разных компьютерах обычно отправляются через сокеты TCP. TCP — это хороший выбор для обмена данными между сетью или Интернетом. Однако транспортЫ IPC предлагают преимущества при обмене данными между процессами на одном компьютере:
- Меньше накладных расходов и скоростей передачи.
- Интеграция с функциями безопасности ОС.
- Не использует tcp-порты, которые являются ограниченным ресурсом.
.NET поддерживает несколько транспортных объектов IPC:
- Сокеты домена Unix (UDS) — это широко поддерживаемая технология IPC. UDS — это лучший выбор для создания кроссплатформенных приложений, которые можно использовать в Linux, macOS и Windows 10/Windows Server 2019 или более поздней версии.
- Именованные каналы поддерживаются всеми версиями Windows. Именованные каналы хорошо интегрируются с безопасностью Windows, которая может управлять доступом клиента к каналу.
- Дополнительные транспорты IPC путем реализации IConnectionListenerFactory и регистрации реализации при запуске приложения.
В зависимости от ОС кроссплатформенные приложения могут выбирать разные транспорты IPC. Приложение может проверить операционную систему при запуске и выбрать нужный транспорт для этой платформы:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
if (OperatingSystem.IsWindows())
{
serverOptions.ListenNamedPipe("MyPipeName");
}
else
{
var socketPath = Path.Combine(Path.GetTempPath(), "socket.tmp");
serverOptions.ListenUnixSocket(socketPath);
}
serverOptions.ConfigureEndpointDefaults(listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http2;
});
});
Вопросы безопасности
Приложения IPC отправляют и получают вызовы RPC. Внешнее взаимодействие — это потенциальный вектор атаки для приложений IPC и должен быть правильно защищен.
Безопасное приложение сервера IPC для непредвиденных вызывающих объектов
Серверное приложение IPC размещает службы RPC для вызова других приложений. Входящие вызывающие серверы должны проходить проверку подлинности, чтобы предотвратить ненадежные клиенты от вызова RPC к серверу.
Безопасность транспорта — это один из вариантов защиты сервера. ТранспортЫ IPC, такие как сокеты домена Unix и именованные каналы, поддерживают ограничение доступа на основе разрешений операционной системы:
- Именованные каналы поддерживают защиту канала с помощью модели управления доступом Windows. Права доступа можно настроить в .NET при запуске сервера с помощью PipeSecurity класса.
- Сокеты домена Unix поддерживают защиту сокета с разрешениями файла.
Еще одним вариантом защиты сервера IPC является использование проверки подлинности и авторизации, встроенной в ASP.NET Core. Например, сервер можно настроить для проверки подлинности сертификата. Вызовы RPC, выполненные клиентскими приложениями без обязательного сертификата, завершаются ошибкой с несанкционированным ответом.
Проверка сервера в клиентском приложении IPC
Для клиентского приложения важно проверить identity вызывающий сервер. Проверка необходима для защиты от вредоносных субъектов от остановки доверенного сервера, запуска собственного и приема входящих данных от клиентов.
Именованные каналы обеспечивают поддержку получения учетной записи, в которую выполняется сервер. Клиент может проверить, был запущен ли сервер ожидаемой учетной записью:
internal static bool CheckPipeConnectionOwnership(
NamedPipeClientStream pipeStream, SecurityIdentifier expectedOwner)
{
var remotePipeSecurity = pipeStream.GetAccessControl();
var remoteOwner = remotePipeSecurity.GetOwner(typeof(SecurityIdentifier));
return expectedOwner.Equals(remoteOwner);
}
Еще одним вариантом проверки сервера является защита конечных точек с помощью HTTPS внутри ASP.NET Core. Клиент может настроить SocketsHttpHandler
для проверки, что сервер использует ожидаемый сертификат при установке подключения.
var socketsHttpHandler = new SocketsHttpHandler()
{
SslOptions = new SslOptions()
{
RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
{
if (sslPolicyErrors != SslPolicyErrors.None)
{
return false;
}
// Validate server cert thumbprint matches the expected thumbprint.
}
}
};
Защита от эскалации привилегий именованного канала
Именованные каналы поддерживают функцию, называемую олицетворением. С помощью олицетворения сервер именованных каналов может выполнять код с привилегиями пользователя клиента. Это мощная функция, но может позволить серверу с низким уровнем привилегий олицетворить вызывающий объект с высоким уровнем привилегий, а затем запустить вредоносный код.
Клиент может защититься от этой атаки, не разрешая олицетворение при подключении к серверу. Если сервер не требуется, TokenImpersonationLevel при создании клиентского подключения следует использовать значение None
или Anonymous
его значение:
using var pipeClient = new NamedPipeClientStream(
serverName: ".", pipeName: "testpipe", PipeDirection.In, PipeOptions.None, TokenImpersonationLevel.None);
await pipeClient.ConnectAsync();
TokenImpersonationLevel.None
— значение по умолчанию в NamedPipeClientStream
конструкторах, у которых нет impersonationLevel
параметра.
Настройка клиента и сервера
Клиент и сервер должны быть настроены для использования транспорта обмена данными между процессами (IPC). Дополнительные сведения о настройке Kestrel и SocketsHttpHandler использовании IPC:
- Взаимодействие между процессами с сокетами домена gRPC и Unix
- Взаимодействие между процессами с gRPC и именованными каналами
Примечание.
Встроенная поддержка именованных каналов в ASP.NET Core требует .NET 8 или более поздней версии.
Процессы, выполняемые на одном компьютере, могут быть разработаны для взаимодействия друг с другом. Операционные системы предоставляют технологии для быстрого и эффективного внутрипроцессного взаимодействия (IPC). Популярными примерами технологий IPC являются сокеты домена Unix и именованные каналы.
.NET обеспечивает поддержку внутрипроцессного взаимодействия с помощью gRPC.
Примечание.
Встроенная поддержка именованных каналов в ASP.NET Core требует .NET 8 или более поздней версии.
Дополнительные сведения см . в версии .NET 8 или более поздней версии этого раздела.
Начало работы
Вызовы gRPC отправляются с клиента на сервер. Чтобы обеспечить обмен данными между приложениями на компьютере с gRPC, по крайней мере одно приложение должно размещать сервер gRPC ASP.NET Core.
ASP.NET Core и gRPC можно разместить в любом приложении с помощью .NET Core 3.1 или более поздней версии. Для этого необходимо добавить платформу Microsoft.AspNetCore.App
в проект.
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Grpc.AspNetCore" Version="2.47.0" />
<Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>
</Project>
В предыдущем файле проекта выполняются следующие действия:
- Добавляется ссылка на платформу в
Microsoft.AspNetCore.App
. Ссылка на платформу позволяет приложениям, отличным от ASP.NET Core, таким как службы Windows, приложения WPF или приложения WinForms, использовать ASP.NET Core и размещать сервер ASP.NET Core. - Добавляется ссылка на пакет NuGet в
Grpc.AspNetCore
. - Добавляется файл
.proto
.
Настройка сокетов домена Unix
Вызовы gRPC между клиентом и сервером на разных компьютерах обычно отправляются через сокеты TCP. Протокол TCP был разработан для обмена данными по сети. Сокеты домена Unix (UDS) — это широко поддерживаемая технология IPC, которая эффективнее чем TCP, когда клиент и сервер находятся на одном компьютере. .NET обеспечивает встроенную поддержку UDS в клиентских и серверных приложениях.
Требования:
- .NET 5 или более поздней версии
- Linux, macOS или Windows 10/Windows Server 2019 или более поздней версии
Конфигурация сервера
Сокеты домена Unix (UDS) поддерживаются Kestrel, который настраивается в Program.cs
:
public static readonly string SocketPath = Path.Combine(Path.GetTempPath(), "socket.tmp");
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.ConfigureKestrel(options =>
{
if (File.Exists(SocketPath))
{
File.Delete(SocketPath);
}
options.ListenUnixSocket(SocketPath, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http2;
});
});
});
Предшествующий пример:
- Настраивает конечные точки Kestrel в
ConfigureKestrel
. - Вызывает ListenUnixSocket для прослушивания UDS по указанному пути.
- Создает конечную точку UDS, которая не настроена для использования HTTPS. Дополнительные сведения о включении HTTPS см. в разделе о настройке конечной точки HTTPS Kestrel.
Настройка клиента
GrpcChannel
поддерживает выполнение вызовов gRPC через настраиваемый транспорт. При создании канала его можно настроить с помощью SocketsHttpHandler
, у которого имеется настраиваемый ConnectCallback
. Обратный вызов позволяет клиенту устанавливать соединения через настраиваемые транспорты, а затем передавать HTTP-запросы через этот транспорт.
Пример фабрики подключений для сокетов доменов UNIX:
public class UnixDomainSocketConnectionFactory
{
private readonly EndPoint _endPoint;
public UnixDomainSocketConnectionFactory(EndPoint endPoint)
{
_endPoint = endPoint;
}
public async ValueTask<Stream> ConnectAsync(SocketsHttpConnectionContext _,
CancellationToken cancellationToken = default)
{
var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
try
{
await socket.ConnectAsync(_endPoint, cancellationToken).ConfigureAwait(false);
return new NetworkStream(socket, true);
}
catch
{
socket.Dispose();
throw;
}
}
}
Использование настраиваемой фабрики подключений для создания канала:
public static readonly string SocketPath = Path.Combine(Path.GetTempPath(), "socket.tmp");
public static GrpcChannel CreateChannel()
{
var udsEndPoint = new UnixDomainSocketEndPoint(SocketPath);
var connectionFactory = new UnixDomainSocketConnectionFactory(udsEndPoint);
var socketsHttpHandler = new SocketsHttpHandler
{
ConnectCallback = connectionFactory.ConnectAsync
};
return GrpcChannel.ForAddress("http://localhost", new GrpcChannelOptions
{
HttpHandler = socketsHttpHandler
});
}
Каналы, созданные с помощью приведенного выше кода, отправляют вызовы gRPC через сокеты доменов UNIX. Поддержку других технологий IPC можно реализовать, используя возможности расширяемости в Kestrel и SocketsHttpHandler
.
ASP.NET Core