.net 2 - protection contre les fichiers potentiellement dangereux

Contenu du snippet

Si vous écrivez un client de messagerie instantanée ou de peer-to-peer, vous pouvez utiliser les méthodes de cette classe pour bloquer l'accès aux fichiers exécutables reçus, en attendant par exemple une analyse anti-virus ou une confirmation explicite de l'utilisateur ayant confiance en ce fichier.

Source / Exemple :


using System; // Array, Boolean, Environment, Int32, OperatingSystem, PlatformNotSupportedException, String, Version
using System.IO; // File
using System.Security.AccessControl; // AccessControlType, FileSecurity, FileSystemAccessRule, FileSystemRights
using System.Security.Principal; // SecurityIdentifier, WellKnownSidType

/// <summary>
/// Permet de bloquer/débloquer des fichiers exécutables.
/// Peut être utilisé à la réception de fichiers sur Internet, lorsque leur expéditeur est de confiance partielle.
/// </summary>
public static class ExeLocker
{
	/// <summary>
	/// Identificateur de sécurité (SID) représentant tous les utilisateurs ("Tout le monde").
	/// </summary>
	public static readonly SecurityIdentifier everybody = new SecurityIdentifier(WellKnownSidType.WorldSid,null);
	
	/// <summary>
	/// Vérifie si le système supporte le blocage des exécutables. C'est le cas de Windows 2000, XP, 2003 et Vista.
	/// </summary>
	/// <returns>true si le système supporte le blocage des exécutables, sinon false.</returns>
	public static bool CanLock {
		get {
			OperatingSystem os = Environment.OSVersion;
			// Noyau NT ?
			if (os.Platform != PlatformID.Win32NT)
				return false;
			// 2000 <=> NT 5.0, XP <=> NT 5.1, 2003 <=> NT 5.2, Vista <=> NT 6.0
			return (os.Version >= new Version(5,0));
		}
	}
	
	/// <summary>
	/// Bloque un fichier exécutable.
	/// </summary>
	/// <param name="path">Chemin d'accès du fichier à bloquer.</param>
	/// <returns>true si le fichier a été bloqué, false si il l'était déjà.</returns>
	/// <exception cref="System.PlatformNotSupportedException">Le système ne supporte pas le blocage des exécutables.</exception>
	public static bool Lock(string path)
	{
		// Est-ce que le système supporte le blocage ?
		if (!CanLock)
			throw new PlatformNotSupportedException();
		// Si le fichier est déjà bloqué, aucune opération à effectuer.
		if (IsLocked(path))
			return false;
		FileSecurity acl = File.GetAccessControl(path);
		// Refuser l'exécution au SID "Tout le monde".
		FileSystemAccessRule ace = new FileSystemAccessRule(everybody,FileSystemRights.ExecuteFile,AccessControlType.Deny);
		acl.AddAccessRule(ace);
		File.SetAccessControl(path,acl);
		// Si on arrive là, le fichier a bien été bloqué.
		return true;
	}
	
	/// <summary>
	/// Débloque un fichier exécutable.
	/// </summary>
	/// <param name="path">Chemin d'accès du fichier à débloquer.</param>
	/// <returns>true si le fichier a été débloqué, false si il n'était pas bloqué.</returns>
	/// <exception cref="System.PlatformNotSupportedException">Le système ne supporte pas le blocage des exécutables.</exception>
	public static bool Unlock(string path)
	{
		// Est-ce que le système supporte le blocage ?
		if (!CanLock)
			throw new PlatformNotSupportedException();
		FileSecurity acl = File.GetAccessControl(path);
		FileSystemAccessRule ace = new FileSystemAccessRule(everybody,FileSystemRights.ExecuteFile,AccessControlType.Deny);
		// Cette méthode retourne false si l'entrée à supprimer ne figure pas dans la liste;
		// en d'autres termes, si le fichier n'est pas bloqué.
		if (!acl.RemoveAccessRule(ace))
			return false;
		File.SetAccessControl(path,acl);
		// Si on arrive là, le fichier a bien été débloqué.
		return true;
	}
	
	/// <summary>
	/// Vérifie si un fichier exécutable est bloqué sans effectuer d'autres opérations.
	/// </summary>
	/// <param name="path">Chemin d'accès du fichier à vérifier.</param>
	/// <returns>true si le fichier est bloqué, false sinon.</returns>
	/// <exception cref="System.PlatformNotSupportedException">Le système ne supporte pas le blocage des exécutables.</exception>
	public static bool IsLocked(string path)
	{
		// Est-ce que le système supporte le blocage ?
		if (!CanLock)
			throw new PlatformNotSupportedException();
		FileSecurity acl = File.GetAccessControl(path);
		// Parcourir la liste de contrôle d'accès (ACL) du fichier et
		// renvoyer true si une entrée (ACE) est l'entrée de blocage.
		foreach (FileSystemAccessRule ace in acl.GetAccessRules(true,false,typeof(SecurityIdentifier)))
			if ((ace.AccessControlType == AccessControlType.Deny) && (ace.FileSystemRights == FileSystemRights.ExecuteFile) && (ace.IdentityReference == everybody))
				return true;
		// Si on arrive là, l'entrée n'a pas été trouvée, le fichier n'est donc pas bloqué
		return false;
	}
}
/// <summary>
/// Classe contenant le point d'entrée de l'application.
/// </summary>
public static class Program
{
	/// <summary>
	/// Le point d'entrée de l'application.
	/// </summary>
	/// <param name="args">Arguments de ligne de commande passés à l'application.</param>
	/// <returns>Code de sortie de l'application.</returns>
	public static int Main(string[] args)
	{
		// Est-ce que le système supporte le blocage ?
		if (!ExeLocker.CanLock)
			return 2;
		// La syntaxe de la commande est-elle correcte ?
		if (args.Length < 2)
			return 2;
		string path = string.Join(" ",args,1,args.Length - 1);
		switch (args[0].ToLower())
		{
			case "-l" : // Bloquer
				return (ExeLocker.Lock(path)?0:1);
			case "-u" : // Débloquer
				return (ExeLocker.Unlock(path)?0:1);
			case "-c" : // Vérifier
				return (ExeLocker.IsLocked(path)?1:0);
			default : // Syntaxe incorrecte
				return 2;
		}
	}
}

Conclusion :


Pour empêcher l'exécution d'un fichier potentiellement dangereux, cette classe place une entrée de type Refuser l'exécution dans la liste de contrôle d'accès du fichier dont le chemin est passé en paramètre. On peut aussi retirer la protection ou vérifier sa présence.

Systèmes supportés : Windows 2000 (NT 5.0), XP (NT 5.1), 2003 (NT 5.2), Vista (NT 6.0) et supérieurs. Utilisez la propriété CanLock pour éviter d'avoir à faire tous les tests individuellement.

Explication du niveau (initié) : Les listes de contrôle d'accès peuvent apparaître très simples à certains, mais pas à tout le monde. J'ai moi-même encore du mal à les maîtriser.

Notes concernant l'EXE obtenu par compilation de cette source :
Syntaxe (si l'EXE s'appelle "lock") :
lock -l fichier (pour bloquer fichier => code de sortie = (ExeLocker.Lock(fichier)?0:1))
lock -u fichier (pour débloquer fichier => code de sortie = (ExeLocker.Unlock(fichier)?0:1))
lock -c fichier (pour vérifier si fichier est bloqué => code de sortie = (ExeLocker.IsLocked(fichier)?1:0))
Remarque : Le code de sortie vaudra toujours 2 si le système ne supporte pas le blocage ou si la syntaxe de la commande est incorrecte.
Dans un fichier de commandes (.bat, .cmd, .nt), le code de sortie peut être obtenu par la variable %errorlevel% (avec les extensions de commandes) ou par des instructions conditionnelles "if errorlevel N <instruction>".
Dans un exécutable .Net 1.1 (vous ne pourrez pas utiliser directement la classe ExeLocker), le code de sortie peut être récupéré par la propriété ExitCode du composant System.Diagnostics.Process associé au programme.

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.