Sécuriser un service réparti
Les services répartis sont par défaut disponibles uniquement pour l’utilisateur local et pour les processus impliqués dans la session Visual Studio qui l’a activée. Sous ces valeurs par défaut, les considérations de sécurité pour les services répartits ne sont pas différentes d’autres codes exécutés dans ces processus, notamment :
- Du point de vue du modèle de menace, les extensions qui s’exécutent dans le processus Visual Studio sont supposées être entièrement approuvées. Les extensions qui s’exécutent hors processus doivent traiter les appels de service Visual Studio comme franchissant une limite d’approbation.
- Votre code doit valider les arguments aux points d’entrée pour confirmer qu’ils tombent dans des modèles/plages attendus.
- Lors de la lecture des données à partir du disque, pensez à ce que les données aient pu être falsifiées.
- Lors de la réception de données à partir d’un réseau ou d’Internet, soyez prudent lors de l’analyse ou de la désérialisation des données pour éviter les vulnérabilités courantes.
Plusieurs considérations de sécurité supplémentaires critiques s’appliquent lorsque votre service est inscrit avec l’indicateur ProvideBrokeredServiceAttribute.AllowTransitiveGuestClients défini. Le reste de cet article se concentre sur ces considérations.
Case activée d’autorisation pour les opérations sensibles
Acquisition du service d’autorisation
Votre service réparti doit avoir un constructeur qui prend un AuthorizationServiceClient paramètre. L’argument doit être stocké dans un champ et supprimé dans la méthode de Dispose() votre service.
class Calculator : ICalculator, IDisposable
{
private readonly AuthorizationServiceClient authorizationService;
internal Calculator(AuthorizationServiceClient authorizationService)
{
this.authorizationService = authorizationService;
}
public void Dispose()
{
this.authorizationService.Dispose();
}
}
La fabrique de services que vous proffer modifiez légèrement pour prendre en charge ce nouveau paramètre. Au lieu de fournir une BrokeredServiceFactory méthode IBrokeredServiceContainer.Proffer , fournissez un AuthorizingBrokeredServiceFactory délégué. Ce délégué reçoit le AuthorizationServiceClient message que vous devrez transmettre à votre service réparti.
Cette modification de votre code proffer peut ressembler à ceci :
container.Proffer(
CalculatorService,
- (moniker, options, serviceBroker, cancellationToken) => new ValueTask<object?>(new CalculatorService()));
+ (moniker, options, serviceBroker, authorizationService, cancellationToken) => new ValueTask<object?>(new CalculatorService(authorizationService)));
Utilisation du service d’autorisation
Toute opération qui peut divulguer des informations sensibles ou muter l’état de l’utilisateur doit être case activée avec le service d’autorisation à l’aide AuthorizationServiceClient.AuthorizeOrThrowAsyncde .
Pour affirmer que l’appelant est le propriétaire du code (la même identité que l’opérateur de l’hôte Live Share), ce code peut être utilisé :
private static readonly ProtectedOperation ClientIsOwner = WellKnownProtectedOperations.CreateClientIsOwner();
public ValueTask ResetOperationCounterAsync(CancellationToken cancellationToken)
{
// Resetting the counter should only be allowed if the user is the owner.
await this.authorizationService.AuthorizeOrThrowAsync(ClientIsOwner, cancellationToken);
// Proceed with the operation.
this.operationCounter = 0;
}
Différents autres niveaux d’autorisation sont définis dans la WellKnownProtectedOperations classe.
Toutes les case activée d’autorisation sont toujours approuvées lorsque le client de service s’exécute sur le même ordinateur et le même compte d’utilisateur. Ils sont également approuvés pour un invité Live Share qui fonctionne sous le même compte Microsoft que l’hôte.
Lorsque l’opération demandée n’est pas autorisée, AuthorizeOrThrowAsync lève un UnauthorizedAccessException. L’hôte Live Share peut avertir le propriétaire de la tentative ayant échoué, en donnant à l’hôte la possibilité d’accorder l’autorisation nécessaire pour terminer l’opération si celle-ci ProtectedOperation est reconnue afin qu’une tentative ultérieure sur le client réussisse.
Le AuthorizationServiceClient cache toutes les case activée d’autorisation localement afin que les case activée d’autorisation répétées soient rapides. Si le jeu d’autorisations d’un utilisateur change (par exemple, l’hôte Live Share modifie les autorisations pour l’invité), le cache local est automatiquement vidé.
Consommation d’autres services réparti
Lorsqu’un service réparti lui-même nécessite l’accès à un autre service réparti, il doit utiliser celui IServiceBroker fourni à sa fabrique de services. Il ne doit pas utiliser le service broker global, car cela n’est pas conscient du contexte de cette instance de service répartie particulière et de l’autorisation que son client doit activer et appeler d’autres comportements.
Si notre service de calculatrice avait besoin d’autres services répartiteurs pour implémenter son comportement, nous modifierions le constructeur pour accepter un IServiceBroker:
internal class Calculator : ICalculator
{
private readonly IServiceBroker serviceBroker;
private readonly AuthorizationServiceClient authorizationService;
internal class Calculator(IServiceBroker serviceBroker, AuthorizationServiceClient authorizationService)
{
this.serviceBroker = serviceBroker;
this.authorizationService = authorizationService;
}
}
Ce paramètre supplémentaire aura un impact sur le code de proffering de votre fabrique de services :
container.Proffer(
CalculatorService,
(moniker, options, serviceBroker, authorizationService, cancellationToken)
- => new ValueTask<object?>(new CalculatorService(authorizationService)));
+ => new ValueTask<object?>(new CalculatorService(serviceBroker, authorizationService)));
Disponibilité limitée du service réparti
Lorsque le client de votre service réparti est un invité Live Share (sous un compte différent du propriétaire de l’hôte), votre service broker contextuel active uniquement d’autres services répartiteurs qui ont également défini l’indicateur AllowTransitiveGuestClients comme précaution de sécurité. Les tentatives d’activation d’un service répartiteur non éligible lèvent un UnauthorizedAccessException.
Si votre service réparti nécessite un autre service réparti qui ne dispose pas de l’indicateur AllowTransitiveGuestClients , vous pouvez utiliser le répartiteur de services globaux pour l’obtenir, mais il doit considérer que les services répartits obtenus à partir de celui-ci n’ont aucune idée qu’un invité non approuvé est le client final. Vous devez suivre les mêmes précautions que celles fournies dans la section suivante concernant l’appel d’autres services VS ou d’autres API.
En savoir plus sur l’utilisation des services répartités.
Consommation d’autres services VS ou d’autres API
L’appel de services Visual Studio standard, de bibliothèques tierces ou d’API .NET standard est autorisé dans les services réparti qui sont exposés aux invités Live Share, mais ces appels doivent être écrits avec soin et toutes les entrées validées en premier.
Les chemins d’accès ou URL de fichier doivent être soigneusement case activée pour s’assurer qu’ils sont valides et se trouvent dans les sous-chemins attendus auxquels l’invité a l’autorisation d’accéder.
Par exemple, si votre service réparti autorise la lecture ou l’écriture dans des fichiers en fonction d’un chemin d’accès, le chemin d’accès doit être case activée sous la solution ouverte et que l’invité dispose réellement d’autorisations d’écriture le cas échéant.
La validation correcte des chemins d’accès aux fichiers peut être difficile à prendre en compte ..
et d’autres moyens de le faire ressembler à un chemin commence par le préfixe approprié, puis échappez le répertoire de solution autorisé.
Utilisez la AuthorizationServiceClient section ci-dessus comme il convient pour affirmer que le client dispose d’une autorisation avant d’appeler une API qui n’a pas sa propre autorisation case activée s intégrées. Seuls les services répartités intégrés à Visual Studio doivent être supposés contenir leurs propres case activée d’autorisation, et cela s’appuie sur l’acquisition de ces services répartits à l’aide du répartiteur de services contextuels, comme décrit dans la section ci-dessus.
Toutes les autres API, y compris les services Visual Studio non répartis ou les services répartités obtenus avec le répartiteur de services global, peuvent s’exécuter comme vous les dirigez sans tenir compte du niveau d’autorisation de votre invité Live Share, ce qui rend votre propre autorisation case activée critique pour protéger la sécurité de l’hôte Live Share.
Évitez d’exposer des fonctionnalités de votre service répartiteur qu’un autre service réparti visual Studio expose déjà au fur et à mesure qu’il augmente la surface d’attaque.
Partage de l’état entre les instances de service réparties
Lorsque votre service réparti nécessite un partage d’état entre plusieurs instances du service, ces données sont exposées potentiellement à plusieurs utilisateurs avec différents jeux d’autorisations. Il devient essentiel pour votre service réparti de protéger ces données sur ces utilisateurs. Utilisez le modèle STRIDE pour vous aider à identifier, classer et finalement atténuer les menaces.
Vous pouvez décider de traiter votre état partagé comme approuvé et, par conséquent, lui accorder l’autorisation de faire ce qu’il doit faire en interne (par exemple, accéder aux services VS ou utiliser le service broker global). Dans ce cas, il devient la responsabilité d’une instance de service répartie individuelle de protéger les appels effectués dans son état partagé pour s’assurer que toutes les entrées sont appropriées en fonction des autorisations de son propre utilisateur à l’aide du service d’autorisation.
L’outil Microsoft Threat Modeling Tool peut être un outil utile pour sécuriser votre état partagé et vos utilisateurs.