IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

vérifier la signature d'une dll par reflection


Sujet :

C#

  1. #1
    Membre éclairé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juin 2005
    Messages
    700
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Juin 2005
    Messages : 700
    Par défaut vérifier la signature d'une dll par reflection
    Est ce possible?

    Si j'ajoute une reference vers une dll signée, je me protege de celui qui voudrait remplacer cette dll par une autre (si j'ai bien compris le principe).

    Mais si je veux charger dynamiquement cette dll, par reflection durant l'execution : puis je garantir la meme protection? etre sur que cette dll n'a pas été altérée par un tiers?

    Merci à tous pour vos éclaircissements.

    EDIT : Solution ici

  2. #2
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Bonjour, il existe des variantes des méthodes chargeant l'assembly (Assembly.Load par ex) pour lesquelles tu peux spécifier la clé de sécurité de l'assembly. Si la clé ne correspond pas, une exception sera levée.

    En revanche, si tu as obtenu cette assembly par reflection (ex : typeof(MyType).Assembly) et bien, si l'assembly en question a été référencé avec son nom fort, tu es certain que MyType sera défini dans la bonne version.

  3. #3
    Membre éclairé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juin 2005
    Messages
    700
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Juin 2005
    Messages : 700
    Par défaut
    Merci pour ces quelques pistes, je vais étudier tout ca

    Le but va etre de charger des plugins que je ferai apres avoir distribué mon application.

  4. #4
    Membre éclairé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juin 2005
    Messages
    700
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Juin 2005
    Messages : 700
    Par défaut
    J'ai trouvé une methodologie pour s'assurer qu'une assembly que l'on souhaite charger ai bien la signature attendue. N'hesitez pas à commenter :

    -On crée donc une dll que l'on signe.
    -On va récupérer la clé publique de cette dll :
    -Lancer "Visual Studio xxxx Command Prompt" (je ne comprends pas pourquoi d'ailleur on ne peut pas passer par "cmd" tout simplement)
    -Aller dans le repertoire de la dll puis taper la commande suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    secutil -array -cmode -strongname VotreFichier.dll > resultat.txt
    -Ouvrir resultat.txt dans le bloc note, et récupérer la clé publique

    Exemple du contenu de resultat.txt
    Microsoft (R) .NET Framework SecUtil 3.5.21022.8
    Copyright (c) Microsoft Corporation. All rights reserved.

    Public Key =
    { 0, 36, 0, 0, 4, 128, 0, 0, 148, 0, 0, 0, 6, 2, 0, 0, 0, 36, 0, 0, 82, 83, 65, 49, 0, 4, 0, 0, 1, 0, 1, 0, 193, 117, 109, 4, 41, 249, 57, 19, 51, 208, 4, 61, 184, 22, 199, 134, 148, 30, 20, 104, 76, 138, 9, 139, 70, 39, 149, 132, 234, 41, 72, 63, 104, 53, 154, 18, 99, 207, 225, 118, 91, 31, 49, 227, 242, 40, 141, 253, 240, 16, 94, 33, 226, 189, 114, 62, 60, 58, 189, 160, 102, 140, 73, 238, 9, 33, 171, 179, 164, 118, 236, 103, 156, 11, 85, 241, 245, 92, 125, 177, 65, 52, 215, 54, 65, 93, 43, 68, 180, 172, 61, 232, 236, 50, 184, 86, 81, 232, 225, 33, 227, 112, 144, 52, 202, 238, 53, 20, 53, 110, 93, 240, 222, 187, 118, 160, 212, 17, 47, 129, 106, 163, 108, 80, 55, 153, 137, 226 }
    Name =
    Plugin
    Version =
    1.0.0.0
    Success
    Voici maintenant un bout de code, qui va charger l'assembly, vérifier sa clé publique, puis si elle est correcte, instancier la classe souhaitée :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    namespace TestPluginSigned
    {
        class Program
        {
            static void Main(string[] args)
            {
                byte[] PluginKey = 
                { 0, 36, 0, 0, 4, 128, 0, 0, 148, 0, 0, 0, 6, 2, 0, 0, 0, 36, 0, 0, 82, 83, 65, 49, 0, 4, 0, 0, 1, 0, 1, 0, 193, 117, 109, 4, 41, 249, 57, 19, 51, 208, 4, 61, 184, 22, 199, 134, 148, 30, 20, 104, 76, 138, 9, 139, 70, 39, 149, 132, 234, 41, 72, 63, 104, 53, 154, 18, 99, 207, 225, 118, 91, 31, 49, 227, 242, 40, 141, 253, 240, 16, 94, 33, 226, 189, 114, 62, 60, 58, 189, 160, 102, 140, 73, 238, 9, 33, 171, 179, 164, 118, 236, 103, 156, 11, 85, 241, 245, 92, 125, 177, 65, 52, 215, 54, 65, 93, 43, 68, 180, 172, 61, 232, 236, 50, 184, 86, 81, 232, 225, 33, 227, 112, 144, 52, 202, 238, 53, 20, 53, 110, 93, 240, 222, 187, 118, 160, 212, 17, 47, 129, 106, 163, 108, 80, 55, 153, 137, 226 };
     
                Assembly ass = null;
                try
                {
     
                    Console.WriteLine("Charge l'assembly");
                    if (!File.Exists("Plugin.dll"))
                        Console.WriteLine("Plugin absent");
     
                    ass = Assembly.LoadFrom("Plugin.dll", evidence);
     
                    bool isKeyValid = ass != null && 
                        ass.GetName() != null &&
                        ass.GetName().GetPublicKey() != null &&
                        PluginKey.SequenceEqual(ass.GetName().GetPublicKey());
     
                    if (!isKeyValid)
                    {
                        Console.WriteLine("les clés ne correspondent pas");
                        ass = null;
                    }
                    else
                    {
                        Console.WriteLine("Assembly chargée :");
                        Console.WriteLine("instancie le plugin");
     
                        IPluginTest.IPlugin plugin = ass.CreateInstance("Plugin.Class1") as IPluginTest.IPlugin;
                        Console.WriteLine("appelle son Run");
                        plugin.Run();
     
                    }
                }
                catch (Exception ex)
                {
     
                    Console.WriteLine("Piti probleme :");
                    Console.WriteLine(ex);
                }
     
                Console.ReadLine();
     
            }
        }
    }

  5. #5
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Il y a un problème avec ce code : ta vérification est effectuée après le chargement de l'assembly. Même si aucun constructeur statique ne devrait avoir été exécuté (ils ne le sont en principe qu'au moment du premier usage d'une classe), je ne m'appuierai pas là-dessus, je ne crois pas que cela fasse partie des specs. Mieux vaut considérer que le code statique aura été exécuté et changer de méthode.

    Voici trois bonnes façons de faire :
    * Via Assembly.Load : spécifier un nom complet (versions acceptant un AssemblyName ou une chaîne de caractères)
    * Via Assembly.LoadFrom : en ajoutant des preuves d'assemblies via Evidence.AddAssembly(StrongName name)
    * Via Assembly.GetName pour vérifier manuellement la clé publique avant le chargement.


    PS : De plus, si l'assembly n'a pas de clé de sécurité, GetPublicKey renverra null il me semble. Ce qui, d'après ton code, produirait un faux positif, ce qui constitue une faille de sécurité.

  6. #6
    Membre éclairé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juin 2005
    Messages
    700
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Juin 2005
    Messages : 700
    Par défaut
    Citation Envoyé par DonQuiche Voir le message
    Mieux vaut considérer que le code statique aura été exécuté et changer de méthode.
    Excelente remarque je n'y avais pas pensé, ca me parrait effectivement plus sage !

    [...]bonnes façons de faire :[...]
    * Via Assembly.LoadFrom : en ajoutant des preuves d'assemblies via Evidence.AddAssembly(StrongName name)
    C'est justement ce que j'ai cherché à faire suite à ton post, mais ca ne se passe pas bien du tout ! Le code ci dessus ne jete aucune exception et charge mon assembly, alors que j'ai recompilée Plugin.dll en lui retirant sa signature (voir meme en lui mettant une autre signature)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
     
    //Clé publique provenant de resultat.txt qui est devenu obsolete vu 
    // que j'ai changé la signature de ma dll
    byte[] PluginKey = 
                { 0, 36, 0, 0, 4, 128, 0, 0, 148, 0, 0, 0, 6, 2, 0, 0, 0, 36, 0, 0, 82, 83, 65, 49, 0, 4, 0, 0, 1, 0, 1, 0, 193, 117, 109, 4, 41, 249, 57, 19, 51, 208, 4, 61, 184, 22, 199, 134, 148, 30, 20, 104, 76, 138, 9, 139, 70, 39, 149, 132, 234, 41, 72, 63, 104, 53, 154, 18, 99, 207, 225, 118, 91, 31, 49, 227, 242, 40, 141, 253, 240, 16, 94, 33, 226, 189, 114, 62, 60, 58, 189, 160, 102, 140, 73, 238, 9, 33, 171, 179, 164, 118, 236, 103, 156, 11, 85, 241, 245, 92, 125, 177, 65, 52, 215, 54, 65, 93, 43, 68, 180, 172, 61, 232, 236, 50, 184, 86, 81, 232, 225, 33, 227, 112, 144, 52, 202, 238, 53, 20, 53, 110, 93, 240, 222, 187, 118, 160, 212, 17, 47, 129, 106, 163, 108, 80, 55, 153, 137, 226 };
                StrongNamePublicKeyBlob blob =
                new StrongNamePublicKeyBlob(PluginKey);
     
                Version version = new Version("1.0.0.0");
     
                StrongName sn = new StrongName(blob, "Plugin", version);
                Evidence evidence = new Evidence();
                evidence.AddAssembly(sn);
                Assembly ass = null;
                try
                {
     
                    Console.WriteLine("Charge l'assembly");
                    if (!File.Exists("Plugin.dll"))
                        Console.WriteLine("Plugin absent");
     
                    //Je m'attends à une exception, vu que la clé publique n'est
                    // pas la bonne ! pourtant ca passe.
                    ass = Assembly.LoadFrom("Plugin.dll", evidence);
     
                     //ici par contre isKeyValid vaudra false comme prévu
                     bool isKeyValid = ass != null && 
                        ass.GetName() != null &&
                        ass.GetName().GetPublicKey() != null &&
                        PluginKey.SequenceEqual(ass.GetName().GetPublicKey());
    }
     catch (Exception ex)
                {
     
                    Console.WriteLine("Piti probleme :");
                    Console.WriteLine(ex);
                }
    Console.ReadLine();
    PS : De plus, si l'assembly n'a pas de clé de sécurité, GetPublicKey renverra null il me semble. Ce qui, d'après ton code, produirait un faux positif
    si si , j'avais prévu le coup
    ass.GetName().GetPublicKey() != null
    Mais ton argument m'a convaincu de ne pas employer cette methodologie, je vais donc chercher pourquoi mon evidence ne fonctionne pas comme il se doit...

  7. #7
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Citation Envoyé par giova_fr Voir le message
    C'est justement ce que j'ai cherché à faire suite à ton post, mais ca ne se passe pas bien du tout ! Le code ci dessus ne jete aucune exception et charge mon assembly, alors que j'ai recompilée Plugin.dll en lui retirant sa signature (voir meme en lui mettant une autre signature)
    Ah oui, au temps pour moi, les preuves (evidence) ne sont utilisées que pour déterminer les droits de l'assembly dans le modèle de transparence de niveau 1 (en voie de décrépitude, cette version de LoadFrom est d'ailleurs appelée à disparaître). Malheureusement, non seulement ça ne fournit aucun effet dans le modèle niveau 2 mais, même dans le niveau 1, elle pourrait contourner les restrictions de sécurité au cas où elle se retrouverait à appeler du code full trust avec des assertions de permissions.

    Du coup, le plus simple serait d'utiliser Assembly.GetName(filename) avant l'appel à LoadFrom.

  8. #8
    Membre éclairé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juin 2005
    Messages
    700
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Juin 2005
    Messages : 700
    Par défaut
    Merci encore pour cette réponse (que je comprends à demi-mots).

    Par contre :
    Assembly.GetName(filename)

    N'est pas une methode statique et de plus il n'existe que GetName() ou GetName(Boolean)

    Du coup je ne comprends pas trop

  9. #9
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741

  10. #10
    Membre éclairé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juin 2005
    Messages
    700
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Juin 2005
    Messages : 700
    Par défaut
    On y est !!! Encore merci pour ton aide Donquiche.

    Je résume donc la solution :

    -On Signe la dll que l'on souhaite charger par reflection
    -Ensuite On va récupérer la clé publique de cette dll :
    -Lancer "Visual Studio xxxx Command Prompt"
    -Aller dans le repertoire de la dll puis taper la commande suivante :
    secutil -array -cmode -strongname VotreFichier.dll > resultat.txt
    -Ouvrir resultat.txt et y récupérer le tableau de byte qui représente la clé publique de cette signature.

    Voici maintenant un bout de code qui avant de charger l'assembly va vérifier sa signature.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    public class Loader
        {
            public static void Load()
            {
                byte[] PluginKey = { 0, 36, 0, 0, 4, 128, 0, 0, 148, 0, 0, 0, 6, 2, 0, 0, 0, 36, 0, 0, 82, 83, 65, 49, 0, 4, 0, 0, 1, 0, 1, 0, 193, 117, 109, 4, 41, 249, 57, 19, 51, 208, 4, 61, 184, 22, 199, 134, 148, 30, 20, 104, 76, 138, 9, 139, 70, 39, 149, 132, 234, 41, 72, 63, 104, 53, 154, 18, 99, 207, 225, 118, 91, 31, 49, 227, 242, 40, 141, 253, 240, 16, 94, 33, 226, 189, 114, 62, 60, 58, 189, 160, 102, 140, 73, 238, 9, 33, 171, 179, 164, 118, 236, 103, 156, 11, 85, 241, 245, 92, 125, 177, 65, 52, 215, 54, 65, 93, 43, 68, 180, 172, 61, 232, 236, 50, 184, 86, 81, 232, 225, 33, 227, 112, 144, 52, 202, 238, 53, 20, 53, 110, 93, 240, 222, 187, 118, 160, 212, 17, 47, 129, 106, 163, 108, 80, 55, 153, 137, 226 };
     
                Assembly ass;
                try
                {
     
                    Console.WriteLine("Cherche l'assembly");
                    if (!File.Exists("Plugin.dll"))
                        Console.WriteLine("Plugin absent");
                    Console.WriteLine("vérifie la signature de l'assembly");
                    AssemblyName assName = AssemblyName.GetAssemblyName("Plugin.dll");
                    bool isKeyValid = assName != null &&
                            assName.GetPublicKey() != null &&
                            PluginKey.SequenceEqual(assName.GetPublicKey());
     
                    if (!isKeyValid)
                    {
                        Console.WriteLine("les clés ne sont pas valides");
                    }
                    else
                    {
                        ass = Assembly.LoadFrom("Plugin.dll");
                        Console.WriteLine("Assembly chargée :");
                        Console.WriteLine("instancie le plugin");
     
                        IPluginTest.IPlugin plugin = ass.CreateInstance("Plugin.Class1") as IPluginTest.IPlugin;
                        Console.WriteLine("appelle son Run");
                        plugin.Run();
     
                    }
                }
                catch (Exception ex)
                {
     
                    Console.WriteLine("Piti probleme :");
                    Console.WriteLine(ex);
                }
            }
        }
    }

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Evenement au déchargement d'une dll par windows
    Par peijnoob dans le forum Windows
    Réponses: 3
    Dernier message: 22/06/2007, 09h54
  2. Réponses: 4
    Dernier message: 07/05/2007, 21h38
  3. [c#] comment récupérer le namespace d'une DLL par réflection?
    Par Jayceblaster dans le forum Windows Forms
    Réponses: 2
    Dernier message: 20/07/2006, 13h20
  4. Réponses: 6
    Dernier message: 12/05/2006, 15h20
  5. Problème mémoire avec une dll par chargement dynamique
    Par widze19 dans le forum C++Builder
    Réponses: 6
    Dernier message: 15/12/2003, 13h20

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo