Il existe une fonction de la plateforme Windows Server 2003 qui permet d'ouvrir une session de logon pour un compte du domaine sans mot de passe. Pas mal! De mes tests, ca marche aussi sur Windows Vista.

Cette fonction s'appuie sur S4U2Self (S4U-to-Self) de la famille d'extensions Kerberos Windows (S4U ou Service-for-User), et on la désigne couramment du terme "transition de protocole". En quoi l'ouverture d'une session de logon sans mot de passe est-elle une transition de protocole? En rien. C'est plutôt qu'elle va permettre la fameuse transition de protocole, qui doit être faite par une application. Une telle application, disons une passerelle, va authentifier l'utilisateur via un protocole (par exemple authentification client SSL/TLS) puis va ouvrir une session de logon pour cet utilisateur, ce qui va lui permettre d'accéder aux ressources distantes via Kerberos (plus précisément une autre extension Windows dite S4U2Proxy) pour le compte de l'utilisateur. La "transition" du premier protocole vers Kerberos, c'est l'application qui l'effectue, pas le système.

Cette transition pourrait être faite sans S4U2Self, mais dans ce cas elle nécessiterait que l'application connaisse les mots de passe des utilisateurs. Pour ce faire elle pourrait les obtenir via une authentification "basic", ou tout simplement en avoir une liste. La transition de protocole facilite donc la mise en œuvre de passerelles frontales qui permettent l'accès à des services ou ressources "backend" en Kerberos, sans que ces passerelles n'aient connaissance des mots de passe des utilisateurs. Le scenario cible est celui d'une organisation ayant déployé un domaine Active Directory avec Kerberos, et souhaitant permettre l'accès à des ressources en extranet avec une authentification client SSL/TLS par certificat.

Ouvrir une session de logon sans connaitre le mot de passe du compte? Heureusement (ou bien évidemment) certaines conditions d'appliquent:

  • Le compte du domaine (autrement dit l'identité) qui effectue l'opération doit être approuvé pour la transition de protocole. Plus précisément, il s'agit de la configuration suivante au niveau du compte: "Trust this user for delegation to specified services only" et "Use any authentication protocol". Si la passerelle s'exécute avec un compte utilisateur dédié du domaine, c'est ce compte auquel il faudra faire confiance pour la transition de protocole. Si la passerelle s'exécute avec un compte built-in (Network Service, ou Local System), l'approbation pour la transition de protocole sera attribuée au compte machine du domaine.
  • Le TGT Kerberos "forwardable" ainsi obtenu ne permet d'obtenir ensuite un ticket de service Kerberos (via S4U2Proxy cette fois) que pour les services qui figurent dans la liste A2D2 (Allowed-to-delegate-to). Chaque identité approuvée pour transition a sa propre liste de contraintes A2D2.
  • Le compte de l'utilisateur pour lequel l'ouverture de session de logon sans mot de passe s'effectue ne doit pas être un compte "sensitive and cannot be delegated". Les comptes Active Directory peuvent ainsi être configurés pour interdire leur impersonation.
  • Le code de la passerelle effectuant l'opération doit faire partie de la Trusted Computing Base, autrement dit avoir le privilège SeTcbPrivilege.

Dans ses articles sur la transition de protocole (http://msdn.microsoft.com/msdnmag/issues/03/04/SecurityBriefs/ et plus récemment http://msdn.microsoft.com/msdnmag/issues/07/01/SecurityBriefs/default.aspx?loc=fr – maintenant disponible en Français J) Keith Brown analyse le trade-off entre une passerelle qui connait les mots de passe de l'utilisateur et une passerelle s'appuyant sur la transition de protocole. Il semble que la transition de protocole l'emporte de par la contrainte de délégation (les services cible doivent figurer sur la liste A2D2) qui limiterait les dégâts en cas de compromission du service. Pour ma part, je pense qu'une analyse au cas par cas est nécessaire. Dans son article d'avril 2004, Keith Brown mentionne qu'en théorie, la transition de protocole peut permette l'accès aux ressources distantes alors que l'accès aux ressources locales n'est pas possible. Cela m'a pris un moment pour percuter sur cette remarque anodine qui mérite explication.

Que ce passe-t-il lors d'une transition de protocole?

L'application invoque LsaLogonUser pour ouvrir une session de logon sans connaitre le mot de passe de l'utilisateur. Le système contacte le contrôleur de domaine via S4U2Self pour obtenir un TGT Kerberos pour l'utilisateur. Le système crée une session de logon Windows à laquelle est rattaché le TGT Kerberos. L'application peut maintenant impersoner la session de logon Windows pour accéder à des ressources locales, ou tenter d'accéder à des ressources ou services distants. Lors de l'accès à une ressource distante, le système obtient un ticket de service Kerberos auprès du contrôleur de domaine via S4U2Proxy. Le ticket de service permet d'authentifier l'utilisateur sur la machine distante et d'accéder à la ressource.

Que se passe-il si l'identité de l'application (compte de machine ou d'utilisateur du domaine) n'est pas approuvée pour la transition de protocole?

Dans ce cas, le contrôleur de domaine, via S4U2Self, renvoi bien un TGT Kerberos, mais celui-ci n'est pas "forwardable". Le système (dans le cas où l'application fait partie du TCB) crée une session de logon de niveau impersonation à laquelle est rattaché le TGT Kerberos. Apres impersonation, l'accès aux ressources locales est possible. Cependant un accès aux ressources distantes n'est pas possible parce que le TGT n'étant pas forwardable l'obtention d'un ticket de service via S4U2Proxy échouerait (le système ne le tente même pas).

Que se passe-t-il si l'application ne fait pas partie du TCB?

Dans ce cas, le TGT Kerberos obtenu via S4U2Self est bien forwardable (l'identité est approuvée pour transition de protocole), mais la session de logon Windows est de niveau identity. L'accès aux ressources locales n'est pas possible (un jeton de niveau identity est utile pour déterminer les groupes de l'utilisateur, mais ne permet pas l'accès aux ressources auxquelles l'utilisateur aurait droit). Puisque le TGT Kerberos sous jacent est de niveau forwardable, rien n'empêche l'obtention d'un ticket de service via S4U2Proxy tout à fait valide pour un accès distant. Cependant, le système n'est pas censé supporter ce scenario, et la situation est intenable, et c'est la raison pour laquelle elle a été mentionnée "en théorie".

Le tableau suivant illustre la situation:

Compte de service

Jeton

Ticket Kerberos
S4U2Self

Fonctionnel

TCB

Approuvé pour transition

Impersonation

Forwardable

Délégation*
Accès distant

TCB

-

Impersonation

Non forwardable

Impersonation
Accès local

-

Approuvé pour transition

Identity

Forwardable

Identity

Découverte des groupes (autorisation)

-

-

Identity

Non forwardable

Identity

Découverte des groupes (autorisation)

*Via S4U2Proxy – sujet aux contraintes A2D2 et le fait que le compte de l'utilisateur ne soit pas "sensitive and cannot be delegated"

On fera remarquer que la notion de TCB est une notion tout à fait locale. Si vous êtes TCB, vous êtes tout puissant sur la machine en local. Le contrôleur de domaine, cela lui fait une belle jambe que vous soyez TCB ou non. D'ailleurs il ne le sait même pas. La notion d'approbation pour transition est quant à elle une notion du domaine. En local, que votre identité soit ainsi privilégiée pour la transition au niveau du domaine n'a que peu d'importance. Tant que vous n'êtes pas TCB, vous ne pourrez impersoner l'utilisateur (entendu sans connaitre son mot passe) ni accéder pour son compte à ses ressources. Ses ressources locales cela s'entend.

Pour les ressources distantes le fait que le système local (de la passerelle) ne le permet pas non plus ne doit pas être considéré comme une mesure de sécurité quelconque. Ce qui nous amène à la remarque (que vous trouverez évidente) suivante: le trust pour délégation est une fonction extrêmement sensible puisque l'identité du domaine ainsi trustée va pouvoir accéder aux ressources des autres et pour le compte des autres sans connaitre leur mot de passe. Granted, cet accès est contraint aux seules ressources figurant sur la liste A2D2, mais quand même... Il est fortement recommandé dès lors qu'on utilise la transition de protocole de configurer les comptes administrateur (ainsi que ceux qui n'ont pas lieu d'accéder aux services de la passerelle) en "sensitive and cannot be delegated. Malheureusement, Windows Server 2003 ne le fait pas automatiquement.

Je veux pour exemple de la sensibilité de la transition de protocole le scenario suivant: vous avez une machine du domaine dont le compte machine a été trusté pour délégation avec dans la liste A2D2 un serveur de fichiers. Un utilisateur "standard" qui n'a aucun droit sur le serveur de fichier en question ouvre une session de logon interactive sur cette machine et tente d'accéder aux fichiers du serveur de fichiers avec un net use. Non seulement l'accès réussi, mais l'accès se fait avec le compte d'administrateur du domaine. Le redirecteur SMB fait du zèle, et c'est commode! Si ce n'était pas le scenario souhaité, il aurait fallu restreindre et configurer le compte administrateur du domaine en "sensitive and cannot be delegated".

Et le renforcement des services, alors, après cette (longue) explication?

La factorisation des parties sensibles d'une application ou d'un service nécessitant privilèges élevés fait partie des meilleures pratiques de sécurité. Keith Brown l'illustre en factorisant la transition de protocole dans un composant COM+ out-process. La passerelle peut ainsi s'exécuter sans privilège TCB, et la partie du code nécessitant ce privilège (le composant COM+) ne fait pas face au réseau.

Sur Windows Vista et Longhorn Server, on pourra tirer parti des mécanismes de renforcement des services pour une telle passerelle en tant que service Win32. Imaginons que le service s'exécute avec le compte built-in Network Service. Ce compte ne possède pas moins d'une dizaine de privilèges. Hors, parmi ces privilèges, seul celui d'impersoner (impersonation de la session de logon obtenue via la transition de protocole elle-même effectuée par le composant COM+). La première chose qu'on pourra effectuer est la configuration du service pour n'avoir que ce privilège.

Pour permettre l'accès au composant COM+, on pourrait être tenté de rajouter le compte Network Service dans les rôles COM+ définis. Cependant cela donnerait accès à la transition de protocole à l'ensemble du code qui s'exécute en tant que Network Service. Plutôt, on configurera le service pour avoir un SID de service (SIDType=unrestricted, voir https://blogs.technet.com/voy/archive/2007/03/22/per-service-sid.aspx) qu'on pourra utiliser pour contrôler finement l'accès aux ressources du service (le composant COM+ peut être vu comme une ressource sensible du service). On ne peut pas directement rajouter un SID de service dans les rôles COM+ avec le snapin mmc "Component Services" mais on peut utiliser l'indirection d'un groupe local (comme "ProtocolTransitionUsers" par exemple). Dans ce cas, on rajoute le SID de service dans le groupe local qui est lui positionne dans le rôle COM+. La syntaxe à utiliser avec les outils d'administration est "NT SERVICE\<service_name>".

Finalement ou pourra utiliser les règles de restriction réseau (Windows Service Hardening rules) pour restreindre la passerelle aux seules communications réseau dont elle a besoin. Les règles WSH sont mises en place durant l'installation du service, et ne peuvent pas être modifiées par la configuration du pare-feu intégré Windows. Ces règles sont "statiques" et effectives quelque soit la configuration du pare-feu, y compris sa désactivation par un administrateur. Ces règles ne peuvent que restreindre l'accès au réseau par votre service, et en aucun cas elles ne peuvent l'élargir (par rapport à une configuration du pare-feu existante).

Vous vous demandez peut-être pourquoi dans cet exemple je propose un SIDType="unrestricted", plutôt que "restricted", et quelles sont les différences. Un SIDType "unrestricted" permet d'avoir un SID de service qu'on pourra utiliser pour un contrôle et une protection fine des ressources du service. Un SIDType "restricted" fait que, en plus du SID de service, le service s'exécute avec jeton restreint en écriture (concept nouveau sur Windows Vista – voir http://blogs.technet.com/voy/). Un SIDType="restricted" permet, en plus de la protection des ressources du service, une meilleure protection du système contre une compromission éventuelle du service. En ce sens, l'exécution restreinte de votre service en écriture est une mesure de bonne citoyenneté. Malheureusement, cette mesure peut être onéreuse pour le développeur d'un service Win32, car vous devez maitriser précisément l'ensemble des ressources pour lesquelles votre service a besoin d'un accès en écriture. Lorsqu'on utilise des APIs cela n'est pas toujours facile à faire.

Alors, à vos transitions! Et bon renforcement…