Introduction

Le .NET Framework est un composant logiciel, qui doit être installé sur un système d'exploitation Microsoft Windows afin de permettre l'exécution d'applications .NET, celles-ci étant exécutées, par ce que l'on peut qualifier de « Machine Virtuelle » : le CLR (Common Language Runtime). La spécificité d'une application .NET, et que celle-ci n'est pas compilée directement en langage machine, mais en un langage intermédiaire : MSIL (Microsoft Intermediate Language). Lors de l'exécution de votre application (quelque soit le langage utilisé lors du développement), le CLR va, via un compilateur JIT (Just-In-Time), traduire le code MSIL en code machine et ce de manière optimisée pour l'hôte sur lequel il s'exécute.

Quelque soit le langage que vous utiliserez pour développer votre application .NET, vous manipulerez ce que l'on appel du code managé. Le code .NET est dit managé, car sauf cas spécifique (où vous spécifiez que vous voulez développer en mode « unsafe ») vous n'avez pas à vous préoccuper de la gestion de la mémoire et de la sécurité. Le CLR s'en charge pour vous.

Dans un premier temps, nous donnerons quelques définitions quant au vocabulaire utilisé dans la suite de cet article. Puis dans une deuxième partie, nous verrons comment le CLR assure la sécurité lors de l'exécution d'une application .NET et surtout comment créer des règles de sécurité au sein du Framework .NET depuis sa version 2.0. En troisième partie, nous verrons les nouveautés apportées par le Framework 3.5 en matière de sécurité. Nous parlerons notamment des nouveaux algorithmes de cryptage (arrivés avec Windows Vista). Un autre nouveauté du Framework 3.5, la programmation par « Add-in », ne sera pas évoquée dans cet article, le sujet méritant à lui seul un article complet.

Vocabulaire

Assemblage (ou Assembly)

Un assemblage .NET correspond aux .exe et .dll que nous connaissions dans les autres langages de développement. Il peut être unique ou composé de module. Un assemblage peut être constitué d'un ou plusieurs modules. Dans tous les cas, l'assemblage contiendra un module appelé « module principale ». Les autres modules, dits satellites, seront d'extension « .netmodule ». Il est à noter ici que Visual Studio ne permet pas la création d'assemblages pluri-modulaires.

Domaine d'application

Les domaines d'application sont responsables, entre autre, de l'isolation d'une application .NET au sein du CLR. En effet, une application .NET étant exécutée au sein du CLR, il est nécessaire de simuler l'isolation que nous connaissions avec la coquille logicielle « processus ». Nous développeront plus en détails leurs rôles dans la suite.

CLR / CAS

CLR, pour Common Language Runtime : c'est le moteur d'exécution d'application de la plateforme .NET. Ses rôles principaux sont la gestion de la mémoire et la sécurité d'exécution des applications .NET. Mais c'est aussi le CLR qui va assurer le débug des applications, ainsi que la compilation du code MSIL en code natif « à la volée » via le JIT-Compiler (Just In Time Compiler, Compilateur Juste à temps).

CAS, pour Code Access Security. C'est l'agent de sécurité de le CLR. Nous détaillerons ses rôles dans le paragraphe suivant.

Sandboxing (Bac à sable)

Le sandboxing est une technique qui consiste à exécuter une application avec des privilèges restreins afin de pouvoir isoler celle-ci est prévenir de tout risque de sécurité majeur. Il est fréquent d'exécuter le code d'une bibliothèque de classe en SandBox, notamment dans le cas d'application web, évitant ainsi tout risque d'un point de vue sécuritaire.

Après ces quelques notions de vocabulaire, nous allons nous intéresser à la sécurité d'exécution des applications .NET au sein du CLR.

Code Access Security : l'agent de sécurité de le CLR !

On pourrait imager CAS en prenant l'exemple d'un pare-feu. Ce dernier à pour mission de filtrer les paquets TCP/IP transitant sur un réseau et de bloquer ceux n'étant pas conforme aux stratégies de sécurité qui ont été établies. Le CAS a exactement le même rôle, mais au sein de le CLR. Il analyse le code vos applications .NET dans le but de remplir trois objectifs :

Restreindre ce qu'un code peut réaliser

Le principe de code managé sur lequel repose les fondements de la plateforme .NET a pour principale conséquence de limiter la portée d'une action d'un programme et ce, afin de préservé l'intégrité et la sécurité des ressources et données au sein du système d'exploitation qui héberge l'application. C'est le premier rôle que va assurer le CAS, en contrôlant à tout moment l'exécution d'une application et terminant celle-ci de force en cas de non respect des règles de sécurité. Nous verrons bien entendu dans la suite comment définir ces règles.

En d'autres termes, CAS va fournir un sandbox efficace pour vérifier, isoler et restreindre le code. Cela va passer par une vérification des types (langages type-safe) évitant que le code accède à la mémoire de manière arbitraire, mais aussi par l'isolation des processus dans leur propre domaine d'application (AppDomains), et enfin un contrôle des permissions permettant la réalisation d'un contrôle d'accès aux opérations et ressources sensibles du système. Pour cela, CAS réalise ce que l'on appel en anglais un « walk on the stack » (parcours de la pile d'appel du programme) afin de contrôler les opération qui s'exécutent.

Déterminer quel code peut appeler votre code

Tout assembage .NET, lors de son exécution est chargée dans ce que l'on appel un « domaine d'application » (ou AppDomain) qui lui est propre, ce qui permet d'isoler les applications les unes des autres. Pour une application classique (non .NET), cette isolation est en générale réalisée par les processus, mais sous la plateforme .NET, c'est au sein du CLR que sont exécutées ces dernières. Afin d'assurer une isolation digne de celle d'un processus, le CLR charge le CAS de vérifier l'application afin de s'assurer d'exécuter un code sécurisé à 100% (dit code « type-safe ») et surtout d'empêcher toute application ayant des moindres privilèges d'en utiliser une autre afin de parvenir à ses fins.

Identifier un code

Pour s'exécuter au sein du CLR, un assemblage doit être identifié par le CAS, que ce soit au moyen d'une signature numérique, d'un nom fort, ou encore d'un simple hash. Cette identification va permettre d'éviter de ré-analyser une application à chaque fois qu'elle s'exécute. La plupart du temps, un assemblage sera analysé lors de son premier lancement ou lors de son chargement dans le GAC (Global Cache Assembly), puis sera identifiée comme sécurisée au sein du CLR, par l'intermédiaire de sa signature. Mais attention, d'une manière ou d'une autre, CAS veille toujours ! En effet, CAS sera capable de réagir très rapidement en cas de non respect d'une règle élémentaire de sécurité, même pour un code identifié comme type-safe. Vous avez sûrement remarqué que les applications .NET sont légèrement plus lentes à se lancer que les applications classiques. La vérification de l'intégrité du code est en partie responsable de ce ralentissement. Microsoft à d'ailleurs annoncé que les équipes de développement du CLR travaillaient actuellement sur l'amélioration de la vitesse de lancement des applications, notamment, en améliorant l'application des stratégies de sécurité par CAS.

Maintenant que nous avons compris le principe de vérification du code managé .NET par le CAS, nous allons voir comment définir des règles de sécurité sur nos machines.

Création de règle d'exécution d'assemblie .NET:

La création et la configuration de stratégie de sécurité pour nos assemblages .NET vont se faire dans une MMC (Microsoft Management Console). Commençons par ouvrir le gestionnaire MMC :

Une fois notre console MMC ouverte, nous allons pouvoir y ajouter un composant logiciel enfichable (Snap in). Pour cela, rendez vous dans le menu Fichier et choisissez l'option, comme ci-dessous (ou Ctrl+M) :

Puis ajoutez le composant « .NET Framwork 2.0 Configuration » :

Non, il ne s'agit pas d'une erreur de ma part, les outils de configuration du Framework n'ayant pas changé entre les versions 2.0 et supérieures, nous utilisons toujours l'outil de configuration de la version 2.0.

Naviguez dans votre console jusqu'au Poste de travail. Vous avez alors plusieurs actions possibles :

C'est évidemment la section stratégie de sécurité du Runtime qui va nous intéresser ici. En effet, c'est cet outil qui va nous permettre d'affecter les autorisations d'accès aux ressources protégées à nos assemblages. Nous avons alors accès à plusieurs menus :

  • Augmenter le niveau de confiance d'un assemblage
  • Ajuster la sécurité de la zone
  • Evaluer l'assemblage
  • Créer un package de déploiement
  • Réinitialiser tous les niveaux de stratégies

Passons à présent à une description rapide de ces menus.

Niveau de confiance d'un assemblage

Le niveau de confiance d'un assemblage va définir à quelles ressources système un assemblage peut accéder.

Afin de modifier le niveau de confiance d'une application, nous devons au préalable lui attribuer un nom fort (strong name) et ce à l'aide de l'outil « sn.exe » disponible dans l'Invite de commande de Visual Studio :

C:\> sn –k MaPaireDeClef.snk

Key pair written to MaClef.snk

C:\> sn –p MaPaireDeClef.snk MaClefPublique.snk

Public key written to MaClefPublique.snk

C:\> sn –i MaPaireDeClef.snk MonApplicationDotNET.exe

Key pair installed into 'MonApplicationDotNET.exe'

La première ligne permet la création d'une paire de clefs aléatoire et de les stocker dans « MaPaireDeClef.snk ». La deuxième ligne permet de générer une clé public (celle capable d'identifier votre application .NET) est de la stocker dans le fichier MaClefPublic.snk. C'est cette clé que vous diffuserez avec votre application. Enfin, la dernière ligne nous permet d'attribuer un nom fort à l'assemblage .NET « MonApplicationDotNET.exe ».

Rappel :

Un assemblage, pour être chargé dans le GAC (Global Assembly Cache), dont être ce que l'on appel un assemble possédant un « nom fort », c'est-à-dire signé numériquement.

Une fois votre assemblage signé, vous pouvez définir le niveau de confiance que le CLR doit lui accorder. Pour cela, revenons à la console MMC citée plus haut. Il suffit de choisir le menu « Augmenter le niveau de confiance d'un assemblage », de rechercher l'assemblage avec lequel l'on souhaite travailler, puis de choisir son niveau de confiance :

Le découpage de la sécurité en zone

Un assemblage .NET ne va pas être exécuté avec le même niveau de confiance selon la zone depuis laquelle il est lancé. Il existe en effet un découpage en trois zones :

  • Poste de travail : l'assemblage est exécuté avec une confiance totale (Full trust) et a accès, par défaut, à toutes les ressources et opérations privilégiées du système.
  • Intranet : l'assemblage est exécuté avec une confiance moyenne (Medium Trust). L'accès au registre, aux paramètres des stratégies de sécurité sont prohibés et les opérations sur le système de fichier ne peuvent se faire que par interaction avec l'utilisateur.
  • Internet : l'assemblage est exécuté avec un niveau de confiance faible (Low Trust). Accès prohibé au registre, variables d'environnement, opérations privilégiées du système, système de fichier…

Evaluation d'un assemblage

Cette console nous permet de tester le niveau de confiance d'un assemblage précis, sur les différents niveaux décris ci-dessus (Entreprise, Machine, Utilisateur) afin de définir plus précisément les jeux de permissions à accorder.

Création d'un package de déploiement

La configuration de la sécurité pour un programme / ensemble de programmes est une tâche assez simple, mais pouvant tout de même devenir fastidieuse dans le cas de déploiements multiples sur plusieurs machines. L'outil de configuration de sécurité du Framework nous permet de créer des packages de déploiement de stratégie de sécurité pour l'exécution des assemblages. C'est dans cette section que nous allons pouvoir les réaliser.

Notez que vous pouvez désactiver le CAS temporairement. Si une application .NET plante sans explication, il peut s'avérer utile de désactiver le CAS afin d'écarter tout problème de sécurité :

Caspol.exe ("Code Access Security Policy") est l'outil ligne de commande permettant de gérer les stratégies de sécurité du CLR .NET. On utilise cet outil via l'Invite de commande Visual Studio 2005 / 2008.

Groupe de code et jeux de permissions

Une stratégie de sécurité se compose de plusieurs éléments, notamment de groupe de code et de jeux de permissions, et peuvent s'appliquer, nous l'avons vu plus haut à différents niveaux : Entreprise, Machine, Utilisateur. Les groupes de code sont organisés de manière hiérarchique. Ces groupes permettent de faire correspondre preuves et jeu de permissions lors de l'application des stratégies de sécurité.

On appel preuve (Evidence) toutes les informations que peut présenter un assemblage quant à sa provenance (nom fort par exemple). Un jeu de permissions va être un ensemble d'action qu'un ou plusieurs assemblages sont autorisés à effectuer. Illustrons les lignes précédentes à l'aide d'un simple schéma :

La stratégie de sécurité est appliquée à un groupe de code, i.e. à tout assemblage pouvant justifier de certaines informations. Elle fait le pont entre la preuve et le jeu de permissions accordé au groupe de code.

CAS et Enforcement : une garantie que le code sera restreint !

Dans la partie précédente, nous avons vu qu'il était possible de restreindre le comportement d'un assemblage, d'un code, par la création de jeux de permissions que CAS se charge de faire respecter. Le terme « Enforcement » signifie qu'il faut garantir que le code ne pourra accéder à des ressources ou des opérations inappropriées. Cependant, une application peut être exécutée avec des droits plus élevés dans certains cas (par exemple sous Vista, « Run as Administrator »). Dans ces cas, l'application doit pouvoir demander si elle à les droits nécessaires.

Intéressons nous rapidement au namespace System.Security qui va nous permettre de travailler en collaboration avec CAS. La classe qui va nous intéresser plus particulièrement est « CodeAccessPermission » qui va nous fournir des méthodes permettant de demander une autorisation au CAS, voir même de réaliser une élévation de privilège :

  • CodeAccessPermission.Demand() : réalise un parcours de la pile d'appel (« Walk the stack ») pour vérifier que chaque assemblage soit autorisé.
  • CodeAccessPermission.Assert() : il peut arriver que le résultat de la méthode « Demand » ci-dessus soit négatif, c'est-à-dire que l'un des élément de la pile des appels ne soit pas autorisé à réaliser une action précise. Dans ce cas, la méthode Assert() va nous permettre dans un premier temps de stopper l'analyse de la pile d'appels (« Stack walk check ») puis réaliser une élévation de privilège.

Exemple :

public class MyFileStream

{

public MyFileStream(string filePath)

{

FileIOPermission fiop = new

FileIOPermission(FileIOPermissionAccess.Read, filePath);

fiop.Demand();

//si on arrive ici, Demand a réussi.

SecurityPermission sp = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);

sp.Assert();

//P/Invoke sur le fichier win32 API

}

}

Il reste encore une notion importante à aborder du côté sécurité du code : le code Transparency.

Notion de code « Transparency »

Avant le .NET Framework 2.0, n'importe quel code au sein d'un programme était considéré comme critique par CAS. Depuis, il existe un moyen de réduire la quantité de code « Security Critical » au sein d'une application. On dit d'un code qu'il est « Security Critical » lorsque ce dernier fait appel à du code critique (non managé, ressources et opérations du système par exemple). A l'opposé, nous retrouvons le code « Security Transparent » : c'est un code isolé, ne pouvant faire appel à du code critique et ne pouvant demander une élévation de privilège (Assert impossible).

Afin de définir quel code est Security Critical et quel code est Security Transparent, non utiliserons l'attribut « SecurityCriticalAttribute » défini dans le namespace System.Security. Cet attribut peut précéder une méthode ou une classe. Tout élément de code précédé de [SecurityCritical] sera considéré par CAS comme du code critique, tout le reste du code sera considéré comme du code transparent.

//le constructeur de cette classe est SecurityCritical, le reste est du code transparency.

[assembly:SecurityCritical]

public class MaClassCritique

{

[SecurityCritical]

public MaClassCritique()

{

//appel de code critique : Demand, Assert, Permission...

}

//security transparent

public void MaMethode()

{

}

//security transparent

public void MonAutreMethode()

{

}

}

Les nouveautés du .NET Framework 3.5 en matière de sécurité

Dans cette dernière partie, nous parlerons des nouveautés apparues dans le .NET Framework 3.5 en ce qui concerne le domaine de la sécurité.

La première nouveauté remarquable de ce Framework est l'apparition de nouveaux algorithmes de sécurité : les algorithmes « Elliptic Curve Cryptography ». Ces algorithmes sont exposés par Windows Vista, donc ne sont disponibles qu'avec le Framework .NET 3.5 sous Windows Vista. Ils font partie de la « Suite B » qui est un jeu d'algorithmes publié par la NSA (National Security Agency). Vous pouvez retrouver la documentation officielle de ces algorithmes sur le site de la NSA : http://www.nsa.gov/ia/industry/crypto_suite_b.cfm.

Parmi les algorithmes implémentés dans le cette nouvelle version du Framework, on retrouve :

  • Advanced Encryption Standard (AES) avec des clés de taille de 128 et 256 bits pour le chiffrement.
  • Secure-Hash (SHA) en version SHA-256 et SHA-384 pour la réalisation de hashs.
  • Elliptic Curve Digital Signature Algorithm (ECDSA) : cet algorithme est utilisable par l'intermédiaire de la classe ECDsaCng du namespace System.Security.Cryptography. Il permet l'échange de données à l'aide d'un couple clé privée / clé publique.
  • Elliptic Curve Diffie-Hellman (ECDH). Il est utilisable via la classe ECDiffieHellmanCng du namespace System.Security.Cryptography et vous permettra l'échange de clés et l'accord secret entre deux entités.

Comme dans la version précédente du .NET Framework, les algorithmes AES et SHA s'utilisent au travers de « CryptoServiceProvider » disponibles toujours dans le namespace System.Security.Cryptography :

A présent voyons un exemple d'utilisation de la classe ECDsaCng suscitée, qui je vous le rappel vous permet de mettre en place de la signature numérique sur vos données, en utilisant les courbes elliptiques.

L'idée ici est de signer numériquement un fichier et de voir comment vérifier si la signature est conforme avant de l'ouvrir :

FileStream fs = File.Open(@"C:\boot.ini", FileMode.Open, FileAccess.Read);

//instanciation de la classe nous permettant l'utilisation de l'algorithme

ECDsaCng signer = new ECDsaCng();

signer.HashAlgorithm = CngAlgorithm.Sha512;//on utilise SHA512

//on récupère le flux de byte associé au FileStream

byte[] fileData = new byte[fs.Length];

fs.Read(fileData, 0, (int)fs.Length);

//on récupère la signature du fichier

byte[] signature = signer.SignData(fileData);

//code de vérification :

if (signer.VerifyData(fileData, signature))

{

Console.WriteLine("Le fichier est conforme à la signature");

}

else

{

Console.WriteLine("Le fichier n'est pas conforme à la signature");

}

Console.Read();

Une autre grande nouveauté du .NET Framework 3.5 en matière de sécurité est, comme citée en introduction, la programmation modulaire basée sur le modèle d'Add-In à l'aide de l'assemblage System.AddIn.dll qui permet au développeur de concevoir des applications flexibles, extensibles et sécurisées. Cette technique ne sera pas décrite dans cet article car elle mérité à elle seule un article complet.

Conclusion

Dans cet article consacré à la compréhension globale de la sécurité du .NET Framework nous avons discuté du rôle du CAS (Code Access Security) au sein du CLR (Common Language Runtime). Nous avons vu que ce composant du .NET Framework était chargé d'assurer la sécurité des assemblages qui s'exécutent sur une machine, et ce avec trois objectifs principaux :

  • Restreindre ce qu'un code peut réaliser
  • Déterminer quel code peut appeler un autre code
  • Identifier un code

Nous avons également vu que CAS était chargé d'assurer la sécurité au niveau de l'accès de la mémoire, en s'assurant qu'un code est bien « type-safe », c'est-à-dire qu'il n'accède pas à la mémoire de manière désordonnée.

Dans une deuxième partie nous avons discuté du niveau de confiance d'un assemblage qui permettait de « personnaliser » le comportant du CAS pour tel ou tel assemblage. Nous avons parlé dans cette partie de Preuve, de Groupe de Code, de Stratégie ainsi que de Jeux de Permissions.

Nous avons ensuite parlé de nouveautés du .NET Framework 3.5 en abordant « l'Enforcement » et la notion de « code transparency ». Nous avons terminés par les quelques nouveautés cryptographiques apportées par la dernière version Framework, notamment les algorithmes de la Suite B créée par la NSA, disponibles uniquement sous Windows Vista !!

Au total, 0 commentaire(s) posté(s) ! Poster un commentaire

comments Ajouter un commentaire

(Affichera votre icône Gravatar)  
[b][/b] - [i][/i] - [u][/u]- [quote][/quote]