Skip to main content

La sécurité appliquée à .NET

 

Frédéric Queudret

Frédéric QUEUDRET

MVP Client Application & CTO de la société Mpoware, accélérateur d’innovation. Société française d’édition de logiciels et de prestations de services sur les technologies .NET.

 

La sécurité est un vaste sujet qu’il est toujours nécessaire d’aborder humblement étant donné la diversité, la complexité et la versatilité qui le caractérise. Ce qui est connu un jour est remis en cause le lendemain par de nouvelles techniques, de nouvelles attaques et de nouvelles protections. Cet article a pour objectif de sensibiliser, sous divers angles d’approche, le lecteur développeur à quelques notions de sécurité qui touchent les développements .NET.

Le « Security Development LifeCycle »

L’objectif d’intégrer la sécurité dans les développements applicatif est d’offrir un degré de protection adapté en fonction du danger perceptible ou potentiel.

Mais comment définir le danger ? Quel danger peut bien représenter une application ?

En fait de nombreux, que les personnes plutôt malintentionnées utiliseront pour arriver à des fins pas très louables !

Comme quoi ?

Parmi les plus connus : utilisation frauduleuse de données (bancaires ?!), destruction de données critiques, espionnage, vol d’identité, … et la liste est tellement longue qu’elle pourrait faire un sujet d’article à part entière.

Dans un monde où l’information devient une arme pour qui sait la manipuler, il est capital d’identifier les dangers et de prendre les mesures qui s’imposent dans nos développements afin d’éviter l’utilisation détournée de nos codes.

Le "Security Development LifeCycle" (SDL) ou aussi appelé "Trustworthy Computing Security Development Lifecycle"  est un processus décrit par Microsoft permettant d’intégrer les besoins relatifs à la sécurité tout au long du cycle de vie du développement d’une application. Ce processus est basé sur les bonnes pratiques de conception et de codage, la modélisation des menaces et les contre-mesures appropriées, la documentation et revues de code…

Il existe des documents (référence n°3) et outils (référence n°2) permettant la modélisation et l’analyse des menaces comme, ci-dessous, le Microsoft Threat Analysis & Modeling v2.1.2.

 

 

L’objectif de cette modélisation est d’identifier :

·        Les actifs de valeur, tels que des données en base ou sur le système de fichiers (une table des clients en base),

·        Les menaces potentielles d’endommagement des actifs (la perte de toutes mes données clients),

·        Les vulnérabilités ou faiblesses qui font que les menaces peuvent être mises à exécution (l’accès en écriture à mes données clients),

·        Les attaques qui représentent le mode de « passage à l’action » (injection du code SQL tel que TRUNCATE TABLE MesClients),

·        La contre-mesure qui permet de minimiser un risque et de se préserver contre une menace (Un plan de backup régulier des données Clients ?).

Ensuite, il convient d’identifier les menaces et de les catégoriser : STRIDE.

·        Spoofing : consiste à utiliser une identité de manière frauduleuse (prendre l’identité de quelqu’un par exemple),

·        Tampering : Modification ou altération non autorisée de données (exemple : modification de données dans une communication ou modification du binaire d’un programme),

·        Repudiation : l’utilisateur doit pouvoir prouver qu’il n’a pas commis certaines actions (par exemple, le code CVC d’une carte bleue est utilisé par les banques pour prouver que c’est bien le possesseur de la carte qui l’a utilisée lors d’une transaction ; dans ce cas, le porteur de la carte ne peut répudier sa transaction, en théorie car la législation permet le recours),

·        Information disclosure : C’est l’exposition d’informations à caractère confidentiel ou privé,

·        Denial of Service : ou comment rendre un système ou une application inutilisable (comme par exemple une soudaine activité très forte sur un site Web qui rend le service inutilisable pour ses utilisateurs internautes),

·        Elevation of privilege : Utilisation de privilèges plus élevés que ceux initialement accordés.

Les catégories de menaces nous aident à identifier des contre-mesures possibles qui nous permettront de protéger nos applications face à d’éventuelles attaques (le terme « éventuel » est choisi pour introduire ensuite la quantification du risque ou DREAD).

Le tableau ci-dessous donne une liste non exhaustive des contre-mesures applicables aux catégories de menaces :

Catégories de menacesContre-mesures possibles
Vol d’identité (Spoofing)

Utilisation d’une authentification forte.

Ne pas stocker les secrets (mot de passe…) « en clair ».

Ne pas échanger de secrets « en clair ».

Protéger les cookies d’authentification avec SSL.

Altération de données (Tampering)

Utiliser la signature et le hash de données.

Utiliser des protocoles de communication résistants face à l’altération de données et permettant de contrôler l’intégrité des messages échangés.

Répudiation

Avoir une traçabilité forte.

Utiliser des signatures numériques.

Divulgation d’information (Information disclosure)

Utiliser un chiffrement fort.

Utiliser des protocoles de communication permettant d’assurer la confidentialité des messages échangés.

Ne pas stocker les secrets « en clair » (comme les mots de passe)

Déni de service (Denial of service)Utiliser des mécanismes de limitations de bande passante.
Elévation de privilègesSuivre le principe de n’accorder que les privilèges nécessaires pour effectuer l’action demandée.

La sécurité étant un vaste et interminable sujet, les contre-mesures peuvent ne pas toujours résoudre l’ensemble du problème que pose une menace. Nous verrons d’ailleurs que .NET en résout certains par rapport au code natif, comme le buffer overrun (*), mais en apporte d’autres. Il est donc important de connaître le niveau de risque encouru face à une menace, car l’excès de sécurité pourrait nuire à vos développements voire même être sa principale faille si les contre-mesures sont mal utilisées ou inadaptées : il faut éviter de tomber dans l’excès de paranoïa et DREAD est là pour ça !

(*) Rien n’est jamais acquis en sécurité…

La table ci-dessous propose un système de quantification permettant de calculer le risque face à une menace :

 Elevé (3)Moyen (2)Faible (1)
D ommage potentielL’attaquant peut tromper la sécurité, obtenir tous les accès, être administrateur, télécharger du contenu.Fuite de données sensibles.Fuite de données banales.
R eproductibilitéL’attaque peut être reproduite autant de fois que voulu.L’attaque peut être reproduite à certaines conditions.L’attaque est difficile à reproduire.
E xploitabilitéUn développeur novice peut exécuter l’attaque rapidement.Un programmeur expérimenté pourrait exécuter l’attaque, puis répéter les étapes.L’attaque ne peut être réalisée que par un développeur chevronné avec des connaissances pointues sur les couches basses.
UtilisateursA ffectésTous les utilisateurs.Quelques utilisateurs.Une très petite partie des utilisateurs.
D écouverteDes informations publiées expliquent l’attaque.La vulnérabilité n’est connue que d’un groupe restreint d’utilisateur.Le problème est obscur et complexe et certainement difficile à découvrir.

Si nous appliquons cette mesure de risque à deux menaces très connues, nous obtenons les quantifications suivantes :

MenaceDREADTotalNiveau
L’attaquant obtient des informations d’authentification via un outil de supervision du réseau3322212Elevé
Injection de commandes SQL3333214Elevé

Cette courte introduction à l’identification des menaces et contre-mesures pour vos développements étant faite, nous allons maintenant passer à des choses plus concrètes et des problématiques qui touchent les applications .NET.

Vol de propriété intellectuelle

Il n’y a pas très longtemps, je lisais sur le blog d’un développeur .NET qu’il avait retrouvé son application recompilée sur un site étranger avec une lettre de différence dans le nom. Son application étant disponible en téléchargement, il n’y avait rien de plus facile que de la rétro-concevoir étant donné qu’elle était compilée en MSIL, un langage intermédiaire permettant la portabilité sur différents systèmes exécutant .NET. Bien que l’application n’ait rien de particulier, c’est tout de même le fruit du travail de son auteur qui était en jeu. Imaginez seulement ce que cela peut donner sur un logiciel commercial ou issu de la recherche.

Comment décompiler un programme en .NET ? Rien de plus simple et tout bon développeur .NET s’y emploie chaque jour sur le framework pour parfaire ses connaissances avec des outils comme ILDASM ou Reflector qui est très largement utilisé.

 

 

Offuscation

L’offuscation est l’art de brouiller les pistes ou encore obscurcir le code. Cette méthode ralentit considérablement la rétro-conception en fonction des algorithmes utilisés. Il existe environ une quarantaine d’algorithmes d’offuscation. Un algorithme d’offuscation possède en général 3 mesures permettant de connaître son efficacité : sa puissance, sa robustesse et son coût.

La puissance d’un offuscateur est la mesure selon laquelle le code est difficile à lire pour un humain. Par exemple, un des algorithmes d’offuscation est basé sur la destruction systématique de tout commentaire dans le code qui pourrait aider à comprendre son fonctionnement. Un autre algorithme d’offuscation consiste à modifier tous les noms des variables du code (exemple ci-dessous).

Le code source initial :

static int VeryInnovativeAlgorithm(int value, int power, int x, int y, int z)

 {

    int result = 0;

    for (int k = 0; k < x; k++)

    {

        for (int j = 0; j < y; j++)

        {

            for (int i = 0; i < z; i++)

            {

                result += value * power;

            }

        }

    }

    return result;

 }

Peut-être transformé manuellement de la manière suivante:

static int VeryInnovativeAlgorithm(int EEFFEEEFEEFFFEEFFE, int EEFFEEEFEFEFFEEFFE, int EEFEFEEFEFEFFEEFFE, int EFEEFEEFEFEFFEEFFE, int EFEEFEEFEFEFFEFEFE)

 {

    int EFEEFEEFFEEFFEFEFE = 0;

    for (int EFEEFEEFFEEFFEFFEE = 0; EFEEFEEFFEEFFEFFEE < EEFEFEEFEFEFFEEFFE; EFEEFEEFFEEFFEFFEE++)

    {

        for (int EFEEFFEEFEEFFEFFEE = 0; EFEEFFEEFEEFFEFFEE < EFEEFEEFEFEFFEEFFE; EFEEFFEEFEEFFEFFEE++)

        {

            for (int EFEEFFEEFEEFFFFEEE = 0; EFEEFFEEFEEFFFFEEE < EFEEFEEFEFEFFEFEFE; EFEEFFEEFEEFFFFEEE++)

            {

                EFEEFEEFFEEFFEFEFE += EEFFEEEFEEFFFEEFFE * EEFFEEEFEFEFFEEFFE;

            }

        }

    }

    return EFEEFEEFFEEFFEFEFE;

 }

Le programme fonctionne de la même manière mais est plus difficile à lire pour l’humain.

La robustesse d’un algorithme d’offuscation est la difficulté qu’aurait un dé-offuscateur (un programme) à régénérer une structure de code lisible. L’un des mécanismes les plus efficaces est celui de l’interprétation, mais c’est aussi l’un des plus coûteux : cela consiste à modifier le code MSIL pour le rendre interprétable par un runtime faisant parti de l’offuscateur.

Le coût représente par exemple la perte de performances à l’exécution induite par l’utilisation d’un algorithme d’offuscation. En général, plus l’algorithme est robuste, plus il est coûteux : il est nécessaire de bien connaître les effets des algorithmes d’offuscation sur l’exécution et sur la protection du code. Sans cette connaissance, le développeur pourrait se méprendre sur la qualité de la protection qu’il donne à son code.

L’exemple ci-dessous est tiré de l’utilitaire d’offuscation de Mpoware en version beta (code source, puis code offusqué). Cet outil est le seul du marché qui permet d’offusquer du code source C# (offuscation pré-compilation) et non du MSIL (offuscation post-compilation) :

using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;

 namespace Mpoware.CSharp.Parser.Tests
 {
 public class Test5_ClassModifiers
 {
 // Avec un commentaire une ligne
 /*
 ** Small comment
 ** Delimited $$$
 */
 public void Say(string message)
 {
 i = 0;
 Console.WriteLine("Hello " + /*mon message*/ message);
 }
 }
 }

Offusqué de la manière suivante:

using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;

 namespace Mpoware.CSharp.Parser.Tests
 {
 public class Test5_ClassModifiers
 {
 public void Say(string lCn)
 {
 int bFvkZBBQMMybaxvs;
 bFvkZBBQMMybaxvs = 0;
 if (bFvkZBBQMMybaxvs == 0) goto sdlfhsqdfmkjf;
 fmkjdshfkjf: if (bFvkZBBQMMybaxvs == 1) { Console.WriteLine(GetString(new int[] { 2, 2, -3, 0, -1, 3 }) + lCn); goto end; }
 sdlfhsqdfmkjf: ADDKSHFDDRH(bFvkZBBQMMybaxvs); bFvkZBBQMMybaxvs++; if (bFvkZBBQMMybaxvs == 1) { goto fmkjdshfkjf; } else { goto fmkjdshfkjf5; };
 bFvkZBBQMMybaxvs = 0;
 if (bFvkZBBQMMybaxvs == 0) goto sdlfhsqdfmkjf;
 fmkjdshfkjf5: if (bFvkZBBQMMybaxvs == 1) { Console.WriteLine(GetString(new int[] { 2, 2, -3, 0, -1, 3 }) + lCn); goto end; }
 sdlfhsqdfmkjf6: ADDKSHFDDRH(bFvkZBBQMMybaxvs); bFvkZBBQMMybaxvs++; goto fmkjdshfkjf;
 end1: ;
 bFvkZBBQMMybaxvs = 0;
 if (bFvkZBBQMMybaxvs == 0) goto sdlfhsqdfmkjf;
 fmkjdshfkjf1: if (bFvkZBBQMMybaxvs == 1) { Console.WriteLine(GetString(new int[] { 2, 2, -3, 0, -1, 3 }) + lCn); goto end; }
 sdlfhsqdfmkjf2: ADDKSHFDDRH(bFvkZBBQMMybaxvs); bFvkZBBQMMybaxvs++; goto fmkjdshfkjf;
 end2: ;
 bFvkZBBQMMybaxvs = 0;
 if (bFvkZBBQMMybaxvs == 0) goto sdlfhsqdfmkjf;
 fmkjdshfkjf3: if (bFvkZBBQMMybaxvs == 1) { Console.WriteLine(GetString(new int[] { 2, 2, -3, 0, -1, 3 }) + lCn); goto end; }
 sdlfhsqdfmkjf4: ADDKSHFDDRH(bFvkZBBQMMybaxvs); bFvkZBBQMMybaxvs++; goto fmkjdshfkjf;
 end3: ;

 end: return; ;
 }

 private int ADDKSHFDDRH(int bFvkZBBQMMybaxvs)
 {
 return bFvkZBBQMMybaxvs++;
 }
 private string GetString(int[] p)
 {
 StringBuilder s = new StringBuilder();
 int[] al = new int[6] { 111, 108, 72, 32, 101, 34 };
 int i = 0;
 for (int k = 0; k < p.Length; k++)
 {
 i += p[k++]; s.Append((char)al[i]);
 }
 return s.ToString();
 }
 }
 }

Peu de développeurs choisissent finalement de protéger leurs applications contre la rétro-conception par des offuscateurs, car il existe des inconvénients non négligeables et notamment les suivants :

·         Brouillage relativement peu robuste pour un coût minimum,

·         Certains offuscateurs peuvent altérer l’exécution de votre programme et le rendre inutilisable (cela peut arriver avec les applications utilisant la Reflection),

·         Il existe des décompilateurs tels que Salamander .NET qui réduisent considérablement l’utilité de la plupart des offuscateurs,

·         Il peut être plus difficile de débugger un programme offusqué : la pile d’appels est elle-même difficile à lire par l’auteur du programme si l’offuscateur ne propose pas une table de lecture inverse…

Protection des assemblies par cryptage

Certains utilitaires comme .NET Reactor ou le Secure Vault de Mpoware permettent de chiffrer les assemblies à protéger ou une partie des ressources les plus critiques. Ci-dessous, nous vous proposons une technique simple que vous pouvez utiliser pour sécuriser vos assemblies. L’objectif est de chiffrer une assembly de calcul avec un code d’accès, de stocker l’assembly chiffrée dans les ressources d’une assembly appelante sous la forme d’un tableau de byte. Lors de l’utilisation de l’assembly de calcul, l’application demande le code d’accès et charge l’assembly calcul si le code d’accès est le bon.

1.       Dans Visual Studio 2008, créez 2 projets : 1 Windows Forms et 1 librairie de classes. La librairie de classes contiendra vos classes de calcul.

2.       Créez ensuite une application en ligne de commande permettant de chiffrer l’assembly librairie. Le code pourrait permettre d’entrer le path de l’assembly à chiffrer et un mot de passe, comme par exemple :

static void Main(string[] args)

{

   string asmPath = args[0];

   string password = args[1];   

   string[] asmPathParts = asmPath.Split('.');

    asmPathParts[asmPathParts.Length - 1] = "Crypted.dll";

   string cryptedAsmPath = string.Join(".", asmPathParts);

   // Génération d'un mot de passe

   PasswordDeriveBytes pwdGen = new PasswordDeriveBytes(password, MD5CryptoServiceProvider.Create().ComputeHash( Encoding.UTF8.GetBytes(password)));

   byte[] key = pwdGen.GetBytes(16);

   byte[] vector = pwdGen.GetBytes(8);

    // Chiffrement à l'aide de Triple-DES

     TripleDESCryptoServiceProvider provider = newTripleDESCryptoServiceProvider();

    provider.Key = key;

    provider.IV = vector;

    provider.Padding = PaddingMode.PKCS7;

   using (FileStream outFsStream = File.Create(cryptedAsmPath))

    {

        using (CryptoStream stream = new CryptoStream(outFsStream, provider.CreateEncryptor(), CryptoStreamMode.Write))

        {

            BinaryReader reader = new BinaryReader(File.Open(asmPath, FileMode.Open));    

            int length = 256;

            byte[] buffer = new byte[length];

            while (reader.Read(buffer, 0, length) > 0)

            {

                stream.Write(buffer, 0, length);

            }

            reader.Close();

            stream.Flush();

             stream.FlushFinalBlock();

         }

     }

}

3.       Ajoutez l’assembly chiffrée dans les ressources de l’application .NET qui doit l’utiliser (Projet > Ajouter un élément existant). Modifier les propriétés du fichier « nomdufichier.Crypted.dll » et positionner « Build Action » à « Embedded Resource ».

4.       Il ne reste plus qu’à implémenter le code de déchiffrement et le code d’utilisation de l’assembly protégée qui sera basé sur la Reflection.

PasswordFormaskPassword = newPasswordForm();

if(askPassword.ShowDialog() == DialogResult.OK)

{

     // Récupère le mote de passe

     string password = askPassword.Password;

     byte[] rawAsm;

     // Génération du mot de passe

     PasswordDeriveBytespwdGen = newPasswordDeriveBytes(password, MD5CryptoServiceProvider.Create().ComputeHash( Encoding.UTF8.GetBytes(password)));

   byte[] key = pwdGen.GetBytes(16);

   byte[] vector = pwdGen.GetBytes(8);

   // Déchiffrement Triple-DES

   TripleDESCryptoServiceProvider provider = new TripleDESCryptoServiceProvider();

    provider.Key = key;

    provider.IV = vector;

    provider.Padding = PaddingMode.PKCS7;

    // Récupère l'assembly protégée embarquée

     Stream inStream = Assembly.GetExecutingAssembly().GetManifestResourceStream( "WinProtectApp.ProtectedLib.Crypted.dll");

     // Crée le stream qui contiendra l'assembly déchiffrée

     using (MemoryStream outStream = new MemoryStream())

    {

         try

         {

             // Crée le stream de déchiffrement

             using (CryptoStream stream = new CryptoStream(inStream, provider.CreateDecryptor(), CryptoStreamMode.Read))

            {

               BinaryReader reader = new BinaryReader(stream);

               int length = 256;

               byte[] buffer = new byte[length];

                // Lecture du stream d'entrée et écriture vers le stream de sortie en mémoire

                 while(reader.Read(buffer, 0, length) > 0)

                {

                    outStream.Write(buffer, 0, length);

               }

                reader.Close();

                stream.Flush();

            }

        }

        catch (CryptographicException cex)

        {

            // Bad password

            Debug.WriteLine(cex.Message);

            return;

         }

         // Récupération du contenu du stream de sortie

         rawAsm = outStream.ToArray();

     }

     // Utiliser les techniques de Reflection pour exécuter les méthodes de l'assembly protégée

     Assembly clearAsm = Assembly.Load(rawAsm);

   Type secretClassType = clearAsm.GetType("ProtectedLib.SecretClass");

   object instance = clearAsm.CreateInstance(secretClassType.FullName);

   MethodInfo method = secretClassType.GetMethod("Calculate");

    result = (int)method.Invoke(instance, new object[] { value, power });

}

Le cryptage d’assembly n’est pas à toute épreuve : il faut distribuer le mot de passe et l’assembly n’étant chiffré qu’avec un secret, tous les utilisateurs de l’application ont a fortiori le même mot de passe, à moins de compiler une version par utilisateur. De plus grâce à Reflector, le hacker peut lire la recette de déchiffrement de votre assembly. A ces problèmes, nous pouvons apporter plusieurs réponses pour renforcer la protection de notre propriété intellectuelle :

·         Le secret peut-être une information connue de l’assembly appelante, afin de ne pas avoir besoin de demander un code à l’utilisateur,

·         L’assembly à charger peut vérifier l’identité de l’assembly appelante.

Le nommage fort d’une assembly nous permet d’apporter des éléments de la solution : modifiez les propriétés de vos projets pour signer les assemblies.

 

 

Pour que l’assembly appelée puisse vérifier l’identité de son appelant, nous modifions le code de « SecretClass » de la manière suivante :

public class SecretClass

{

     private const string GrantedCallingAssembly = "ACQAAASAAACUAAAABgIAAAAkAABSU0ExAAQAAAEAAQBp6Voly5lr8Ev2EsqWElV+oKssgUQLnzf/uhBg4taWbfZN/PbYM+cPkp86DR+TCUhuszThwd1CSM9yKa5Xb0DQ5sHm876Xz/6XhbJAdNor8MSy/IVy84BYz5wvFYI6kmbuSOO49YwNiZFS5wx25rc/WTwMIXUb4mFFkBdAqmm5tA==";

     private bool _isGranted;

   public SecretClass()

    {

         _isGranted = false;

         // Récupération des informations de l'assembly appelante

         AssemblyNamecallingAsm = Assembly.GetEntryAssembly().GetName();

        // Vérification de l'identité de l'assembly appelante

         if (Convert.ToBase64String(callingAsm.GetPublicKey()) == GrantedCallingAssembly)

        {

            _isGranted = true;

        }

    }

   public int Calculate(int value, int power)

    {

         // Vérifier si l'appelant est bien celui qu'il prétend être

         if(!_isGranted)

        {

            throw newSecurityException();

        }

        int res = 1;

        for (int i = 0; i < power; i++)

        {

            res = res * value;

        }

        return res;

    }

 }

Vous aurez à implémenter le code de récupération de la clé publique en base 64 pour écrire la constante GrantedCallingAssembly.

Pour aller plus loin, nous vous laisserons le soin de renforcer encore un plus le mécanisme par l’utilisation d’un AppDomain dédié au chargement des assemblies chiffrées et bien d’autres techniques issues de votre imagination fertile de développeur.

Conclusion

Cet article fait parti d’une série sur la sécurité que nous enrichirons au fur-et-à-mesure des numéros à venir. Dans un premier temps, nous avons introduit les notions de risques, niveaux de sécurité et réponses appropriées, puis, dans une deuxième partie, nous avons montré comment renforcer la sécurité contre le vol de propriété intellectuelle par l’offuscation et le chiffrement. Lorsqu’il s’agit de protéger efficacement certaines parties de l’application, nous recommandons l’utilisation conjointe de l’offuscation et du chiffrement. Etant donné qu’au bout du compte, le CLR doit tout de même exécuter le code, il n’existe pas de sécurité absolue puisque notre code est au moins lisible par le runtime. Le code natif C/C++ allié aux techniques d’offuscation et de chiffrement est une bonne manière d’arrêter les outils de type Reflector et ILDASM. Le C++/CLI, permettant de mixer du code natif au code managé, peut-être une bonne solution pour encapsuler les parties sensibles de nos applications.

Finalement, plutôt que de distribuer nos assemblies, ne serait-il pas plus judicieux de les déployer sur un serveur et d’en protéger l’accès ? Le modèle Saas à base de services Web par exemple est un excellent rempart contre le vol de propriété intellectuel et il n’impose qu’un seul point de sécurisation : la ferme de serveurs sur lesquelles sont déployées nos assemblies. C’est une alternative très intéressante au moment même où des plateformes comme Windows Azure nous permettent de mettre en œuvre très facilement ce type de scénario.

 

Références

  1. Les 6 étapes de la méthode SDL expliquées
  2. Security Development LifeCycle
  3. Microsoft Threat Analysis & Modeling v2.1.2 (en anglais)
  4. Guide des bonnes pratiques “Improving Web Application Security: Threats and Countermeasures” (en anglais)
  5. Microsoft Application Threat Modeling Blog (en anglais)
  6. Reflector (en anglais)

 

Glossaire

  • MSIL: Microsoft Intermeditate Language, c’est le langage assembleur exécuté par le runtime .NET.
  • Offuscation : pratiques permettant d’obscurcir du code, le rendre ambigu ou difficile à comprendre.
  • AppDomain : Environnement isolé d’exécution d’applications .NET.
  •  

    Microsoft réalise une enquête en ligne pour comprendre votre opinion sur le site Web de. Si vous choisissez de participer, l’enquête en ligne vous sera présentée lorsque vous quitterez le site Web de.

    Souhaitez-vous y participer ?