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:
- Unix-domeinsockets (UDS) is een veelgebruikte IPC-technologie. UDS is de beste keuze voor het bouwen van platformoverschrijdende apps en is bruikbaar op Linux, macOS en Windows 10/Windows Server 2019 of hoger.
- Named pipes worden ondersteund door alle versies van Windows. Benoemde pijpen kunnen goed worden geïntegreerd met Windows-beveiliging, waarmee de clienttoegang tot de pijp kan worden beheren.
- Aanvullende IPC-transporten door IConnectionListenerFactory te implementeren en de implementatie te registreren bij het opstarten van de app.
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:
- communicatie tussen processen met gRPC- en Unix-domeinsockets
- communicatie tussen processen met gRPC en named pipes
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:
- .NET 5 of hoger
- Linux-, macOS- of Windows 10/Windows Server 2019 of hoger
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
.