Icônes SCW
héros bg sans séparateur
Blog

Les pièges de Java : opérateurs bit à bit et opérateurs booléens

Monsieur Alan Richardson
Publié le 07 février 2021
Dernière mise à jour le 10 mars 2026

Java Gotchas - Opérateurs booléens et opérateurs bitwise

> "Java Gotcha" - un modèle d'erreur courant qu'il est facile de mettre en œuvre accidentellement.

Une erreur Java assez simple à commettre accidentellement est l'utilisation d'un opérateur Bitwise au lieu d'un opérateur de comparaison booléen.

Par exemple, une simple erreur de frappe peut conduire à écrire "&" alors que vous vouliez en réalité écrire "&&".

Une heuristique courante que nous apprenons lors de l'examen du code est la suivante :

> Les mots "&" ou "|" utilisés dans une déclaration conditionnelle ne sont probablement pas destinés à être utilisés.

Dans cet article de blog, nous allons explorer l'heuristique et identifier les moyens d'identifier et de corriger ce problème de codage.


Quel est le problème ? Les opérations bitwise fonctionnent bien avec les booléens


L'utilisation des opérateurs Bitwise avec les booléens est parfaitement valide, de sorte que Java ne signale pas d'erreur de syntaxe.

Si je construis un test JUnit pour explorer une table de vérité à la fois pour Bitwise OR (|) et Bitwise AND (&), nous verrons que les sorties de l'opérateur Bitwise correspondent à la table de vérité. Dans ces conditions, nous pourrions penser que l'utilisation des opérateurs bitwise n'est pas un problème.

Table de vérité AND

Trois colonnes, une avec a, une avec b, et la dernière avec (a^b)


@Test
    void bitwiseOperatorsAndTruthTable(){
          Assertions.assertEquals(true, true & true);
          Assertions.assertEquals(false, true & false);
          Assertions.assertEquals(false, false & true);
          Assertions.assertEquals(false, false & false);
    }


Le test est réussi, il s'agit d'un Java parfaitement valide.


Table de vérité OR


Trois colonnes, une avec a, une avec b, et la dernière avec (a v b)


   @Test
    void bitwiseOperatorsOrTruthTable(){
        Assertions.assertEquals(true, true | true);
        Assertions.assertEquals(true, true | false);
        Assertions.assertEquals(true, false | true);
        Assertions.assertEquals(false, false | false);
    }


Ce test est également réussi, pourquoi préférons-nous "&&" et "||" ?


Les images de la table de vérité ont été créées à l'aide de l'outil outil de table de vérité à partir de web.standfor.edu.


Problème : Fonctionnement en court-circuit


Le vrai problème est la différence de comportement entre les opérateurs binaires (&, |) et booléens (&&, ||).

Un opérateur booléen est un opérateur de court-circuit et n'évalue que ce qui est nécessaire.

par exemple

if (args != null & args.length() > 23) {
    System.out.println(args);
}


Dans le code ci-dessus, les deux conditions booléennes seront évaluées, car l'opérateur Bitwise a été utilisé :

  • args != null
  • args.length() > 23

Cela expose mon code à une NullPointerException si args est nul car nous allons toujours vérifier la longueur de args, même si args est nul car les deux conditions booléennes doivent être évaluées.


Opérateurs booléens Évaluation des courts-circuits


Lorsqu'un && est utilisé, par exemple

if (args != null && args.length() > 23) {
    System.out.println(args);
}


Dès que nous savons que l'expression args != null est évaluée à false, l'évaluation de l'expression de la condition s'arrête.

Nous n'avons pas besoin d'évaluer le côté droit.

Quel que soit le résultat de la condition du côté droit, la valeur finale de l'expression booléenne sera fausse.


Mais cela ne se produirait jamais dans un code de production


Il s'agit d'une erreur assez facile à commettre, qui n'est pas toujours détectée par les outils d'analyse statique.

J'ai utilisé le Google Dork suivant pour voir si je pouvais trouver des exemples publics de ce modèle :

filetype:java if "!=null & "
Cette recherche a permis de retrouver du code d'Android dans le RootWindowContainer
isDocument = intent != null & intent.isDocument()


C'est le type de code qui pourrait passer un examen de code parce que nous utilisons souvent les opérateurs Bitwise dans les instructions d'affectation pour masquer les valeurs. Mais dans ce cas, le résultat est le même que dans l'exemple de l'instruction if ci-dessus. Si intent est null, une exception NullPointerException sera levée.

Très souvent, nous nous en sortons avec cette construction parce que nous codons souvent de manière défensive et écrivons du code redondant. La vérification de != null peut être redondante dans la plupart des cas d'utilisation.

Il s'agit d'une erreur commise par les programmeurs dans le code de production.

Je ne sais pas si les résultats de la recherche sont à jour, mais lorsque j'ai lancé la recherche, j'ai obtenu des résultats avec du code provenant de Google, Amazon, Apache... et de moi.

Une récente demande d'extension sur l'un de mes projets open source visait à résoudre exactement cette erreur.

if(type!=null & type.trim().length()>0){
    acceptMediaTypeDefinitionsList.add(type.trim());
}


Comment le trouver


Lorsque j'ai vérifié mon exemple de code dans quelques analyseurs statiques, aucun d'entre eux n'a détecté ce code d'autodestruction caché.

L'équipe de Secure Code Warrior a créé et examiné une recette assez simple de Sensei qui pourrait répondre à ce besoin.

Les opérateurs Bitwise étant parfaitement valables et souvent utilisés dans les affectations, nous nous sommes concentrés sur l'utilisation des instructions if et sur l'utilisation de Bitwise &, pour trouver le code problématique.

search:
  expression:
    anyOf:
    - in:
        condition: {}
    value:
      caseSensitive: false
      matches: ".* & .*"


Cette fonction utilise une expression régulière pour faire correspondre " & " lorsqu'elle est utilisée comme expression de condition, par exemple dans une instruction if.

Pour y remédier, nous nous sommes à nouveau appuyés sur les expressions régulières. Cette fois-ci, nous avons utilisé la fonction sed de QuickFix pour remplacer globalement le & de l'expression par &&.

availableFixes:
  - name: "Replace bitwise AND operator to logical AND operator"
    actions:
      - rewrite:
          to: "{{#sed}}s/&/&&/g,{{{ . }}}{{/sed}}"


Notes de fin

Cela couvre l'utilisation abusive la plus courante d'un opérateur bitwise, c'est-à-dire lorsqu'un opérateur booléen était en fait prévu.

Il existe d'autres situations où cela pourrait se produire, par exemple dans l'exemple de l'affectation, mais lorsque nous écrivons des recettes, nous devons essayer d'éviter les identifications faussement positives, faute de quoi les recettes seront ignorées ou désactivées. Nous élaborons des recettes qui correspondent aux occurrences les plus courantes. Au fur et à mesure de l'évolution de Sensei , nous pourrons ajouter des spécificités supplémentaires à la fonctionnalité de recherche afin de couvrir davantage de conditions de correspondance.

Dans sa forme actuelle, cette recette permettrait d'identifier de nombreux cas d'utilisation en direct, et surtout celui qui a été rapporté dans le cadre de mon projet.

NOTE : Quelques guerriers du code ont contribué à cet exemple et à la révision de la recette - Charlie Eriksen, Matthieu Calie, Robin Claerhaut, Brysen Ackx, Nathan Desmet, Downey Robersscheuten. Merci pour votre aide.


---


Vous pouvez installer Sensei à partir d'IntelliJ en utilisant "Préférences \NPlugins" (Mac) ou "Paramètres \NPlugins" (Windows) puis en recherchant "sensei secure code".

Nous avons beaucoup de code source et de recettes pour ces articles de blog (y compris celui-ci) dans le dépôt `sensei-blog-examples` dans le compte GitHub Secure Code Warrior .

https://github.com/securecodewarrior/sensei-blog-examples

En savoir plus sur Sensei


Afficher les ressources
Afficher les ressources

Dans cet article de blog, nous examinerons les erreurs courantes dans le codage Java (utilisation d'opérateurs bit à bit à la place d'opérateurs conditionnels), les erreurs qui rendent le code vulnérable et comment utiliser Sensei pour corriger et détecter ces problèmes.

Souhaitez-vous en savoir davantage ?

Alan Richardson a plus de 20 ans d'expérience en tant que développeur, testeur et responsable des tests, à tous les niveaux de la hiérarchie des tests.Secure Code Warrior , où il travaille en étroite collaboration avec l'équipe pour améliorer le développement de code sécurisé et de haute qualité. M. Richardson est l'auteur de quatre ouvrages, dont Dear Evil Tester et Java for Testers. Il a également créé des cours de formation en ligne pour aider les développeurs à apprendre les tests techniques Web et Selenium WebDriver avec Java.M. Alan publie des articles et des vidéos de formation sur SeleniumSimplified.com, EvilTester.com, JavaForTesters.com et CompendiumDev.co.uk.

En savoir plus

Secure Code Warrior vous assiste dans la protection de votre code tout au long du cycle de vie du développement logiciel et dans la création d'une culture qui accorde la priorité à la cybersécurité. Que vous soyez responsable de la sécurité des applications, développeur, responsable de la sécurité des systèmes d'information ou professionnel de la sécurité, nous vous aidons à réduire les risques liés au code non sécurisé.

Veuillez réserver une démonstration.
Partager :
marques LinkedInSocialLogo x
Auteur
Monsieur Alan Richardson
Publié le 07 février 2021

Alan Richardson a plus de 20 ans d'expérience en tant que développeur, testeur et responsable des tests, à tous les niveaux de la hiérarchie des tests.Secure Code Warrior , où il travaille en étroite collaboration avec l'équipe pour améliorer le développement de code sécurisé et de haute qualité. M. Richardson est l'auteur de quatre ouvrages, dont Dear Evil Tester et Java for Testers. Il a également créé des cours de formation en ligne pour aider les développeurs à apprendre les tests techniques Web et Selenium WebDriver avec Java.M. Alan publie des articles et des vidéos de formation sur SeleniumSimplified.com, EvilTester.com, JavaForTesters.com et CompendiumDev.co.uk.

Partager :
marques LinkedInSocialLogo x

Java Gotchas - Opérateurs booléens et opérateurs bitwise

> "Java Gotcha" - un modèle d'erreur courant qu'il est facile de mettre en œuvre accidentellement.

Une erreur Java assez simple à commettre accidentellement est l'utilisation d'un opérateur Bitwise au lieu d'un opérateur de comparaison booléen.

Par exemple, une simple erreur de frappe peut conduire à écrire "&" alors que vous vouliez en réalité écrire "&&".

Une heuristique courante que nous apprenons lors de l'examen du code est la suivante :

> Les mots "&" ou "|" utilisés dans une déclaration conditionnelle ne sont probablement pas destinés à être utilisés.

Dans cet article de blog, nous allons explorer l'heuristique et identifier les moyens d'identifier et de corriger ce problème de codage.


Quel est le problème ? Les opérations bitwise fonctionnent bien avec les booléens


L'utilisation des opérateurs Bitwise avec les booléens est parfaitement valide, de sorte que Java ne signale pas d'erreur de syntaxe.

Si je construis un test JUnit pour explorer une table de vérité à la fois pour Bitwise OR (|) et Bitwise AND (&), nous verrons que les sorties de l'opérateur Bitwise correspondent à la table de vérité. Dans ces conditions, nous pourrions penser que l'utilisation des opérateurs bitwise n'est pas un problème.

Table de vérité AND

Trois colonnes, une avec a, une avec b, et la dernière avec (a^b)


@Test
    void bitwiseOperatorsAndTruthTable(){
          Assertions.assertEquals(true, true & true);
          Assertions.assertEquals(false, true & false);
          Assertions.assertEquals(false, false & true);
          Assertions.assertEquals(false, false & false);
    }


Le test est réussi, il s'agit d'un Java parfaitement valide.


Table de vérité OR


Trois colonnes, une avec a, une avec b, et la dernière avec (a v b)


   @Test
    void bitwiseOperatorsOrTruthTable(){
        Assertions.assertEquals(true, true | true);
        Assertions.assertEquals(true, true | false);
        Assertions.assertEquals(true, false | true);
        Assertions.assertEquals(false, false | false);
    }


Ce test est également réussi, pourquoi préférons-nous "&&" et "||" ?


Les images de la table de vérité ont été créées à l'aide de l'outil outil de table de vérité à partir de web.standfor.edu.


Problème : Fonctionnement en court-circuit


Le vrai problème est la différence de comportement entre les opérateurs binaires (&, |) et booléens (&&, ||).

Un opérateur booléen est un opérateur de court-circuit et n'évalue que ce qui est nécessaire.

par exemple

if (args != null & args.length() > 23) {
    System.out.println(args);
}


Dans le code ci-dessus, les deux conditions booléennes seront évaluées, car l'opérateur Bitwise a été utilisé :

  • args != null
  • args.length() > 23

Cela expose mon code à une NullPointerException si args est nul car nous allons toujours vérifier la longueur de args, même si args est nul car les deux conditions booléennes doivent être évaluées.


Opérateurs booléens Évaluation des courts-circuits


Lorsqu'un && est utilisé, par exemple

if (args != null && args.length() > 23) {
    System.out.println(args);
}


Dès que nous savons que l'expression args != null est évaluée à false, l'évaluation de l'expression de la condition s'arrête.

Nous n'avons pas besoin d'évaluer le côté droit.

Quel que soit le résultat de la condition du côté droit, la valeur finale de l'expression booléenne sera fausse.


Mais cela ne se produirait jamais dans un code de production


Il s'agit d'une erreur assez facile à commettre, qui n'est pas toujours détectée par les outils d'analyse statique.

J'ai utilisé le Google Dork suivant pour voir si je pouvais trouver des exemples publics de ce modèle :

filetype:java if "!=null & "
Cette recherche a permis de retrouver du code d'Android dans le RootWindowContainer
isDocument = intent != null & intent.isDocument()


C'est le type de code qui pourrait passer un examen de code parce que nous utilisons souvent les opérateurs Bitwise dans les instructions d'affectation pour masquer les valeurs. Mais dans ce cas, le résultat est le même que dans l'exemple de l'instruction if ci-dessus. Si intent est null, une exception NullPointerException sera levée.

Très souvent, nous nous en sortons avec cette construction parce que nous codons souvent de manière défensive et écrivons du code redondant. La vérification de != null peut être redondante dans la plupart des cas d'utilisation.

Il s'agit d'une erreur commise par les programmeurs dans le code de production.

Je ne sais pas si les résultats de la recherche sont à jour, mais lorsque j'ai lancé la recherche, j'ai obtenu des résultats avec du code provenant de Google, Amazon, Apache... et de moi.

Une récente demande d'extension sur l'un de mes projets open source visait à résoudre exactement cette erreur.

if(type!=null & type.trim().length()>0){
    acceptMediaTypeDefinitionsList.add(type.trim());
}


Comment le trouver


Lorsque j'ai vérifié mon exemple de code dans quelques analyseurs statiques, aucun d'entre eux n'a détecté ce code d'autodestruction caché.

L'équipe de Secure Code Warrior a créé et examiné une recette assez simple de Sensei qui pourrait répondre à ce besoin.

Les opérateurs Bitwise étant parfaitement valables et souvent utilisés dans les affectations, nous nous sommes concentrés sur l'utilisation des instructions if et sur l'utilisation de Bitwise &, pour trouver le code problématique.

search:
  expression:
    anyOf:
    - in:
        condition: {}
    value:
      caseSensitive: false
      matches: ".* & .*"


Cette fonction utilise une expression régulière pour faire correspondre " & " lorsqu'elle est utilisée comme expression de condition, par exemple dans une instruction if.

Pour y remédier, nous nous sommes à nouveau appuyés sur les expressions régulières. Cette fois-ci, nous avons utilisé la fonction sed de QuickFix pour remplacer globalement le & de l'expression par &&.

availableFixes:
  - name: "Replace bitwise AND operator to logical AND operator"
    actions:
      - rewrite:
          to: "{{#sed}}s/&/&&/g,{{{ . }}}{{/sed}}"


Notes de fin

Cela couvre l'utilisation abusive la plus courante d'un opérateur bitwise, c'est-à-dire lorsqu'un opérateur booléen était en fait prévu.

Il existe d'autres situations où cela pourrait se produire, par exemple dans l'exemple de l'affectation, mais lorsque nous écrivons des recettes, nous devons essayer d'éviter les identifications faussement positives, faute de quoi les recettes seront ignorées ou désactivées. Nous élaborons des recettes qui correspondent aux occurrences les plus courantes. Au fur et à mesure de l'évolution de Sensei , nous pourrons ajouter des spécificités supplémentaires à la fonctionnalité de recherche afin de couvrir davantage de conditions de correspondance.

Dans sa forme actuelle, cette recette permettrait d'identifier de nombreux cas d'utilisation en direct, et surtout celui qui a été rapporté dans le cadre de mon projet.

NOTE : Quelques guerriers du code ont contribué à cet exemple et à la révision de la recette - Charlie Eriksen, Matthieu Calie, Robin Claerhaut, Brysen Ackx, Nathan Desmet, Downey Robersscheuten. Merci pour votre aide.


---


Vous pouvez installer Sensei à partir d'IntelliJ en utilisant "Préférences \NPlugins" (Mac) ou "Paramètres \NPlugins" (Windows) puis en recherchant "sensei secure code".

Nous avons beaucoup de code source et de recettes pour ces articles de blog (y compris celui-ci) dans le dépôt `sensei-blog-examples` dans le compte GitHub Secure Code Warrior .

https://github.com/securecodewarrior/sensei-blog-examples

En savoir plus sur Sensei


Afficher les ressources
Afficher les ressources

Pour télécharger le rapport, veuillez remplir le formulaire ci-dessous.

Nous vous prions de bien vouloir nous autoriser à vous envoyer des informations sur nos produits et/ou sur des sujets liés au codage sécurisé. Nous traitons vos informations personnelles avec le plus grand soin et ne les vendons jamais à des tiers à des fins marketing.

Envoi
icône de réussite scw
icône d'erreur scw
Pour envoyer le formulaire, veuillez activer le cookie « Analytics ». Une fois le paramétrage terminé, vous pouvez le désactiver à nouveau.

Java Gotchas - Opérateurs booléens et opérateurs bitwise

> "Java Gotcha" - un modèle d'erreur courant qu'il est facile de mettre en œuvre accidentellement.

Une erreur Java assez simple à commettre accidentellement est l'utilisation d'un opérateur Bitwise au lieu d'un opérateur de comparaison booléen.

Par exemple, une simple erreur de frappe peut conduire à écrire "&" alors que vous vouliez en réalité écrire "&&".

Une heuristique courante que nous apprenons lors de l'examen du code est la suivante :

> Les mots "&" ou "|" utilisés dans une déclaration conditionnelle ne sont probablement pas destinés à être utilisés.

Dans cet article de blog, nous allons explorer l'heuristique et identifier les moyens d'identifier et de corriger ce problème de codage.


Quel est le problème ? Les opérations bitwise fonctionnent bien avec les booléens


L'utilisation des opérateurs Bitwise avec les booléens est parfaitement valide, de sorte que Java ne signale pas d'erreur de syntaxe.

Si je construis un test JUnit pour explorer une table de vérité à la fois pour Bitwise OR (|) et Bitwise AND (&), nous verrons que les sorties de l'opérateur Bitwise correspondent à la table de vérité. Dans ces conditions, nous pourrions penser que l'utilisation des opérateurs bitwise n'est pas un problème.

Table de vérité AND

Trois colonnes, une avec a, une avec b, et la dernière avec (a^b)


@Test
    void bitwiseOperatorsAndTruthTable(){
          Assertions.assertEquals(true, true & true);
          Assertions.assertEquals(false, true & false);
          Assertions.assertEquals(false, false & true);
          Assertions.assertEquals(false, false & false);
    }


Le test est réussi, il s'agit d'un Java parfaitement valide.


Table de vérité OR


Trois colonnes, une avec a, une avec b, et la dernière avec (a v b)


   @Test
    void bitwiseOperatorsOrTruthTable(){
        Assertions.assertEquals(true, true | true);
        Assertions.assertEquals(true, true | false);
        Assertions.assertEquals(true, false | true);
        Assertions.assertEquals(false, false | false);
    }


Ce test est également réussi, pourquoi préférons-nous "&&" et "||" ?


Les images de la table de vérité ont été créées à l'aide de l'outil outil de table de vérité à partir de web.standfor.edu.


Problème : Fonctionnement en court-circuit


Le vrai problème est la différence de comportement entre les opérateurs binaires (&, |) et booléens (&&, ||).

Un opérateur booléen est un opérateur de court-circuit et n'évalue que ce qui est nécessaire.

par exemple

if (args != null & args.length() > 23) {
    System.out.println(args);
}


Dans le code ci-dessus, les deux conditions booléennes seront évaluées, car l'opérateur Bitwise a été utilisé :

  • args != null
  • args.length() > 23

Cela expose mon code à une NullPointerException si args est nul car nous allons toujours vérifier la longueur de args, même si args est nul car les deux conditions booléennes doivent être évaluées.


Opérateurs booléens Évaluation des courts-circuits


Lorsqu'un && est utilisé, par exemple

if (args != null && args.length() > 23) {
    System.out.println(args);
}


Dès que nous savons que l'expression args != null est évaluée à false, l'évaluation de l'expression de la condition s'arrête.

Nous n'avons pas besoin d'évaluer le côté droit.

Quel que soit le résultat de la condition du côté droit, la valeur finale de l'expression booléenne sera fausse.


Mais cela ne se produirait jamais dans un code de production


Il s'agit d'une erreur assez facile à commettre, qui n'est pas toujours détectée par les outils d'analyse statique.

J'ai utilisé le Google Dork suivant pour voir si je pouvais trouver des exemples publics de ce modèle :

filetype:java if "!=null & "
Cette recherche a permis de retrouver du code d'Android dans le RootWindowContainer
isDocument = intent != null & intent.isDocument()


C'est le type de code qui pourrait passer un examen de code parce que nous utilisons souvent les opérateurs Bitwise dans les instructions d'affectation pour masquer les valeurs. Mais dans ce cas, le résultat est le même que dans l'exemple de l'instruction if ci-dessus. Si intent est null, une exception NullPointerException sera levée.

Très souvent, nous nous en sortons avec cette construction parce que nous codons souvent de manière défensive et écrivons du code redondant. La vérification de != null peut être redondante dans la plupart des cas d'utilisation.

Il s'agit d'une erreur commise par les programmeurs dans le code de production.

Je ne sais pas si les résultats de la recherche sont à jour, mais lorsque j'ai lancé la recherche, j'ai obtenu des résultats avec du code provenant de Google, Amazon, Apache... et de moi.

Une récente demande d'extension sur l'un de mes projets open source visait à résoudre exactement cette erreur.

if(type!=null & type.trim().length()>0){
    acceptMediaTypeDefinitionsList.add(type.trim());
}


Comment le trouver


Lorsque j'ai vérifié mon exemple de code dans quelques analyseurs statiques, aucun d'entre eux n'a détecté ce code d'autodestruction caché.

L'équipe de Secure Code Warrior a créé et examiné une recette assez simple de Sensei qui pourrait répondre à ce besoin.

Les opérateurs Bitwise étant parfaitement valables et souvent utilisés dans les affectations, nous nous sommes concentrés sur l'utilisation des instructions if et sur l'utilisation de Bitwise &, pour trouver le code problématique.

search:
  expression:
    anyOf:
    - in:
        condition: {}
    value:
      caseSensitive: false
      matches: ".* & .*"


Cette fonction utilise une expression régulière pour faire correspondre " & " lorsqu'elle est utilisée comme expression de condition, par exemple dans une instruction if.

Pour y remédier, nous nous sommes à nouveau appuyés sur les expressions régulières. Cette fois-ci, nous avons utilisé la fonction sed de QuickFix pour remplacer globalement le & de l'expression par &&.

availableFixes:
  - name: "Replace bitwise AND operator to logical AND operator"
    actions:
      - rewrite:
          to: "{{#sed}}s/&/&&/g,{{{ . }}}{{/sed}}"


Notes de fin

Cela couvre l'utilisation abusive la plus courante d'un opérateur bitwise, c'est-à-dire lorsqu'un opérateur booléen était en fait prévu.

Il existe d'autres situations où cela pourrait se produire, par exemple dans l'exemple de l'affectation, mais lorsque nous écrivons des recettes, nous devons essayer d'éviter les identifications faussement positives, faute de quoi les recettes seront ignorées ou désactivées. Nous élaborons des recettes qui correspondent aux occurrences les plus courantes. Au fur et à mesure de l'évolution de Sensei , nous pourrons ajouter des spécificités supplémentaires à la fonctionnalité de recherche afin de couvrir davantage de conditions de correspondance.

Dans sa forme actuelle, cette recette permettrait d'identifier de nombreux cas d'utilisation en direct, et surtout celui qui a été rapporté dans le cadre de mon projet.

NOTE : Quelques guerriers du code ont contribué à cet exemple et à la révision de la recette - Charlie Eriksen, Matthieu Calie, Robin Claerhaut, Brysen Ackx, Nathan Desmet, Downey Robersscheuten. Merci pour votre aide.


---


Vous pouvez installer Sensei à partir d'IntelliJ en utilisant "Préférences \NPlugins" (Mac) ou "Paramètres \NPlugins" (Windows) puis en recherchant "sensei secure code".

Nous avons beaucoup de code source et de recettes pour ces articles de blog (y compris celui-ci) dans le dépôt `sensei-blog-examples` dans le compte GitHub Secure Code Warrior .

https://github.com/securecodewarrior/sensei-blog-examples

En savoir plus sur Sensei


Veuillez consulter le séminaire en ligne.
Commençons
En savoir plus

Veuillez cliquer sur le lien ci-dessous pour télécharger le PDF de cette ressource.

Secure Code Warrior vous assiste dans la protection de votre code tout au long du cycle de vie du développement logiciel et dans la création d'une culture qui accorde la priorité à la cybersécurité. Que vous soyez responsable de la sécurité des applications, développeur, responsable de la sécurité des systèmes d'information ou professionnel de la sécurité, nous vous aidons à réduire les risques liés au code non sécurisé.

Afficher le rapportVeuillez réserver une démonstration.
Télécharger le PDF
Afficher les ressources
Partager :
marques LinkedInSocialLogo x
Souhaitez-vous en savoir davantage ?

Partager :
marques LinkedInSocialLogo x
Auteur
Monsieur Alan Richardson
Publié le 07 février 2021

Alan Richardson a plus de 20 ans d'expérience en tant que développeur, testeur et responsable des tests, à tous les niveaux de la hiérarchie des tests.Secure Code Warrior , où il travaille en étroite collaboration avec l'équipe pour améliorer le développement de code sécurisé et de haute qualité. M. Richardson est l'auteur de quatre ouvrages, dont Dear Evil Tester et Java for Testers. Il a également créé des cours de formation en ligne pour aider les développeurs à apprendre les tests techniques Web et Selenium WebDriver avec Java.M. Alan publie des articles et des vidéos de formation sur SeleniumSimplified.com, EvilTester.com, JavaForTesters.com et CompendiumDev.co.uk.

Partager :
marques LinkedInSocialLogo x

Java Gotchas - Opérateurs booléens et opérateurs bitwise

> "Java Gotcha" - un modèle d'erreur courant qu'il est facile de mettre en œuvre accidentellement.

Une erreur Java assez simple à commettre accidentellement est l'utilisation d'un opérateur Bitwise au lieu d'un opérateur de comparaison booléen.

Par exemple, une simple erreur de frappe peut conduire à écrire "&" alors que vous vouliez en réalité écrire "&&".

Une heuristique courante que nous apprenons lors de l'examen du code est la suivante :

> Les mots "&" ou "|" utilisés dans une déclaration conditionnelle ne sont probablement pas destinés à être utilisés.

Dans cet article de blog, nous allons explorer l'heuristique et identifier les moyens d'identifier et de corriger ce problème de codage.


Quel est le problème ? Les opérations bitwise fonctionnent bien avec les booléens


L'utilisation des opérateurs Bitwise avec les booléens est parfaitement valide, de sorte que Java ne signale pas d'erreur de syntaxe.

Si je construis un test JUnit pour explorer une table de vérité à la fois pour Bitwise OR (|) et Bitwise AND (&), nous verrons que les sorties de l'opérateur Bitwise correspondent à la table de vérité. Dans ces conditions, nous pourrions penser que l'utilisation des opérateurs bitwise n'est pas un problème.

Table de vérité AND

Trois colonnes, une avec a, une avec b, et la dernière avec (a^b)


@Test
    void bitwiseOperatorsAndTruthTable(){
          Assertions.assertEquals(true, true & true);
          Assertions.assertEquals(false, true & false);
          Assertions.assertEquals(false, false & true);
          Assertions.assertEquals(false, false & false);
    }


Le test est réussi, il s'agit d'un Java parfaitement valide.


Table de vérité OR


Trois colonnes, une avec a, une avec b, et la dernière avec (a v b)


   @Test
    void bitwiseOperatorsOrTruthTable(){
        Assertions.assertEquals(true, true | true);
        Assertions.assertEquals(true, true | false);
        Assertions.assertEquals(true, false | true);
        Assertions.assertEquals(false, false | false);
    }


Ce test est également réussi, pourquoi préférons-nous "&&" et "||" ?


Les images de la table de vérité ont été créées à l'aide de l'outil outil de table de vérité à partir de web.standfor.edu.


Problème : Fonctionnement en court-circuit


Le vrai problème est la différence de comportement entre les opérateurs binaires (&, |) et booléens (&&, ||).

Un opérateur booléen est un opérateur de court-circuit et n'évalue que ce qui est nécessaire.

par exemple

if (args != null & args.length() > 23) {
    System.out.println(args);
}


Dans le code ci-dessus, les deux conditions booléennes seront évaluées, car l'opérateur Bitwise a été utilisé :

  • args != null
  • args.length() > 23

Cela expose mon code à une NullPointerException si args est nul car nous allons toujours vérifier la longueur de args, même si args est nul car les deux conditions booléennes doivent être évaluées.


Opérateurs booléens Évaluation des courts-circuits


Lorsqu'un && est utilisé, par exemple

if (args != null && args.length() > 23) {
    System.out.println(args);
}


Dès que nous savons que l'expression args != null est évaluée à false, l'évaluation de l'expression de la condition s'arrête.

Nous n'avons pas besoin d'évaluer le côté droit.

Quel que soit le résultat de la condition du côté droit, la valeur finale de l'expression booléenne sera fausse.


Mais cela ne se produirait jamais dans un code de production


Il s'agit d'une erreur assez facile à commettre, qui n'est pas toujours détectée par les outils d'analyse statique.

J'ai utilisé le Google Dork suivant pour voir si je pouvais trouver des exemples publics de ce modèle :

filetype:java if "!=null & "
Cette recherche a permis de retrouver du code d'Android dans le RootWindowContainer
isDocument = intent != null & intent.isDocument()


C'est le type de code qui pourrait passer un examen de code parce que nous utilisons souvent les opérateurs Bitwise dans les instructions d'affectation pour masquer les valeurs. Mais dans ce cas, le résultat est le même que dans l'exemple de l'instruction if ci-dessus. Si intent est null, une exception NullPointerException sera levée.

Très souvent, nous nous en sortons avec cette construction parce que nous codons souvent de manière défensive et écrivons du code redondant. La vérification de != null peut être redondante dans la plupart des cas d'utilisation.

Il s'agit d'une erreur commise par les programmeurs dans le code de production.

Je ne sais pas si les résultats de la recherche sont à jour, mais lorsque j'ai lancé la recherche, j'ai obtenu des résultats avec du code provenant de Google, Amazon, Apache... et de moi.

Une récente demande d'extension sur l'un de mes projets open source visait à résoudre exactement cette erreur.

if(type!=null & type.trim().length()>0){
    acceptMediaTypeDefinitionsList.add(type.trim());
}


Comment le trouver


Lorsque j'ai vérifié mon exemple de code dans quelques analyseurs statiques, aucun d'entre eux n'a détecté ce code d'autodestruction caché.

L'équipe de Secure Code Warrior a créé et examiné une recette assez simple de Sensei qui pourrait répondre à ce besoin.

Les opérateurs Bitwise étant parfaitement valables et souvent utilisés dans les affectations, nous nous sommes concentrés sur l'utilisation des instructions if et sur l'utilisation de Bitwise &, pour trouver le code problématique.

search:
  expression:
    anyOf:
    - in:
        condition: {}
    value:
      caseSensitive: false
      matches: ".* & .*"


Cette fonction utilise une expression régulière pour faire correspondre " & " lorsqu'elle est utilisée comme expression de condition, par exemple dans une instruction if.

Pour y remédier, nous nous sommes à nouveau appuyés sur les expressions régulières. Cette fois-ci, nous avons utilisé la fonction sed de QuickFix pour remplacer globalement le & de l'expression par &&.

availableFixes:
  - name: "Replace bitwise AND operator to logical AND operator"
    actions:
      - rewrite:
          to: "{{#sed}}s/&/&&/g,{{{ . }}}{{/sed}}"


Notes de fin

Cela couvre l'utilisation abusive la plus courante d'un opérateur bitwise, c'est-à-dire lorsqu'un opérateur booléen était en fait prévu.

Il existe d'autres situations où cela pourrait se produire, par exemple dans l'exemple de l'affectation, mais lorsque nous écrivons des recettes, nous devons essayer d'éviter les identifications faussement positives, faute de quoi les recettes seront ignorées ou désactivées. Nous élaborons des recettes qui correspondent aux occurrences les plus courantes. Au fur et à mesure de l'évolution de Sensei , nous pourrons ajouter des spécificités supplémentaires à la fonctionnalité de recherche afin de couvrir davantage de conditions de correspondance.

Dans sa forme actuelle, cette recette permettrait d'identifier de nombreux cas d'utilisation en direct, et surtout celui qui a été rapporté dans le cadre de mon projet.

NOTE : Quelques guerriers du code ont contribué à cet exemple et à la révision de la recette - Charlie Eriksen, Matthieu Calie, Robin Claerhaut, Brysen Ackx, Nathan Desmet, Downey Robersscheuten. Merci pour votre aide.


---


Vous pouvez installer Sensei à partir d'IntelliJ en utilisant "Préférences \NPlugins" (Mac) ou "Paramètres \NPlugins" (Windows) puis en recherchant "sensei secure code".

Nous avons beaucoup de code source et de recettes pour ces articles de blog (y compris celui-ci) dans le dépôt `sensei-blog-examples` dans le compte GitHub Secure Code Warrior .

https://github.com/securecodewarrior/sensei-blog-examples

En savoir plus sur Sensei


Table des matières

Télécharger le PDF
Afficher les ressources
Souhaitez-vous en savoir davantage ?

Alan Richardson a plus de 20 ans d'expérience en tant que développeur, testeur et responsable des tests, à tous les niveaux de la hiérarchie des tests.Secure Code Warrior , où il travaille en étroite collaboration avec l'équipe pour améliorer le développement de code sécurisé et de haute qualité. M. Richardson est l'auteur de quatre ouvrages, dont Dear Evil Tester et Java for Testers. Il a également créé des cours de formation en ligne pour aider les développeurs à apprendre les tests techniques Web et Selenium WebDriver avec Java.M. Alan publie des articles et des vidéos de formation sur SeleniumSimplified.com, EvilTester.com, JavaForTesters.com et CompendiumDev.co.uk.

En savoir plus

Secure Code Warrior vous assiste dans la protection de votre code tout au long du cycle de vie du développement logiciel et dans la création d'une culture qui accorde la priorité à la cybersécurité. Que vous soyez responsable de la sécurité des applications, développeur, responsable de la sécurité des systèmes d'information ou professionnel de la sécurité, nous vous aidons à réduire les risques liés au code non sécurisé.

Veuillez réserver une démonstration.[Télécharger]
Partager :
marques LinkedInSocialLogo x
Centre de ressources

Ressources pour débuter

Autres publications
Centre de ressources

Ressources pour débuter

Autres publications