DéveloppeurWeb.Com
    DéveloppeurWeb.Com
    • Agile Zone
    • AI Zone
    • Cloud Zone
    • Database Zone
    • DevOps Zone
    • Integration Zone
    • Web Dev Zone
    DéveloppeurWeb.Com
    Home»Uncategorized»SAST : les outils d’analyse de code recherchent des failles de sécurité
    Uncategorized

    SAST : les outils d’analyse de code recherchent des failles de sécurité

    janvier 31, 2023
    SAST : les outils d'analyse de code recherchent des failles de sécurité
    Share
    Facebook Twitter Pinterest Reddit WhatsApp Email

    Ici, nous allons discuter de la manière dont les solutions SAST détectent les failles de sécurité. Je vais vous parler d’approches différentes et complémentaires pour détecter les vulnérabilités potentielles, vous expliquer pourquoi chacune d’entre elles est nécessaire et comment transformer la théorie en pratique.

    SAST

    SAST (Static Application Security Testing) est utilisé pour trouver des défauts de sécurité sans exécuter une application. Alors que l’analyse statique « traditionnelle » est le moyen de détecter les erreurs, SAST se concentre sur la détection des vulnérabilités potentielles.

    À quoi ressemble le SAST pour nous ? Nous prenons des sources, les donnons à l’analyseur et obtenons un rapport avec une liste des défauts de sécurité possibles.

    Ainsi, le but principal de cet article est de répondre à la question de savoir comment exactement les outils SAST recherchent les vulnérabilités potentielles.

    Types d’informations utilisées

    Les solutions SAST n’analysent pas le code source dans une simple représentation textuelle : c’est peu pratique, inefficace et souvent insuffisant. Par conséquent, les analyseurs travaillent avec des représentations de code intermédiaires et plusieurs types d’informations. S’ils sont combinés, ils fournissent la représentation la plus complète d’une application.

    Informations sur la syntaxe

    Les analyseurs fonctionnent avec une représentation de code intermédiaire. Les plus courants sont les arbres de syntaxe (arbre de syntaxe abstraite ou arbre d’analyse).

    Jetons un coup d’œil au modèle d’erreur :

    operand#1 <operator> operand#1

    Le fait est que le même opérande est utilisé à gauche et à droite de l’opérateur. Un tel code peut contenir une erreur lorsqu’une opération de comparaison est utilisée, par exemple.

    Cependant, le cas ci-dessus est particulier et il existe de nombreuses variantes :

    • Un ou les deux opérandes peuvent être placés entre crochets ;
    • L’opérateur peut être non seulement ‘==’, mais aussi ‘!=’, ‘||’, etc.
    • Les opérandes peuvent être des accès à des éléments, des appels de fonction, etc., plutôt que des identificateurs.

    Dans ce cas, il n’est tout simplement pas pratique d’analyser le code comme un texte. C’est là que les arbres de syntaxe peuvent aider.

    Voyons l’expression : a == (a). Son arbre de syntaxe peut ressembler à ceci :

    Jetons un coup d'œil à l'expression.

    De tels arbres sont plus faciles à utiliser : il y a des informations sur la structure et il est facile d’extraire des opérandes et des opérateurs à partir d’expressions. Avez-vous besoin d’omettre les crochets? Aucun problème. Descendez simplement de l’arbre.

    De cette façon, les arbres sont utilisés comme une représentation pratique et structurée du code. Cependant, les arbres de syntaxe seuls ne suffisent pas.

    Informations sémantiques

    Voici un exemple :

    if (lhsVar == rhsVar)
    { .... }

    Si lhsVar et rhsVar sont les variables de la double type, le code peut avoir quelques problèmes. Par exemple, si les deux lhsVar et rhsVar sont précisément égaux à 0.5cette comparaison est true. Cependant, si une valeur est 0.5 et l’autre est 0.4999999999999la vérification donne alors false. La question se pose alors : à quel type de comportement le développeur s’attend-il ? S’il s’attend à ce que la différence se situe dans la marge d’erreur, la comparaison doit être réécrite.

    Supposons que nous aimerions attraper de tels cas. Mais voici le problème : la même comparaison sera tout à fait correcte si les types de lhsVar et rhsVar sont entiers.

    Imaginons : l’analyseur rencontre l’expression suivante lors de la vérification du code :

    if (lhsVar == rhsVar)
    { .... }

    La question est : devons-nous ou non émettre un avertissement dans ce cas ? Vous pouvez regarder l’arborescence et voir que les opérandes sont des identifiants et que l’opération d’infixe est une comparaison. Cependant, nous ne pouvons pas décider si ce cas est dangereux ou non car nous ne connaissons pas les types de lhsVar et rhsVar variables.

    L’information sémantique vient à la rescousse dans ce cas. En utilisant la sémantique, vous pouvez obtenir les données du nœud de l’arbre :

    • Quel type (en termes de langage de programmation) a l’expression de nœud correspondante ;
    • Quelle entité est représentée par le nœud : variable locale, paramètre, champ, etc. ;

    Dans l’exemple ci-dessus, nous avons besoin d’informations sur les types de lhsVaret rhsVar variables. Tout ce que vous avez à faire est d’obtenir ces informations à l’aide d’un modèle sémantique. Si le type de variable est réel, émettez un avertissement.

    Modèle sémanique

    Annotations de fonction

    La syntaxe et la sémantique ne suffisent parfois pas. Regardez l’exemple:

    IEnumerable<int> seq = null;
    var list = Enumerable.ToList(seq);
    ....

    Les ToList la méthode est déclarée dans une bibliothèque externe ; l’analyseur n’a pas accès au code source. Il y a un seq variables avec un nul valeur, qui est transmise au ToList méthode. Est-ce une opération sûre ou non ?

    Utilisons les informations de syntaxe. Vous pouvez déterminer où est le littéral, où est l’identifiant et où est l’appel de méthode. Mais est-ce que l’appel de la méthode est sûr ? Ce n’est pas clair.

    Essayons la sémantique. Vous pouvez comprendre que seq est une variable locale et même trouver sa valeur. Que pouvons-nous apprendre sur Enumerable.ToList? Par exemple, le type de la valeur de retour et le type du paramètre. Est-il sécuritaire de passer nullà ça? Ce n’est pas clair.

    Les annotations sont une solution possible. Les annotations sont un moyen de guider l’analyseur sur ce que fait la méthode, les contraintes qu’elle impose sur les valeurs d’entrée et de retour, etc.

    Annotation pour le ToList méthode dans le code de l’analyseur peut être la suivante :

    Annotation("System.Collections.Generic",
               nameof(Enumerable),
               nameof(Enumerable.ToList),
               AddReturn(ReturnFlags.NotNull), 
               AddArg(ArgFlags.NotNull));

    Les principales informations que contient cette annotation :

    • le nom complet de la méthode (y compris le nom du type et l’espace de noms). En cas de surcharges, des informations supplémentaires sur les paramètres peuvent être nécessaires ;
    • restrictions sur la valeur de retour. ReturnFlags.NotNull signale que la valeur renvoyée ne sera pas null;
    • restrictions sur les valeurs d’entrée. ArgFlags.NotNull spécifie à l’analyseur que le seul argument de la méthode ne doit pas avoir de nullévaluer.

    Reprenons l’exemple initial :

    IEnumerable<int> seq = null;
    var list = Enumerable.ToList(seq);
    ....

    A l’aide du mécanisme d’annotation, l’analyseur reconnaît les limites du ToList méthode. Si l’analyseur suit la valeur de la seqvariable, il pourra émettre un avertissement sur une exception de la NullReferenceException taper.

    Types d’analyse

    Nous avons maintenant un aperçu des informations utilisées pour l’analyse. Parlons donc des types d’analyse.

    Analyse basée sur des modèles

    Parfois, ces erreurs « régulières » sont en fait des failles de sécurité. Regardez cet exemple de vulnérabilité.

    iOS : CVE-2014-1266

    Informations sur la vulnérabilité :

    • ID CVE : CVE-2014-1266
    • CWE-ID : CWE-20 : validation d’entrée incorrecte
    • L’entrée NVD
    • La description: La fonction SSLVerifySignedServerKeyExchange dans libsecurity_ssl/lib/sslKeyExchange.c dans la fonction Secure Transport du composant Data Security dans Apple iOS 6.x avant 6.1.6 et 7.x avant 7.0.6, Apple TV 6.x avant 6.0.2, et Apple OS X 10.9.x antérieur à 10.9.2 ne vérifie pas la signature dans un message d’échange de clé de serveur TLS, ce qui permet aux attaquants de l’intermédiaire d’usurper les serveurs SSL en (1) utilisant une clé privée arbitraire pour la signature étape ou (2) en omettant l’étape de signature.

    Code:

    ....
    if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
      goto fail;
      goto fail;
    if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
      goto fail;
    ....

    A première vue, il peut sembler que tout va bien. En fait, la deuxième goto est inconditionnel. C’est pourquoi le chèque auprès du SSLHashSHA1.final l’appel de méthode n’a jamais été effectué.

    Le code doit être formaté de cette façon :

    ....
    if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
      goto fail;
    goto fail;
    if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
      goto fail;
    ....

    Comment un analyseur statique peut-il détecter ce genre de défaut ?

    La première façon est de voir que goto est inconditionnel et est suivi d’expressions sans aucune étiquette.

    Prenons le code simplifié ayant le même sens :

    {
      if (condition)
        goto fail;
        goto fail;
      ....
    }

    Son arbre de syntaxe peut ressembler à ceci :

    Arbre de syntaxe

    Block est un ensemble d’énoncés. Il ressort également de l’arbre de syntaxe que :

    • La première goto déclaration concerne la if déclaration, tandis que la seconde se rapporte directement au bloc ;
    • Les ExpressionStatement la déclaration est entre GotoStatement et LabeledStatement;
    • goto relatif au bloc est exécuté sans condition, mais il n’y a pas d’étiquette devant le ExpressionStatement. Cela signifie que ExpressionStatement est inaccessible dans ce cas.

    Bien sûr, il s’agit d’un cas particulier d’heuristique. En pratique, ce genre de problème est mieux résolu par des mécanismes plus généraux de calcul de l’accessibilité du code.

    Une autre façon d’attraper le défaut est de vérifier si le formatage du code correspond à la logique d’exécution.

    Un algorithme simplifié serait le suivant :

    1. Examinez l’indentation avant le if déclaration then bifurquer.
    2. Prenez la déclaration suivante après if.
    3. Si une déclaration est sur la ligne suivante après then branche et ils ont la même indentation – émettre un avertissement.

    Les algorithmes sont simplifiés pour plus de clarté et n'incluent pas les cas extrêmes.

    Les algorithmes sont simplifiés pour plus de clarté et n’incluent pas les cas extrêmes. Les règles de diagnostic sont généralement plus compliquées et contiennent plus d’exceptions pour les cas où aucun avertissement n’est nécessaire.

    Analyse des flux de données

    Voici un exemple :

    if (ptr || ptr->foo())
    { .... }

    Les développeurs ont chamboulé la logique du code en mélangeant les opérateurs ‘&&’ et ‘||’. Donc si ptr est un pointeur nul ; c’est déréférencé.

    Dans ce cas, le contexte est local et il est possible de trouver une erreur par analyse basée sur des modèles. Les problèmes surgissent lorsque le contexte se répand. Par example:

    if (ptr)
    { .... }
    // 50 lines of code
    ....
    auto test = ptr->foo();

    Ici le ptr le pointeur est vérifié NULL puis déréférencé sans vérification ; ça a l’air suspect.

    Note: j’utilise NULL dans le texte pour indiquer la valeur du pointeur null, pas comme une macro C.

    Il serait difficile d’attraper un cas similaire dans les modèles. Il est nécessaire d’émettre un avertissement pour l’exemple de code ci-dessus mais pas pour le fragment de code ci-dessous car ptr n’est pas nul…

    Share. Facebook Twitter Pinterest LinkedIn WhatsApp Reddit Email
    Add A Comment

    Leave A Reply Cancel Reply

    Catégories

    • Politique de cookies
    • Politique de confidentialité
    • CONTACT
    • Politique du DMCA
    • CONDITIONS D’UTILISATION
    • Avertissement
    © 2023 DéveloppeurWeb.Com.

    Type above and press Enter to search. Press Esc to cancel.