Blog

Java-Fallen: Bitweise vs. logische Operatoren

February 7, 2021
Alan Richardson
Hände tippen auf einem Laptop, auf dem Code zu sehen ist, mit dem Text „Mastering Secure Coding with Sensei“ und dem Logo von Secure Code Warrior.

Java-Fallen – Bitweise vs. boolesche Operatoren

> „Java-Falle“ – ein häufiges Fehlermuster, das leicht versehentlich implementiert wird.

Eine recht einfache Java-Falle, in die man versehentlich tappen kann, ist die Verwendung eines bitweisen Operators anstelle eines booleschen Vergleichsoperators.

Ein einfacher Tippfehler kann beispielsweise dazu führen, dass man „&“ schreibt, obwohl man eigentlich „&&“ meinte.

Eine gängige Heuristik, die wir bei der Code-Überprüfung lernen, lautet:

> „&“ oder „|“ in einer bedingten Anweisung ist wahrscheinlich nicht beabsichtigt.

In diesem Blogbeitrag untersuchen wir diese Heuristik und zeigen Wege auf, wie wir dieses Programmierproblem identifizieren und beheben können.


Wo liegt das Problem? Bitweise Operationen funktionieren mit Booleans einwandfrei


Die Verwendung von bitweisen Operatoren mit Booleans ist absolut zulässig, daher meldet Java keinen Syntaxfehler.

Wenn ich einen JUnit-Test erstelle, um die Wahrheitstabelle für das bitweise ODER (|) und das bitweise UND (&) zu untersuchen, sehen wir, dass die Ausgaben des bitweisen Operators mit der Wahrheitstabelle übereinstimmen. Angesichts dessen könnte man meinen, dass die Verwendung von bitweisen Operatoren kein Problem darstellt.

UND-Wahrheitstabelle

Three columns on with a, one with b, and the last with (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);
    }


Der Test ist erfolgreich, dies ist absolut valider Java-Code.


ODER-Wahrheitstabelle


Three columns on with a, one with b, and the last with (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);
    }


Dieser Test ist ebenfalls erfolgreich. Warum bevorzugen wir dann „&&“ und „||“?


Die Bilder der Wahrheitstabellen wurden mit dem Truth Table Tool von web.standfor.edu erstellt.


Problem: Kurzschlussauswertung (Short-Circuit)


Das eigentliche Problem liegt im unterschiedlichen Verhalten von bitweisen (&, |) und logischen (&&, ||) Operatoren.

Ein logischer Operator ist ein Kurzschlussoperator und wertet nur so viel aus, wie unbedingt nötig ist.

z. B.

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


Im obigen Code werden beide booleschen Bedingungen ausgewertet, da der bitweise Operator verwendet wurde:

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

Dies macht meinen Code anfällig für eine NullPointerException, falls args null ist, da wir die Prüfung auf args.length immer durchführen – selbst wenn args null ist, weil beide booleschen Bedingungen ausgewertet werden müssen.


Kurzschlussauswertung bei logischen Operatoren


Wenn ein && verwendet wird, z. B.:

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


Sobald wir wissen, dass args != null zu false ausgewertet wird, stoppt die Auswertung des Bedingungsausdrucks.

Wir müssen die rechte Seite nicht mehr auswerten.

Unabhängig vom Ergebnis der Bedingung auf der rechten Seite wird der Gesamtwert des booleschen Ausdrucks false sein.


Aber so etwas würde in produktivem Code niemals passieren


Dies ist ein leicht vermeidbarer Fehler, der von Tools zur statischen Codeanalyse nicht immer erkannt wird.

Ich habe den folgenden Google-Dork verwendet, um zu sehen, ob ich öffentliche Beispiele für dieses Muster finden kann:

filetype:java if "!=null & "
Diese Suche lieferte Code aus Android im RootWindowContainer:
isDocument = intent != null & intent.isDocument()


Dies ist die Art von Code, die ein Code-Review passieren könnte, da wir bitweise Operatoren häufig in Zuweisungen zum Maskieren von Werten verwenden. In diesem Fall ist das Ergebnis jedoch dasselbe wie im obigen if-Beispiel. Wenn intent null ist, wird eine NullPointerException ausgelöst.

Oft kommen wir mit diesem Konstrukt durch, weil wir häufig defensiv programmieren und redundanten Code schreiben. Die Prüfung auf != null ist in den meisten Anwendungsfällen wahrscheinlich überflüssig.

Dies ist ein Fehler, der Programmierern in produktivem Code unterläuft.

Ich weiß nicht, wie aktuell die Suchergebnisse sind, aber als ich die Suche durchführte, erhielt ich Ergebnisse mit Code von: Google, Amazon, Apache... und mir.

Ein kürzlicher Pull Request für eines meiner Open-Source-Projekte zielte genau auf diesen Fehler ab.

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


So finden Sie diesen Fehler


Als ich meinen Beispielcode mit einigen statischen Analyse-Tools prüfte, erkannte keines davon diesen versteckten „Selbstzerstörungscode“.

Als Team bei Secure Code Warrior haben wir ein recht einfaches Sensei-Rezept erstellt und überprüft, das diesen Fehler aufspüren kann.

Da bitweise Operatoren absolut zulässig sind und häufig bei Zuweisungen verwendet werden, haben wir uns bei der Suche nach dem problematischen Code auf den Anwendungsfall von if-Anweisungen und die Verwendung des bitweisen & konzentriert.

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


Dies verwendet einen regulären Ausdruck, um „ & “ zu finden, wenn es als Bedingungsausdruck verwendet wird, z. B. in einer if-Anweisung.

Um das Problem zu beheben, haben wir erneut auf reguläre Ausdrücke zurückgegriffen. Diesmal nutzten wir die sed-Funktion im QuickFix, um das & im Ausdruck global durch && zu ersetzen.

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


Abschließende Anmerkungen

Dies deckt den häufigsten Missbrauch eines bitweisen Operators ab, d. h. wenn eigentlich ein logischer Operator beabsichtigt war.

Es gibt andere Situationen, in denen dies auftreten könnte, z. B. bei Zuweisungen. Beim Schreiben von Rezepten müssen wir jedoch versuchen, falsch-positive Ergebnisse zu vermeiden, da die Rezepte sonst ignoriert oder deaktiviert werden. Wir erstellen Rezepte so, dass sie die häufigsten Vorkommen abdecken. Mit der Weiterentwicklung von Sensei werden wir möglicherweise die Suchfunktion präzisieren, um weitere Übereinstimmungsbedingungen abzudecken.

In seiner jetzigen Form würde dieses Rezept viele der realen Anwendungsfälle identifizieren und vor allem denjenigen, der in meinem Projekt gemeldet wurde.

HINWEIS: Einige Code Warriors haben zu diesem Beispiel und der Überprüfung des Rezepts beigetragen – Charlie Eriksen, Matthieu Calie, Robin Claerhaut, Brysen Ackx, Nathan Desmet, Downey Robersscheuten. Danke für eure Hilfe.


---


Sie können Sensei direkt aus IntelliJ heraus installieren, indem Sie „Preferences \ Plugins“ (Mac) oder „Settings \ Plugins“ (Windows) wählen und dann einfach nach „sensei secure code“ suchen.

Wir haben eine Menge Quellcode und Rezepte für diese Blogbeiträge (einschließlich dieses hier) im Repository `sensei-blog-examples` im GitHub-Account von Secure Code Warrior hinterlegt.

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

Erfahren Sie mehr über Sensei


Slogan

Kontrollieren Sie KI-gestützte Entwicklung, bevor sie in Produktion geht

Bewerten Sie KI-gestützte Risiken, setzen Sie Richtlinien für sicheren Code direkt beim Commit durch und beschleunigen Sie die sichere Bereitstellung über Ihren gesamten SDLC hinweg.

Demo buchen
Ressourcenbibliothek

Weitere Blogs entdecken

Erhalten Sie Zugang zu Experteninhalten über sichere Programmierung, KI-Governance und Software-Risikomanagement.

alle anzeigen
Fallstudie
Filterbezeichnung
Dies ist ein Text innerhalb eines Div-Blocks.

Supercharged Security Awareness: How Tournaments are Inspiring Developers at Erste Group

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.

Mehr erfahren
Fallstudie
Filterbezeichnung
Dies ist ein Text innerhalb eines Div-Blocks.

Security as culture: How Blue Prism cultivates world-class secure developers

Learn how Blue Prism, the global leader in intelligent automation for the enterprise, used Secure Code Warrior's agile learning platform to create a security-first culture with their developers, achieve their business goals, and ship secure code at speed

Mehr erfahren
Fallstudie
Filterbezeichnung
Dies ist ein Text innerhalb eines Div-Blocks.

Eine Sicherheitskultur: Wie Sage sein Champions-Programm aufgebaut hat

Erfahren Sie, wie Sage die Sicherheit durch einen flexiblen, beziehungsorientierten Ansatz gestärkt, über 200 Security Champions ausgebildet und eine messbare Risikoreduzierung erzielt hat.

Mehr erfahren
Blog
Filterbezeichnung
Dies ist ein Text innerhalb eines Div-Blocks.

Cybersecurity Awareness Month 2026: Das Verständnis von KI-Sicherheit ist entscheidend für die Unternehmensverteidigung

Wir haben einen Punkt erreicht, an dem die meisten führenden KI-Unternehmen öffentlich eine weltweite Verlangsamung der KI-Entwicklung gefordert haben, damit die Sicherheitsvorkehrungen Schritt halten können. Doch die Wahrheit ist: Ernsthafte Sicherheitsprobleme sind bereits Realität geworden. Dies bringt unzählige Sicherheitsverantwortliche und Führungsteams in eine dringliche Lage, da die finanziellen Kosten und Risiken durch die Implementierung von KI stetig steigen.

Mehr erfahren
Blog
Filterbezeichnung
Dies ist ein Text innerhalb eines Div-Blocks.

Enabler 8: Branding für Ihr Programm

Ein Programm für sicheres Programmieren braucht mehr als nur großartige Inhalte, um erfolgreich zu sein. Enabler 8 zeigt, wie Branding die Teilnahme zu einem begehrten, statusorientierten Erlebnis macht.

Mehr erfahren
Blog
Filterbezeichnung
Dies ist ein Text innerhalb eines Div-Blocks.

Jeder Mitarbeiter steht jetzt an vorderster Front der KI-Cybersicherheit

Die Unternehmenslandschaft wandelt sich mit einer Geschwindigkeit, die kaum jemand vorhergesehen hat, bis es zu spät war. Wir haben offiziell die Schwelle von handgeschriebenem Code und einfacher Copilot-Unterstützung hin zur Ära des Agentic Development Lifecycle (ADLC) überschritten. Während autonome KI-Agenten eine beispiellose Effizienz in vielen Bereichen versprechen, bringen sie auch eine völlig neue Klasse von Sicherheits- und Regulierungsrisiken mit sich.

Mehr erfahren

Sichere KI-gestützte Entwicklung vor dem Release

Erkennen Sie Entwicklerrisiken, setzen Sie Richtlinien durch und verhindern Sie Schwachstellen über den gesamten Softwareentwicklungszyklus hinweg.

Demo buchen
Keine Elemente gefunden.