Delen via


Communicatie tussen processen met gRPC

Notitie

Dit is niet de nieuwste versie van dit artikel. Zie de .NET 9-versie van dit artikelvoor de huidige release.

Waarschuwing

Deze versie van ASP.NET Core wordt niet meer ondersteund. Zie de .NET- en .NET Core-ondersteuningsbeleidvoor meer informatie. Zie de .NET 9-versie van dit artikelvoor de huidige release.

Belangrijk

Deze informatie heeft betrekking op een pre-releaseproduct dat aanzienlijk kan worden gewijzigd voordat het commercieel wordt uitgebracht. Microsoft geeft geen garanties, uitdrukkelijk of impliciet, met betrekking tot de informatie die hier wordt verstrekt.

Zie de .NET 9-versie van dit artikelvoor de huidige release.

Processen die op dezelfde machine worden uitgevoerd, kunnen worden ontworpen om met elkaar te communiceren. Besturingssystemen bieden technologieën voor het inschakelen van snelle en efficiënte IPC-(Inter-Process Communication). Populaire voorbeelden van IPC-technologieën zijn Unix-domeinsockets en named pipes.

.NET biedt ondersteuning voor communicatie tussen processen met behulp van gRPC.

Voor ingebouwde ondersteuning voor benoemde pijpen in ASP.NET Core is .NET 8 of hoger vereist.

Aan de slag

IPC-aanroepen worden verzonden van een client naar een server. Als u wilt communiceren tussen apps op een computer met gRPC, moet ten minste één app een ASP.NET Core gRPC-server hosten.

Een ASP.NET Core gRPC-server wordt meestal gemaakt op basis van de gRPC-sjabloon. Het projectbestand dat door de sjabloon is gemaakt, gebruikt Microsoft.NET.SDK.Web als 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>

De Microsoft.NET.SDK.Web SDK-waarde voegt automatisch een verwijzing toe naar het ASP.NET Core-framework. Met de verwijzing kan de app gebruikmaken van ASP.NET Core-typen die zijn vereist voor het hosten van een server.

Het is ook mogelijk om een server toe te voegen aan bestaande non-ASP.NET Core-projecten, zoals Windows Services, WPF-apps of WinForms-apps. Zie Host gRPC in non-ASP.NET Core-projecten voor meer informatie.

Interprocescommunicatie-transporten (IPC)

gRPC-aanroepen tussen een client en server op verschillende computers worden meestal verzonden via TCP-sockets. TCP is een goede keuze voor communicatie via een netwerk of internet. IPC-transporten bieden echter voordelen bij het communiceren tussen processen op dezelfde machine:

  • Minder overhead en snellere overdrachtssnelheden.
  • Integratie met beveiligingsfuncties van het besturingssysteem.
  • Maakt geen gebruik van TCP-poorten, die een beperkte resource zijn.

.NET ondersteunt meerdere IPC-transporten:

Afhankelijk van het besturingssysteem kunnen platformoverschrijdende apps verschillende IPC-transporten kiezen. Een app kan het besturingssysteem controleren bij het opstarten en het gewenste transport voor dat platform kiezen:

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

Beveiligingsoverwegingen

IPC-apps verzenden en ontvangen RPC-oproepen. Externe communicatie is een mogelijke aanvalsvector voor IPC-apps en moet goed worden beveiligd.

IPC-server-app beveiligen tegen onverwachte bellers

De IPC-server-app biedt RPC-services aan waarmee andere applicaties gebruik kunnen maken. Binnenkomende bellers moeten worden geverifieerd om te voorkomen dat niet-vertrouwde clients RPC-aanroepen naar de server uitvoeren.

Transportbeveiliging is één optie voor het beveiligen van een server. IPC-transporten, zoals Unix-domeinsockets en benoemde pijpen, bieden ondersteuning voor het beperken van de toegang op basis van besturingssysteemmachtigingen:

  • Named pipes ondersteunt het beveiligen van een pijp met het Windows-toegangsbeheermodel. Toegangsrechten kunnen worden geconfigureerd in .NET wanneer een server wordt gestart met behulp van de PipeSecurity-klasse.
  • Unix-domeinsockets ondersteunen het beveiligen van een socket met bestandsmachtigingen.

Een andere optie voor het beveiligen van een IPC-server is het gebruik van verificatie en autorisatie die is ingebouwd in ASP.NET Core. De server kan bijvoorbeeld worden geconfigureerd om certificaatverificatie te vereisen. RPC-aanroepen van client-apps zonder het vereiste certificaat mislukken met een niet-geautoriseerd antwoord.

De server valideren in de IPC-client-app

Het is belangrijk dat de client-app de identiteit valideert van de server die wordt aangeroepen. Validatie is nodig om een kwaadwillende actor te beschermen tegen het stoppen van de vertrouwde server, het uitvoeren van een eigen server en het accepteren van binnenkomende gegevens van clients.

Named pipes biedt ondersteuning voor het verkrijgen van het account waarmee een server draait. Een client kan valideren dat de server is gestart door het verwachte account:

internal static bool CheckPipeConnectionOwnership(
    NamedPipeClientStream pipeStream, SecurityIdentifier expectedOwner)
{
    var remotePipeSecurity = pipeStream.GetAccessControl();
    var remoteOwner = remotePipeSecurity.GetOwner(typeof(SecurityIdentifier));
    return expectedOwner.Equals(remoteOwner);
}

Een andere optie voor het valideren van de server is om de eindpunten te beveiligen met HTTPS- in ASP.NET Core. De client kan SocketsHttpHandler configureren om te controleren of de server het verwachte certificaat gebruikt wanneer de verbinding tot stand is gebracht.

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.
        }
    }
};

Bescherming tegen escalatie van benoemde pijpbevoegdheden

Named pipes ondersteunt een functie genaamd impersonatie. Met imitatie kan de benoemde pipes-server code uitvoeren met de bevoegdheden van de clientgebruiker. Dit is een krachtige functie, maar kan een server met lage bevoegdheden toestaan om een aanroeper met hoge bevoegdheden te imiteren en vervolgens schadelijke code uit te voeren.

Client kan bescherming bieden tegen deze aanval door imitatie niet toe te staan bij het maken van verbinding met een server. Tenzij een server dit vereist, moet een TokenImpersonationLevel waarde van None of Anonymous worden gebruikt bij het maken van een clientverbinding:

using var pipeClient = new NamedPipeClientStream(
    serverName: ".", pipeName: "testpipe", PipeDirection.In, PipeOptions.None, TokenImpersonationLevel.None);
await pipeClient.ConnectAsync();

TokenImpersonationLevel.None is de standaardwaarde in NamedPipeClientStream constructors die geen impersonationLevel parameter hebben.

Client en server configureren

De client en server moeten worden geconfigureerd voor het gebruik van een IPC-transport (Inter-Process Communication). Voor meer informatie over het configureren van Kestrel en SocketsHttpHandler voor het gebruik van IPC:

Notitie

Voor ingebouwde ondersteuning voor benoemde pijpen in ASP.NET Core is .NET 8 of hoger vereist.

Processen die op dezelfde machine worden uitgevoerd, kunnen worden ontworpen om met elkaar te communiceren. Besturingssystemen bieden technologieën voor het inschakelen van snelle en efficiënte IPC-(Inter-Process Communication). Populaire voorbeelden van IPC-technologieën zijn Unix-domeinsockets en named pipes.

.NET biedt ondersteuning voor communicatie tussen processen met behulp van gRPC.

Notitie

Voor ingebouwde ondersteuning voor benoemde pijpen in ASP.NET Core is .NET 8 of hoger vereist.
Zie de .NET 8- of latere versie van dit onderwerp voor meer informatie

Aan de slag

gRPC-aanroepen worden van een client naar een server verzonden. Als u wilt communiceren tussen apps op een computer met gRPC, moet ten minste één app een ASP.NET Core gRPC-server hosten.

ASP.NET Core en gRPC kunnen worden gehost in elke app met .NET Core 3.1 of hoger door het Microsoft.AspNetCore.App framework toe te voegen aan het project.

<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>

Het voorgaande projectbestand:

  • Voegt een frameworkreferentie toe aan Microsoft.AspNetCore.App. Met de frameworkreferentie kunnen non-ASP.NET Core-apps, zoals Windows Services, WPF-apps of WinForms-apps, ASP.NET Core gebruiken en een ASP.NET Core-server hosten.
  • Voegt een NuGet-pakketreferentie toe aan Grpc.AspNetCore.
  • Hiermee voegt u een .proto-bestand toe.

Unix-domeinsockets configureren

gRPC-aanroepen tussen een client en server op verschillende computers worden meestal verzonden via TCP-sockets. TCP is ontworpen voor communicatie via een netwerk. Unix-domeinsockets (UDS) een veelgebruikte IPC-technologie zijn die efficiënter is dan TCP wanneer de client en server zich op dezelfde computer bevinden. .NET biedt ingebouwde ondersteuning voor UDS in client- en server-apps.

Eisen:

Serverconfiguratie

Unix-domeinsockets (UDS) worden ondersteund door Kestrel, dat is geconfigureerd in 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;
                });
            });
        });

Het voorgaande voorbeeld:

  • Hiermee configureert u de eindpunten van Kestrelin ConfigureKestrel.
  • Roept ListenUnixSocket aan om naar een UDS te luisteren met het opgegeven pad.
  • Hiermee maakt u een UDS-eindpunt dat niet is geconfigureerd voor het gebruik van HTTPS. Zie Kestrel HTTPS-eindpuntconfiguratievoor meer informatie over het inschakelen van HTTPS.

Clientconfiguratie

GrpcChannel ondersteunt het maken van gRPC-aanroepen via op maat gemaakte transporten. Wanneer een kanaal wordt aangemaakt, kan het worden geconfigureerd met een SocketsHttpHandler en een aangepaste ConnectCallback. Met de callback kan de client verbindingen maken via aangepaste transporten en vervolgens HTTP-aanvragen verzenden via dat transport.

Voorbeeld van een Unix-domeinsockets verbindingfabriek:

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;
        }
    }
}

Gebruik de aangepaste verbindingsfabriek om een kanaal te creëren.

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

Kanalen die zijn gemaakt met behulp van de voorgaande code verzenden gRPC-aanroepen via Unix-domeinsockets. Ondersteuning voor andere IPC-technologieën kan worden geïmplementeerd met behulp van de uitbreidbaarheid in Kestrel en SocketsHttpHandler.