4.2. Sécurité et utilisateurs

À l'heure où la sécurité devient un enjeu majeur en raison de l'importance des menaces virales et autres attaques contre les systèmes informatiques et leurs utilisateurs, les systèmes Unix tels que Linux, bien que de conception très ancienne, apparaissent comme avant-gardistes et parfaitement en phase avec le marché.

La sécurité est à présent considérée comme une fonctionnalité essentielle du système d'exploitation, et devient de plus en plus incontournable. De ce fait, il est nécessaire de présenter les concepts de sécurité utilisés par les systèmes Unix et Linux, afin que vous puissiez appréhender les risques et maîtriser tous les principales fonctions de sécurité du système.

Nous verrons donc ces concepts de base dans un premier temps. Puis, nous nous intéresserons à la notion d'utilisateur, qui est à la base de la sécurité sous Unix. Enfin, nous verrons comment cette sécurité est assurée dans le système, en particulier au niveau du système de fichiers.

4.2.1. Généralités

Les systèmes Unix, depuis leurs origines, ont toujours pris en compte les problèmes de sécurité. En particulier, les développeurs d'application Unix ont toujours fait attention à ce que leurs logiciels se comportent relativement bien en termes de sécurité. En pratique, bien que la sécurité des programmes soit loin d'être parfaite, surtout pour les plus anciens, des principes de base ont toujours été respectés, ce qui fait que les applications Unix ne font pas, en règle générale, n'importe quoi avec le système.

Ainsi, il est beaucoup plus facile de faire fonctionner une application Unix dans un contexte de sécurité restreint qu'une application Windows, car les développeurs de ces dernières ont longtemps été habitués à une très grande liberté et ont donc réalisé des applications qui ne peuvent pas être utilisées si elles n'ont pas les pleins pouvoirs. Les applications Unix qui se comportent mal sont donc très rares, ce qui fait que les systèmes Unix peuvent faire peu de cas d'elles et n'ont pas à maintenir une compatibilité ascendante avec elles. Les systèmes Unix ont donc un modèle de sécurité beaucoup plus simple et strict, et n'ont pas à s'embarasser avec des techniques complexes et des circonvolutions insensées telles que la virtualisation de l'ensemble du système pour les applications afin d'assurer un semblant de sécurité tout en permettant la compatibilité ascendante.

Par ailleurs, la sécurité permet de protéger non seulement le système, mais aussi l'utilisateur de ses propres erreurs. En effet, le système est capable de se protéger contre les fausses manipulations de l'utilisateur. Cela peut être extrêmement utile avec les débutants, puisqu'ils peuvent expérimenter à loisir tout en étant sûrs qu'ils ne feront pas de bêtise irrémédiable. Ainsi, ils seront plus sereins et n'auront pas « peur de faire une bêtise ». Mais cela est très utile même pour les utilisateurs chevronnés, car tout le monde peut effectivement faire une erreur !

La sécurité permet également de protéger les données de chaque utilisateur vis à vis des autres. En effet, par défaut, les données d'un utilisateur ne peuvent pas être modifiées par un autre utilisateur. Vous n'aurez donc aucune crainte que vos chères têtes blondes puissent effacer ou détruire par mégarde votre correspondance professionnelle ou l'ensemble des photos de famille...

Enfin, ayant été prise en compte dès le départ, la sécurité sait se rendre très discrète sur les systèmes Unix, et bien que parfaitement fonctionnelle, elle n'ennuie pas l'utilisateur et reste facilement configurable. Ces deux aspects sont fondamentaux, car du coup, l'utilisateur n'a pas la tentation - ni le besoin - de tout désactiver pour faire fonctionner ses applications !

En résumé, la sécurité sous Linux, c'est :

4.2.2. Notion d'utilisateur et d'administrateur

Linux dispose de plusieurs modèles de sécurité mais, historiquement, la sécurité se base sur la notion d'utilisateur. Nous allons donc nous intéresser ici à la notion d'utilisateur, et voir comment cette notion peut être utilisée pour mettre en pratique les contrôles de sécurité du système.

Comme vous le savez sans doute déjà, Linux est un système multi-utilisateurs. Cela signifie que plusieurs personnes peuvent utiliser l'ordinateur simultanément (et pas uniquement les unes à la suite des autres), et que le système se charge de faire respecter la loi entre elles. Le système protège les données de chaque utilisateur des actions que peuvent effectuer les autres utilisateurs. Il veille également à partager équitablement les ressources de la machine entre les utilisateurs, tant au niveau de la puissance de calcul qu'au niveau de la mémoire, du disque, des imprimantes, etc.

Note : Si vous vous demandez comment plusieurs personnes peuvent se partager le clavier et l'écran et ainsi utiliser l'ordinateur en même temps, la réponse est simple : ils ne le peuvent pas. Par contre, il est possible que plusieurs personnes soient connectées à l'ordinateur via le réseau, utilisant d'autres claviers et d'autres écrans (on appelle un couple clavier/écran un « terminal »). Il est de plus théoriquement possible de connecter plusieurs claviers, souris et écrans à une même unité centrale, même si ces configurations sont encore très rares et non standards. Les utilisateurs peuvent également lancer des programmes en arrière plan, et laisser ces programmes tourner même lorsqu'ils ne sont plus connectés à l'ordinateur. Évidemment, cela nécessite que les programmes ainsi lancés ne soient pas interactifs. Autrement dit, ils doivent être capable de fonctionner sans intervention de celui qui les a lancés.

Ne croyez pas que ce dernier cas de situation est extrêmement rare. En effet, le système utilise des tâches qui tournent en arrière plan dans des comptes dédiés et différents du vôtre, afin de prendre en charge certaines fonctionnalité ou de réaliser des opérations de maintenance.

En interne, le système affecte un numéro unique à chaque utilisateur afin de pouvoir l'identifier. Ce numéro d'utilisateur est défini lors de la création de son compte dans le système, et ne peut être modifié par la suite. Ainsi, toute action effectuée dans le système peut être rattachée à un utilisateur particulier. L'utilisation du système requiert donc que chaque utilisateur s'identifie au niveau du système avant toute autre opération. Généralement, cela se fait en indiquant son nom d'utilisateur, que l'on appelle classiquement le « login ». Bien entendu, afin d'éviter qu'un utilisateur puisse usurper l'identité d'un autre utilisateur, le système exige que l'utilisateur fournisse un mot de passe après s'être identifié pour s'authentifier.

La sécurité du système se base alors, lorsqu'une opération est exécutée, sur l'identité de l'utilisateur qui réalise cette commande et sur les droits dont cet utilisateur dispose sur les objets que cette commande doit manipuler. Par exemple, la suppression d'un fichier système ne peut pas être réalisée par un utilisateur lambda, parce que cet utilisateur n'a pas les droits de suppression (ni de modification d'ailleurs, et parfois même de lecture) sur ce fichier.

L'administration du système lui-même revient à la charge d'un utilisateur particulier. Cet utilisateur, classiquement nommé « root », a virtuellement tous les droits sur le système. C'est ce qu'on appelle l'administrateur du système, ou encore le super utilisateur. En interne, le super utilisateur est identifié par le numéro 0, qui lui est réservé. Ainsi, seul l'utilisateur dont le numéro est 0 peut modifier les fichiers de configuration du système.

Note : Bien entendu, travailler sous l'identité du super utilisateur est extrêmement dangereux, car dès lors tous les mécanismes de sécurité du système sont désactivés. Une erreur de manipulation avec cette identité peut donc être fatale et détruire complètement le système ! C'est pour cette raison que la plupart des distributions imposent de définir un compte utilisateur standard en plus du compte root, et que vous ne devriez travailler que sous ce compte. Ce n'est pas une restriction, c'est tout simplement pour votre bien. Ne vous inquiétez pas, comme il l'a déjà été dit plus haut, vous n'avez quasiment jamais besoin des droits administrateurs pour travailler sous Linux, parce que les applications sont en général conçues dès le départ pour être utilisables dans des comptes restreints. Alors n'ayez aucune crainte, et respectez les bonnes manières : ne travaillez jamais sous le compte root.

Les nouveaux utilisateurs de Linux qui ont fait leurs premiers pas en informatique sous Microsoft Windows ont souvent tendance à considérer cette recommandation comme un « faites ce que je dis, pas ce que je fais » et croient donc que les utilisateurs chevronnés ne la respectent pas. Qu'ils se détrompent, la plupart des utilisateurs de Linux respectent cette règle en permanence ! Ce n'est pas parce que ce n'est pas votre habitude que cette recommandation est un « on-dit ». D'ailleurs, elle est tellement importante que certaines distributions désactivent tout bonnement le compte administrateur. Il est donc tout simplement impossible de se connecter sous ce compte, même si l'on est la personne qui a installé le système ! Bien entendu, dans ce cas, les opérations d'administration sont toutes identifiées et nécessitent de fournir le mot de passe administrateur pour être exécutées.

En résumé, les mécanismes de sécurité basés sur la notion d'utilisateur fonctionne selon les principes suivants :

4.2.3. La sécurité au niveau du système de fichiers

Nous avons vu que le noyau contrôlait les droits de l'utilisateur vis à vis des ressources qu'il manipulait pour chaque processus qu'il exécute. En particulier, l'accès à chaque fichier est contrôlé lors de l'ouverture de ce fichier par les processus de l'utilisateur. Ainsi, les données de chaque utilisateur sont protégées par le système, ainsi que les fichiers du système lui-même. De plus, comme l'accès aux périphériques se fait généralement par l'intermédiaire de fichiers spéciaux, les accès aux ressources matérielles sont également contrôlés via les mécanismes de sécurité du système de fichiers. Il est donc important de comprendre comment les systèmes de fichiers gèrent la sécurité.

4.2.3.1. Les droits sur les fichiers

Les systèmes de fichiers définissent, pour chaque fichier, les droits auquel un utilisateur peut prétendre. Ces droits comprennent la possibilité de lire ou écrire un fichier, d'accéder ou non à une ressource ou d'exécuter un programme. En pratique, chaque utilisateur peut définir les droits qu'il veut se donner sur ses propres fichiers, et surtout les droits qu'il veut donner aux autres utilisateurs du système sur ses fichiers. Par exemple, il peut protéger un fichier auquel il tient particulièrement en lecture seule, afin d'éviter de le détruire par inadvertance.

L'administrateur peut également créer un ou plusieurs « groupes » d'utilisateurs, afin que les utilisateurs puissent donner des droits spécifiques aux utilisateurs de ces groupes sur leurs fichiers. En pratique, cela se fait en fixant le groupe propriétaire du fichier, et en fixant les droits spécifiques à ce groupe sur le fichier.

Il est donc possible de définir les droits sur un fichier à trois niveaux différents :

  • au niveau du propriétaire du fichier (par défaut, l'utilisateur qui l'a créé) ;

  • au niveau du groupe propriétaire du fichier (par défaut, les fichiers créés par les utilisateurs appartiennent au groupe « users ») ;

  • au niveau de tous les autres utilisateurs (c'est-à-dire les utilsateurs qui ne sont ni le propriétaire du fichier, ni les utilisateurs du groupe du fichier).

En pratique, les droits des fichiers sont représentés par une série de lettres indiquant les droits de chacun des niveaux que l'on vient de voir. Le droit de lecture est représenté par la lettre 'r' (pour « Read only »), le droit d'écriture par la lettre 'w' (pour « Writeable »), et le droit d'exécution par la lettre 'x' (pour « eXecutable »). Le droit de lecture correspond à la possibilité d'ouvrir et de consulter un fichier, ou de lister le contenu d'un répertoire. Le droit d'écriture correspond à la possibilité de modifier un fichier, ou de créer ou supprimer un fichier d'un répertoire. Enfin, le droit d'exécution correspond à la possibilité d'exécuter un fichier contenant un programme, ou d'entrer dans un répertoire.

Par exemple, la liste des droits sur un fichier lisezmoi.txt appartenant à un hypothétique utilisateur Jean Dupont (dont le login serait jean) se présente comme suit dans la sortie de la commande ls -l lisezmoi.txt (qui, comme on le verra plus loin, permet d'afficher les informations de ce fichier) :

-rw-r--r-- 1 jean users 444 2006-12-10 08:42 lisezmoi.txt

Ce fichier appartient bien à l'utilisateur jean et au groupe users et a une taille de 444 octets. Les droits sont affichés au début de la ligne. Le premier groupe de droit (rw-) indique que l'utilisateur peut lire et écrire le fichier, mais pas l'exécuter. En effet, le tiret (-) indique que le droit d'exécution n'est pas donné. Les deuxième et troisième groupes de droits (r-- tous les deux) indiquent respectivement que les utilisateurs du groupe users et tous les autres utilisateurs n'ont que le droit de lecture. Le premier tiret au début de la ligne signifie que le fichier n'est pas un répertoire, dans le cas contraire il serait remplacé par la lettre 'd' (pour « Directory »).

Note : On notera que le fait d'avoir le droit d'écriture sur un fichier ne donne pas le droit de le supprimer (cependant, on peut le vider !). Pour cela, il faut avoir le droit d'écriture sur le répertoire contenant ce fichier. De même, il est possible d'obtenir la liste des fichiers d'un répertoire sans pouvoir s'y déplacer, ou encore de modifier un fichier sans pouvoir le lire. Comme on le voit, les droits d'accès aux fichiers et aux répertoires sont très souples.

Par défaut, lors de la création d'un fichier par un utilisateur, les droits de lecture et d'écriture sont donnés à cet utilisateur, et seuls les droits de lecture sont donnés au groupe du fichier et aux autres utilisateurs. Ainsi, tout le monde peut lire le fichier, mais seul son propriétaire peut le modifier. Cela correspond à l'usage classique sur un système multiutilisateur où les utilisateurs se connaissent et n'ont pas de fichiers confidentiels. Dans le cas contraire, l'utilisateur devra retirer les droits de lecture pour les autres utilisateurs (nous verrons comment faire cela plus loin).

Note : Comme vous pouvez le constater, les droits d'exécution ne sont pas donnés par défaut, même pour les fichiers binaires. Ainsi, le système ne se base pas sur le contenu du fichier, et, comme on l'a vu, encore moins sur son extension, pour déterminer si un fichier est exécutable ou non. Pour qu'un fichier soit exécutable, il faut lui donner explicitement les droits d'exécution !

Cela n'a l'air de rien, mais cette contrainte est un facteur de sécurité extrêmement important de nos jours. En effet, la plupart des virus de mail ne sont en fait rien d'autres que des chevaux de Troie transférés en pièce jointe, et qui ne peuvent s'exécuter que si l'utilisateur les lance explictement. Sous Windows, le simple fait de double-cliquer sur une pièce jointe dont l'extension est exécutable lance effectivement le programme (c'est pour cela que les pièces jointes de ce type sont souvent filtrées maintenant). Sous Unix et Linux, cela ne fait strictement rien, même si c'est un programme, car pour l'exécuter, il faut d'abord l'enregistrer, modifier ses droits d'exécution explicitement, et l'exécuter. Ainsi, un utilisateur non averti n'a quasiment aucune chance de lancer un tel cheval de Troie par mégarde...

4.2.3.2. Notion d'ACL

La notion de groupe d'utilisateurs que l'on vient de voir est généralement utilisée pour définir des classes d'utilisateurs, et attribuer un peu plus de privilèges que les utilisateurs normaux n'en disposent aux utilisateurs de ces classes, selon les nécessités.

Par exemple, l'administrateur peut n'autoriser l'accès au lecteur de CD-ROM qu'à quelques utilisateurs, en modifiant les droits sur le fichier spécial de périphérique permettant d'accéder au lecteur de CD-ROM. Premièrement, il crée un groupe d'utilisateurs « cdrom » et affecte le fichier spécial de périphérique du CD-ROM à ce groupe. Ensuite, il restreint les droits d'accès à ce fichiers pour que seuls les membres de ce groupe puisse y accéder. Enfin, il place les utilisateurs autorisés à accéder au CD-ROM dans le groupe en question.

Toutefois, cette technique est relativement contraignante pour les utilisateurs, parce que la création d'un nouveau groupe d'utilisateurs est une opération privilégiée que seul l'administrateur du système peut réaliser d'une part, et parce qu'un utilisateur ne peut changer le groupe propriétaire d'un fichier que vers un groupe dont il fait lui-même partie, d'autre part. Enfin, un même fichier ne peut appartenir qu'à un seul groupe, et créer un groupe pour rassembler tous les utilisateurs de deux groupes n'est pas une solution très élégante. C'est pour cette raison que les systèmes de fichiers modernes intègrent la notion d'ACL (abréviation de l'anglais « Access Control List », c'est-à-dire les listes de contrôle d'accès).

Les ACL sont des listes d'informations décrivant les droits d'accès aux fichiers. Avec les ACLs, les droits ne sont pas définis pour chaque catégorie d'utilisateurs (propriétaire, groupe et autres), mais de manière plus fine, fichier par fichier, pour des utilisateurs et des groupes variés. De plus, les ACLs peuvent être manipulées par le propriétaire du fichier, donc sans avoir recours aux droits administrateur, ce qui résoud le problème des groupes.

Note : La contrepartie de cette facilité est qu'il n'est pas toujours évident de contrôler la sécurité de manière globale avec les ACLs, puisqu'on ne peut plus retirer les droits d'un utilisateur sur tout un jeu de fichiers appartenant à un même groupe simplement en le supprimant de la liste des utilisateurs de ce groupe. Il n'est donc pas recommandé d'utiliser les ACLs pour définir les droits sur les fichiers systèmes, et de ne conserver cette fonctionnalité que pour que les utilisateurs puissent définir des droits plus fins sur leurs propres fichiers.

4.2.3.3. Les attributs spéciaux des fichiers

Nous avons vu dans les sections précédentes que la notion d'utilisateur, couplée avec les droits sur les fichiers, permettait au noyau de fournir une sécurité sur les fichiers des utilisateurs et du système. En particulier, les processus lancés par l'utilisateur s'exécutent en son nom, et sont soumis aux mêmes restrictions que l'utilisateur qui les a lancés.

Il existe toutefois quelques programmes qui doivent faire exceptions à cette règle. Il s'agit généralement de programmes qui ont besoin des droits administrateurs pour réaliser une opération de reconfiguration sur le compte de l'utilisateur. C'est en particulier le cas de quelques commandes systèmes (comme passwd, qui permet de changer de mot de passe), qui peuvent être lancées par les utilisateurs mais qui doivent s'exécuter au nom du système (dans le compte root).

Ces programmes sont bien entendu réalisés avec un grand soin, de telle sorte que l'on peut être sûr que l'utilisateur ne peut pas les utiliser dans le but de réaliser une opération à laquelle il n'a pas droit dans le compte administrateur. De ce fait, il est impossible à un utilisateur de violer les règles de sécurité du système.

Pour parvenir à ce comportement, les systèmes de fichiers utilisent des attributs spéciaux sur les fichiers exécutables de ces programmes. Ces attributs viennent en complément des droits d'accès que l'on a présentés dans les sections précédentes.

Le premier de ces attributs est le bit « setuid » (qui est l'abréviation de l'anglais « SET User IDentifier »). Il ne peut être placé qu'au niveau des droits du propriétaire sur le fichier. Il permet d'indiquer que le fichier est exécutable, et que lorsque le programme qu'il contient est lancé par un utilisateur, le processus correspondant s'exécute avec les droits du propriétaire du fichier et non pas avec ceux de l'utilisateur qui l'a lancé. Cependant, le système conserve tout de même le numéro de l'utilisateur réel qui a lancé le processus en interne, ce qui fait que le programme peut savoir par qui il a été lancé et au nom de qui il s'exécute effectivement.

Au final, un processus dispose donc toujours de deux numéros d'utilisateur :

  • le numéro de l'utilisateur réel (« real user id » en anglais), qui est le numéro de l'utilisateur qui a lancé le programme ;

  • le numéro de l'utilisateur effectif (« effective user id » en anglais), qui est le numéro de l'utilisateur avec les droits duquel le processus fonctionne.

Le bit setuid permet donc simplement d'affecter le numéro du propriétaire du fichier au numéro d'utilisateur effectif du processus lorsqu'il est lancé. Le fait de conserver le numéro de l'utilisateur réel permet au programme de réaliser des vérifications de sécurité additionnelles. Par exemple, la commande passwd, qui permet de changer le mot de passe d'un utilisateur, a besoin des droits de l'utilisateur root pour enregistrer le nouveau mot de passe. Il dispose donc du bit setuid pour que tous les utilisateurs puissent l'utiliser. Cependant, même s'il s'exécute au nom de l'utilisateur root, il ne doit pas permettre à n'importe qui de changer le mot de passe des autres utilisateurs : seul l'utilisateur root a le droit de faire cette opération. Il utilise donc le numéro de l'utilisateur réel qui a lancé la commande pour savoir si c'est bien l'utilisateur root qui l'a lancé.

Le bit setuid est l'attribut le plus couramment utilisé, essentiellement pour certaines commandes systèmes. Il est représenté par la lettre 's' (comme « Setuid »), et il remplace le droit d'exécution ('x') des fichiers pour le propriétaire des fichiers (rappelons que le bit setuid implique que le fichier est exécutable). Il n'a aucune signification pour les répertoires.

Le deuxième attribut spécial est le bit « setgid » (qui est l'abréviation de l'anglais « SET Group IDentifier »). Ce bit fonctionne un peu de la même manière que le bit setuid, à ceci près qu'il fixe le numéro de groupe effectif du processus lancé à celui de son fichier exécutable. Cet attribut est également représenté par la lettre 's', et remplace le droit d'exécution ('x') pour les utilisateurs du groupe auquel appartient le fichier exécutable. De plus, et contrairement au bit setuid, ce bit a une signification pour les répertoires. Un répertoire disposant du bit setgid permet de faire en sorte que tous les fichiers qui sont créés dans ce répertoire se voient automatiquement attribués le même groupe que le répertoire. Ce bit est relativement peu utilisé.

Enfin, il existe un troisième attribut, le bit « sticky ». Cet attribut remplace l'attribut exécutable pour les autres utilisateurs que le propriétaire du fichier ou du répertoire et les membres du groupe auquel il appartient. Contrairement aux bits setuid et setgid, il est représenté par la lettre 't' (pour « sTickky »). Sa signification est assez spéciale : elle permet de faire en sorte que les programmes restent chargés en mémoire après leur terminaison, ce qui permet de les relancer plus rapidement. Afin de ne pas consommer la mémoire de manière permanente, le code du programme est placé automatiquement dans le swap s'il n'est toujours pas relancé après un certain temps, mais même dans ce cas, tous les calculs de chargement sont déjà effectués. Le lancement des programmes marqués de ce bit sera donc toujours accéléré. Sachez cependant ne pas abuser du bit sticky car la mémoire (même virtuelle) est encore une ressource rare. Pour les répertoires, sa signification est totalement différente : elle permet de restreindre les droits des utilisateurs sur les répertoires ayant ce bit positionné. Ce bit fait en sorte que même si un utilisateur dispose des droits d'écriture sur le répertoire, il ne peut pas supprimer tous les fichiers de ce répertoire. Les seuls fichiers qu'il est autorisé à supprimer sont ses propres fichiers. Bien entendu, il est toujours possible d'ajouter des fichiers dans le répertoire en question.

Les questions qui se posent évidemment sont les suivantes. Est-ce qu'un particulier a besoin de tout cela ? Ces fonctionnalités ne sont-elles pas réservées aux serveurs ? Est-ce qu'on ne risque pas de perdre beaucoup de temps pour définir les droits pour chaque utilisateur et pour chaque ressource du système ? La gestion de la sécurité ne consomme-t-elle pas trop de ressources ? Ces questions sont légitimes. Heureusement, les réponses sont simples. Rappelons pour commencer qu'il est très intéressant, même pour un particulier, de disposer de ces fonctionnalités. En effet, la sécurité permet tout simplement de protéger le système contre les erreurs des utilisateurs, voire l'utilisateur lui-même de ses propres erreurs. Ainsi, avec Linux, on peut faire n'importe quoi, on est certain que le système restera intact. Cette sécurité est telle que, finalement, Linux est justement le système d'exploitation idéal pour apprendre l'informatique à quelqu'un : savoir que le système protège tout ce qui est important permet aux débutants de prendre des initiatives sans crainte. Quant aux éventuels revers de médaille, ils sont absents : la gestion de la sécurité ne consomme quasiment aucune ressource, et sa configuration est élémentaire. Toutes les distributions s'installent de telle sorte que le système se protège des utilisateurs, et que ceux-ci soient indépendants les uns des autres. En pratique, les utilisateurs n'ont tout simplement pas à se soucier de tous ces attributs de fichiers. Même l'administrateur laisse souvent les attributs par défaut définis par les distributions, car ils correspondent à la majorité des besoins de sécurité.