
Los errores de Java: operadores bitwise frente a operadores booleanos
Los errores de Java: operadores bitwise frente a operadores booleanos
«Java Gotcha»: un patrón de error común que es fácil de implementar accidentalmente.
Un truco de Java bastante simple en el que caer accidentalmente es: usar un operador bit a bit en lugar de un operador de comparación booleano.
Por ejemplo, un simple error de escritura puede resultar en escribir «&» cuando realmente querías escribir «&&».
Una heurística común que aprendemos al revisar el código es:
«&» o «|» cuando se usan en una declaración condicional probablemente no sean intencionales.
En esta entrada del blog, exploraremos la heurística e identificaremos formas en las que podemos identificar y solucionar este problema de codificación.
¿Cuál es el problema? Las operaciones bit a bit funcionan bien con los valores booleanos.
El uso de operadores bit a bit con booleanos es perfectamente válido, por lo que Java no notificará ningún error de sintaxis.
Si construyo una prueba JUnit para explorar una tabla de verdad tanto para Bitwise OR (|) como para Bitwise AND (&), veremos que las salidas del operador Bitwise coinciden con la tabla de verdad. En vista de esto, podríamos pensar que el uso de operadores Bitwise no es un problema.
Y Tabla de la verdad

@Test
void BitwiseOperatorsAndTruthTable () {
Assertions.assertEquals (verdadero, verdadero y verdadero);
Assertions.assertEquals (falso, verdadero y falso);
Assertions.assertEquals (falso, falso y verdadero);
Assertions.assertEquals (falso, falso y falso);
}
La prueba pasa, esto es Java perfectamente válido.
La tabla de la verdad

@Test
anular BitwiseOperatorSorTruthTable () {
Assertions.assertEquals (verdadero, verdadero | verdadero);
Assertions.assertEquals (verdadero, verdadero | falso);
Assertions.assertEquals (verdadero, falso | verdadero);
Assertions.assertEquals (falso, falso | falso);
}
Esta prueba también pasa, ¿por qué preferimos «&&» y «||»?
Las imágenes de la tabla de verdad se crearon utilizando la herramienta de tabla de verdad de web.standfor.edu.
Problema: Funcionamiento en cortocircuito
El verdadero problema es la diferencia de comportamiento entre los operadores bitwise (&, |) y booleanos (&&, ||).
Un operador booleano es un operador de cortocircuito y solo evalúa lo necesario.
por ejemplo
si (args! = nulo & args.length () > 23) {
System.out.println (argumentos);
}
En el código anterior, se evaluarán ambas condiciones booleanas, porque se ha utilizado el operador Bitwise:
- argumentos! = nulo
- args.length () > 23
Esto deja mi código abierto a una NullPointerException si args es nulo porque siempre realizaremos la verificación de args.length, incluso cuando args sea nulo porque se deben evaluar ambas condiciones booleanas.
Evaluación de cortocircuitos de operadores booleanos
Cuando se usa un &&, p. ej.
si (args! = nulo && args.length () > 23) {
System.out.println (argumentos);
}
¡En cuanto sepamos que es un argumento! = null se evalúa como falso, la evaluación de la expresión de condición se detiene.
No necesitamos evaluar el lado derecho.
Sea cual sea el resultado de la condición del lado derecho, el valor final de la expresión booleana será falso.
Pero esto nunca sucedería en el código de producción.
Este es un error bastante fácil de cometer y las herramientas de análisis estático no siempre lo detectan.
Utilicé el siguiente Google Dork para ver si podía encontrar algún ejemplo público de este patrón:
tipo de archivo: java si es «! =nulo &»
Esta búsqueda devolvió un código de Android en el RootWindowContainer
isDocument = intención! = nulo & intent.isDocument ()
Este es el tipo de código que puede pasar una revisión de código, ya que a menudo utilizamos operadores bit a bit en las sentencias de asignación para enmascarar los valores. Pero en este caso, el resultado es el mismo que en el ejemplo anterior de la sentencia if. Si la intención es alguna vez nula, se lanzará una NullPointerException.
Muy a menudo nos salimos con la nuestra con esta construcción porque a menudo codificamos a la defensiva y escribimos código redundante. ¡El cheque para! = null puede resultar redundante en la mayoría de los casos de uso.
Se trata de un error cometido por los programadores en el código de producción.
No sé qué tan actuales son los resultados de la búsqueda, pero cuando la ejecuté, aparecieron resultados con código de: Google, Amazon, Apache... y yo.
Una reciente solicitud de extracción en uno de mis proyectos de código abierto fue solucionar exactamente este error.
si (escriba! =nulo y escribe.trim () .length () >0) {
Aceptar MediaTypeDefinitionsList.add (type.trim ());
}
Cómo encontrar esto
Cuando comprobé mi código de muestra en algunos analizadores estáticos, ninguno de ellos detectó este código oculto de autodestrucción.
Como equipo de Secure Code Warrior, hemos creado y revisado una receta de Sensei sencilla que podría responder a esta pregunta.
Como los operadores Bitwise son perfectamente válidos y se utilizan con frecuencia en las asignaciones, nos centramos en el caso de uso de las sentencias if y en el uso de Bitwise & para encontrar el código problemático.
buscar:
expresión:
Cualquiera de:
- en:
condición: {}
valor:
Sensible a mayúsculas y minúsculas: falso
coincidencias: «.* & . *»
Esto usa una expresión regular para que coincida con "&» cuando se usa como expresión de condición, por ejemplo, en una sentencia if.
Para solucionarlo, volvimos a confiar en expresiones regulares. Esta vez, utilizamos la función sed del QuickFix para reemplazar globalmente el & de la expresión por &&.
Correcciones disponibles:
- nombre: «Reemplazar el operador AND bit a bit por el operador AND lógico»
acciones:
- reescribir:
a: «{{#sed}} s/&/&&/g, {{{.}}} {{/sed}}»
Notas finales
Esto cubre el uso indebido más común de un operador bit a bit, es decir, cuando realmente se pretendía utilizar un operador booleano.
Hay otras situaciones en las que esto podría surgir, por ejemplo, en el ejemplo de una tarea, pero al escribir recetas debemos intentar evitar la identificación de falsos positivos; de lo contrario, las recetas se ignorarán o se desactivarán. Creamos recetas para que coincidan con las ocurrencias más comunes. A medida que Sensei , es muy posible que añadamos especificidad adicional a la función de búsqueda para cubrir más condiciones coincidentes.
En su forma actual, esta receta identificaría muchos de los casos de uso actuales y, lo más importante, el que se informó en mi proyecto.
NOTA: Unos pocos guerreros del código contribuyeron a este ejemplo y revisión de recetas: Charlie Eriksen, Matthieu Calie, Robin Claerhaut, Brysen Ackx, Nathan Desmet y Downey Robersscheuten. Gracias por tu ayuda.
---
Puede instalar Sensei IntelliJ mediante «Preferencias\ Plugins» (Mac) o «Configuración\ Plugins» (Windows) y, a continuación, buscar «código seguro de sensei
Tenemos muchos códigos fuente y recetas para estas entradas de blog (incluida esta) en el repositorio `sensei` de la cuenta de GitHub de Secure Code Warrior.
https://github.com/securecodewarrior/sensei-blog-examples
En esta entrada de blog analizamos un error común de codificación en Java (usar un operador bit a bit en lugar de un operador condicional), el error que hace que nuestro código sea vulnerable y cómo podemos usar Sensei corregir y detectar el problema.
Alan Richardson cuenta con más de veinte años de experiencia profesional en TI, trabajando como desarrollador y en todos los niveles de la jerarquía de pruebas, desde probador hasta jefe de pruebas. Jefe de Relaciones con los Desarrolladores en Secure Code Warrior, trabaja directamente con los equipos, para mejorar el desarrollo de un código seguro de calidad. Alan es autor de cuatro libros, entre ellos "Dear Evil Tester" y "Java For Testers". Alan también ha creado una formación en línea courses para ayudar a la gente a aprender las pruebas técnicas de la web y Selenium WebDriver con Java. Alan publica sus escritos y vídeos de formación en SeleniumSimplified.com, EvilTester.com, JavaForTesters.com, y CompendiumDev.co.uk.

Secure Code Warrior aquí para que su organización le ayude a proteger el código durante todo el ciclo de vida del desarrollo de software y a crear una cultura en la que la ciberseguridad sea una prioridad. Ya sea administrador de AppSec, desarrollador, CISO o cualquier persona relacionada con la seguridad, podemos ayudar a su organización a reducir los riesgos asociados con el código inseguro.
Reserve una demostraciónAlan Richardson cuenta con más de veinte años de experiencia profesional en TI, trabajando como desarrollador y en todos los niveles de la jerarquía de pruebas, desde probador hasta jefe de pruebas. Jefe de Relaciones con los Desarrolladores en Secure Code Warrior, trabaja directamente con los equipos, para mejorar el desarrollo de un código seguro de calidad. Alan es autor de cuatro libros, entre ellos "Dear Evil Tester" y "Java For Testers". Alan también ha creado una formación en línea courses para ayudar a la gente a aprender las pruebas técnicas de la web y Selenium WebDriver con Java. Alan publica sus escritos y vídeos de formación en SeleniumSimplified.com, EvilTester.com, JavaForTesters.com, y CompendiumDev.co.uk.
Los errores de Java: operadores bitwise frente a operadores booleanos
«Java Gotcha»: un patrón de error común que es fácil de implementar accidentalmente.
Un truco de Java bastante simple en el que caer accidentalmente es: usar un operador bit a bit en lugar de un operador de comparación booleano.
Por ejemplo, un simple error de escritura puede resultar en escribir «&» cuando realmente querías escribir «&&».
Una heurística común que aprendemos al revisar el código es:
«&» o «|» cuando se usan en una declaración condicional probablemente no sean intencionales.
En esta entrada del blog, exploraremos la heurística e identificaremos formas en las que podemos identificar y solucionar este problema de codificación.
¿Cuál es el problema? Las operaciones bit a bit funcionan bien con los valores booleanos.
El uso de operadores bit a bit con booleanos es perfectamente válido, por lo que Java no notificará ningún error de sintaxis.
Si construyo una prueba JUnit para explorar una tabla de verdad tanto para Bitwise OR (|) como para Bitwise AND (&), veremos que las salidas del operador Bitwise coinciden con la tabla de verdad. En vista de esto, podríamos pensar que el uso de operadores Bitwise no es un problema.
Y Tabla de la verdad

@Test
void BitwiseOperatorsAndTruthTable () {
Assertions.assertEquals (verdadero, verdadero y verdadero);
Assertions.assertEquals (falso, verdadero y falso);
Assertions.assertEquals (falso, falso y verdadero);
Assertions.assertEquals (falso, falso y falso);
}
La prueba pasa, esto es Java perfectamente válido.
La tabla de la verdad

@Test
anular BitwiseOperatorSorTruthTable () {
Assertions.assertEquals (verdadero, verdadero | verdadero);
Assertions.assertEquals (verdadero, verdadero | falso);
Assertions.assertEquals (verdadero, falso | verdadero);
Assertions.assertEquals (falso, falso | falso);
}
Esta prueba también pasa, ¿por qué preferimos «&&» y «||»?
Las imágenes de la tabla de verdad se crearon utilizando la herramienta de tabla de verdad de web.standfor.edu.
Problema: Funcionamiento en cortocircuito
El verdadero problema es la diferencia de comportamiento entre los operadores bitwise (&, |) y booleanos (&&, ||).
Un operador booleano es un operador de cortocircuito y solo evalúa lo necesario.
por ejemplo
si (args! = nulo & args.length () > 23) {
System.out.println (argumentos);
}
En el código anterior, se evaluarán ambas condiciones booleanas, porque se ha utilizado el operador Bitwise:
- argumentos! = nulo
- args.length () > 23
Esto deja mi código abierto a una NullPointerException si args es nulo porque siempre realizaremos la verificación de args.length, incluso cuando args sea nulo porque se deben evaluar ambas condiciones booleanas.
Evaluación de cortocircuitos de operadores booleanos
Cuando se usa un &&, p. ej.
si (args! = nulo && args.length () > 23) {
System.out.println (argumentos);
}
¡En cuanto sepamos que es un argumento! = null se evalúa como falso, la evaluación de la expresión de condición se detiene.
No necesitamos evaluar el lado derecho.
Sea cual sea el resultado de la condición del lado derecho, el valor final de la expresión booleana será falso.
Pero esto nunca sucedería en el código de producción.
Este es un error bastante fácil de cometer y las herramientas de análisis estático no siempre lo detectan.
Utilicé el siguiente Google Dork para ver si podía encontrar algún ejemplo público de este patrón:
tipo de archivo: java si es «! =nulo &»
Esta búsqueda devolvió un código de Android en el RootWindowContainer
isDocument = intención! = nulo & intent.isDocument ()
Este es el tipo de código que puede pasar una revisión de código, ya que a menudo utilizamos operadores bit a bit en las sentencias de asignación para enmascarar los valores. Pero en este caso, el resultado es el mismo que en el ejemplo anterior de la sentencia if. Si la intención es alguna vez nula, se lanzará una NullPointerException.
Muy a menudo nos salimos con la nuestra con esta construcción porque a menudo codificamos a la defensiva y escribimos código redundante. ¡El cheque para! = null puede resultar redundante en la mayoría de los casos de uso.
Se trata de un error cometido por los programadores en el código de producción.
No sé qué tan actuales son los resultados de la búsqueda, pero cuando la ejecuté, aparecieron resultados con código de: Google, Amazon, Apache... y yo.
Una reciente solicitud de extracción en uno de mis proyectos de código abierto fue solucionar exactamente este error.
si (escriba! =nulo y escribe.trim () .length () >0) {
Aceptar MediaTypeDefinitionsList.add (type.trim ());
}
Cómo encontrar esto
Cuando comprobé mi código de muestra en algunos analizadores estáticos, ninguno de ellos detectó este código oculto de autodestrucción.
Como equipo de Secure Code Warrior, hemos creado y revisado una receta de Sensei sencilla que podría responder a esta pregunta.
Como los operadores Bitwise son perfectamente válidos y se utilizan con frecuencia en las asignaciones, nos centramos en el caso de uso de las sentencias if y en el uso de Bitwise & para encontrar el código problemático.
buscar:
expresión:
Cualquiera de:
- en:
condición: {}
valor:
Sensible a mayúsculas y minúsculas: falso
coincidencias: «.* & . *»
Esto usa una expresión regular para que coincida con "&» cuando se usa como expresión de condición, por ejemplo, en una sentencia if.
Para solucionarlo, volvimos a confiar en expresiones regulares. Esta vez, utilizamos la función sed del QuickFix para reemplazar globalmente el & de la expresión por &&.
Correcciones disponibles:
- nombre: «Reemplazar el operador AND bit a bit por el operador AND lógico»
acciones:
- reescribir:
a: «{{#sed}} s/&/&&/g, {{{.}}} {{/sed}}»
Notas finales
Esto cubre el uso indebido más común de un operador bit a bit, es decir, cuando realmente se pretendía utilizar un operador booleano.
Hay otras situaciones en las que esto podría surgir, por ejemplo, en el ejemplo de una tarea, pero al escribir recetas debemos intentar evitar la identificación de falsos positivos; de lo contrario, las recetas se ignorarán o se desactivarán. Creamos recetas para que coincidan con las ocurrencias más comunes. A medida que Sensei , es muy posible que añadamos especificidad adicional a la función de búsqueda para cubrir más condiciones coincidentes.
En su forma actual, esta receta identificaría muchos de los casos de uso actuales y, lo más importante, el que se informó en mi proyecto.
NOTA: Unos pocos guerreros del código contribuyeron a este ejemplo y revisión de recetas: Charlie Eriksen, Matthieu Calie, Robin Claerhaut, Brysen Ackx, Nathan Desmet y Downey Robersscheuten. Gracias por tu ayuda.
---
Puede instalar Sensei IntelliJ mediante «Preferencias\ Plugins» (Mac) o «Configuración\ Plugins» (Windows) y, a continuación, buscar «código seguro de sensei
Tenemos muchos códigos fuente y recetas para estas entradas de blog (incluida esta) en el repositorio `sensei` de la cuenta de GitHub de Secure Code Warrior.
https://github.com/securecodewarrior/sensei-blog-examples
Los errores de Java: operadores bitwise frente a operadores booleanos
«Java Gotcha»: un patrón de error común que es fácil de implementar accidentalmente.
Un truco de Java bastante simple en el que caer accidentalmente es: usar un operador bit a bit en lugar de un operador de comparación booleano.
Por ejemplo, un simple error de escritura puede resultar en escribir «&» cuando realmente querías escribir «&&».
Una heurística común que aprendemos al revisar el código es:
«&» o «|» cuando se usan en una declaración condicional probablemente no sean intencionales.
En esta entrada del blog, exploraremos la heurística e identificaremos formas en las que podemos identificar y solucionar este problema de codificación.
¿Cuál es el problema? Las operaciones bit a bit funcionan bien con los valores booleanos.
El uso de operadores bit a bit con booleanos es perfectamente válido, por lo que Java no notificará ningún error de sintaxis.
Si construyo una prueba JUnit para explorar una tabla de verdad tanto para Bitwise OR (|) como para Bitwise AND (&), veremos que las salidas del operador Bitwise coinciden con la tabla de verdad. En vista de esto, podríamos pensar que el uso de operadores Bitwise no es un problema.
Y Tabla de la verdad

@Test
void BitwiseOperatorsAndTruthTable () {
Assertions.assertEquals (verdadero, verdadero y verdadero);
Assertions.assertEquals (falso, verdadero y falso);
Assertions.assertEquals (falso, falso y verdadero);
Assertions.assertEquals (falso, falso y falso);
}
La prueba pasa, esto es Java perfectamente válido.
La tabla de la verdad

@Test
anular BitwiseOperatorSorTruthTable () {
Assertions.assertEquals (verdadero, verdadero | verdadero);
Assertions.assertEquals (verdadero, verdadero | falso);
Assertions.assertEquals (verdadero, falso | verdadero);
Assertions.assertEquals (falso, falso | falso);
}
Esta prueba también pasa, ¿por qué preferimos «&&» y «||»?
Las imágenes de la tabla de verdad se crearon utilizando la herramienta de tabla de verdad de web.standfor.edu.
Problema: Funcionamiento en cortocircuito
El verdadero problema es la diferencia de comportamiento entre los operadores bitwise (&, |) y booleanos (&&, ||).
Un operador booleano es un operador de cortocircuito y solo evalúa lo necesario.
por ejemplo
si (args! = nulo & args.length () > 23) {
System.out.println (argumentos);
}
En el código anterior, se evaluarán ambas condiciones booleanas, porque se ha utilizado el operador Bitwise:
- argumentos! = nulo
- args.length () > 23
Esto deja mi código abierto a una NullPointerException si args es nulo porque siempre realizaremos la verificación de args.length, incluso cuando args sea nulo porque se deben evaluar ambas condiciones booleanas.
Evaluación de cortocircuitos de operadores booleanos
Cuando se usa un &&, p. ej.
si (args! = nulo && args.length () > 23) {
System.out.println (argumentos);
}
¡En cuanto sepamos que es un argumento! = null se evalúa como falso, la evaluación de la expresión de condición se detiene.
No necesitamos evaluar el lado derecho.
Sea cual sea el resultado de la condición del lado derecho, el valor final de la expresión booleana será falso.
Pero esto nunca sucedería en el código de producción.
Este es un error bastante fácil de cometer y las herramientas de análisis estático no siempre lo detectan.
Utilicé el siguiente Google Dork para ver si podía encontrar algún ejemplo público de este patrón:
tipo de archivo: java si es «! =nulo &»
Esta búsqueda devolvió un código de Android en el RootWindowContainer
isDocument = intención! = nulo & intent.isDocument ()
Este es el tipo de código que puede pasar una revisión de código, ya que a menudo utilizamos operadores bit a bit en las sentencias de asignación para enmascarar los valores. Pero en este caso, el resultado es el mismo que en el ejemplo anterior de la sentencia if. Si la intención es alguna vez nula, se lanzará una NullPointerException.
Muy a menudo nos salimos con la nuestra con esta construcción porque a menudo codificamos a la defensiva y escribimos código redundante. ¡El cheque para! = null puede resultar redundante en la mayoría de los casos de uso.
Se trata de un error cometido por los programadores en el código de producción.
No sé qué tan actuales son los resultados de la búsqueda, pero cuando la ejecuté, aparecieron resultados con código de: Google, Amazon, Apache... y yo.
Una reciente solicitud de extracción en uno de mis proyectos de código abierto fue solucionar exactamente este error.
si (escriba! =nulo y escribe.trim () .length () >0) {
Aceptar MediaTypeDefinitionsList.add (type.trim ());
}
Cómo encontrar esto
Cuando comprobé mi código de muestra en algunos analizadores estáticos, ninguno de ellos detectó este código oculto de autodestrucción.
Como equipo de Secure Code Warrior, hemos creado y revisado una receta de Sensei sencilla que podría responder a esta pregunta.
Como los operadores Bitwise son perfectamente válidos y se utilizan con frecuencia en las asignaciones, nos centramos en el caso de uso de las sentencias if y en el uso de Bitwise & para encontrar el código problemático.
buscar:
expresión:
Cualquiera de:
- en:
condición: {}
valor:
Sensible a mayúsculas y minúsculas: falso
coincidencias: «.* & . *»
Esto usa una expresión regular para que coincida con "&» cuando se usa como expresión de condición, por ejemplo, en una sentencia if.
Para solucionarlo, volvimos a confiar en expresiones regulares. Esta vez, utilizamos la función sed del QuickFix para reemplazar globalmente el & de la expresión por &&.
Correcciones disponibles:
- nombre: «Reemplazar el operador AND bit a bit por el operador AND lógico»
acciones:
- reescribir:
a: «{{#sed}} s/&/&&/g, {{{.}}} {{/sed}}»
Notas finales
Esto cubre el uso indebido más común de un operador bit a bit, es decir, cuando realmente se pretendía utilizar un operador booleano.
Hay otras situaciones en las que esto podría surgir, por ejemplo, en el ejemplo de una tarea, pero al escribir recetas debemos intentar evitar la identificación de falsos positivos; de lo contrario, las recetas se ignorarán o se desactivarán. Creamos recetas para que coincidan con las ocurrencias más comunes. A medida que Sensei , es muy posible que añadamos especificidad adicional a la función de búsqueda para cubrir más condiciones coincidentes.
En su forma actual, esta receta identificaría muchos de los casos de uso actuales y, lo más importante, el que se informó en mi proyecto.
NOTA: Unos pocos guerreros del código contribuyeron a este ejemplo y revisión de recetas: Charlie Eriksen, Matthieu Calie, Robin Claerhaut, Brysen Ackx, Nathan Desmet y Downey Robersscheuten. Gracias por tu ayuda.
---
Puede instalar Sensei IntelliJ mediante «Preferencias\ Plugins» (Mac) o «Configuración\ Plugins» (Windows) y, a continuación, buscar «código seguro de sensei
Tenemos muchos códigos fuente y recetas para estas entradas de blog (incluida esta) en el repositorio `sensei` de la cuenta de GitHub de Secure Code Warrior.
https://github.com/securecodewarrior/sensei-blog-examples

Haga clic en el enlace de abajo y descargue el PDF de este recurso.
Secure Code Warrior aquí para que su organización le ayude a proteger el código durante todo el ciclo de vida del desarrollo de software y a crear una cultura en la que la ciberseguridad sea una prioridad. Ya sea administrador de AppSec, desarrollador, CISO o cualquier persona relacionada con la seguridad, podemos ayudar a su organización a reducir los riesgos asociados con el código inseguro.
Ver informeReserve una demostraciónAlan Richardson cuenta con más de veinte años de experiencia profesional en TI, trabajando como desarrollador y en todos los niveles de la jerarquía de pruebas, desde probador hasta jefe de pruebas. Jefe de Relaciones con los Desarrolladores en Secure Code Warrior, trabaja directamente con los equipos, para mejorar el desarrollo de un código seguro de calidad. Alan es autor de cuatro libros, entre ellos "Dear Evil Tester" y "Java For Testers". Alan también ha creado una formación en línea courses para ayudar a la gente a aprender las pruebas técnicas de la web y Selenium WebDriver con Java. Alan publica sus escritos y vídeos de formación en SeleniumSimplified.com, EvilTester.com, JavaForTesters.com, y CompendiumDev.co.uk.
Los errores de Java: operadores bitwise frente a operadores booleanos
«Java Gotcha»: un patrón de error común que es fácil de implementar accidentalmente.
Un truco de Java bastante simple en el que caer accidentalmente es: usar un operador bit a bit en lugar de un operador de comparación booleano.
Por ejemplo, un simple error de escritura puede resultar en escribir «&» cuando realmente querías escribir «&&».
Una heurística común que aprendemos al revisar el código es:
«&» o «|» cuando se usan en una declaración condicional probablemente no sean intencionales.
En esta entrada del blog, exploraremos la heurística e identificaremos formas en las que podemos identificar y solucionar este problema de codificación.
¿Cuál es el problema? Las operaciones bit a bit funcionan bien con los valores booleanos.
El uso de operadores bit a bit con booleanos es perfectamente válido, por lo que Java no notificará ningún error de sintaxis.
Si construyo una prueba JUnit para explorar una tabla de verdad tanto para Bitwise OR (|) como para Bitwise AND (&), veremos que las salidas del operador Bitwise coinciden con la tabla de verdad. En vista de esto, podríamos pensar que el uso de operadores Bitwise no es un problema.
Y Tabla de la verdad

@Test
void BitwiseOperatorsAndTruthTable () {
Assertions.assertEquals (verdadero, verdadero y verdadero);
Assertions.assertEquals (falso, verdadero y falso);
Assertions.assertEquals (falso, falso y verdadero);
Assertions.assertEquals (falso, falso y falso);
}
La prueba pasa, esto es Java perfectamente válido.
La tabla de la verdad

@Test
anular BitwiseOperatorSorTruthTable () {
Assertions.assertEquals (verdadero, verdadero | verdadero);
Assertions.assertEquals (verdadero, verdadero | falso);
Assertions.assertEquals (verdadero, falso | verdadero);
Assertions.assertEquals (falso, falso | falso);
}
Esta prueba también pasa, ¿por qué preferimos «&&» y «||»?
Las imágenes de la tabla de verdad se crearon utilizando la herramienta de tabla de verdad de web.standfor.edu.
Problema: Funcionamiento en cortocircuito
El verdadero problema es la diferencia de comportamiento entre los operadores bitwise (&, |) y booleanos (&&, ||).
Un operador booleano es un operador de cortocircuito y solo evalúa lo necesario.
por ejemplo
si (args! = nulo & args.length () > 23) {
System.out.println (argumentos);
}
En el código anterior, se evaluarán ambas condiciones booleanas, porque se ha utilizado el operador Bitwise:
- argumentos! = nulo
- args.length () > 23
Esto deja mi código abierto a una NullPointerException si args es nulo porque siempre realizaremos la verificación de args.length, incluso cuando args sea nulo porque se deben evaluar ambas condiciones booleanas.
Evaluación de cortocircuitos de operadores booleanos
Cuando se usa un &&, p. ej.
si (args! = nulo && args.length () > 23) {
System.out.println (argumentos);
}
¡En cuanto sepamos que es un argumento! = null se evalúa como falso, la evaluación de la expresión de condición se detiene.
No necesitamos evaluar el lado derecho.
Sea cual sea el resultado de la condición del lado derecho, el valor final de la expresión booleana será falso.
Pero esto nunca sucedería en el código de producción.
Este es un error bastante fácil de cometer y las herramientas de análisis estático no siempre lo detectan.
Utilicé el siguiente Google Dork para ver si podía encontrar algún ejemplo público de este patrón:
tipo de archivo: java si es «! =nulo &»
Esta búsqueda devolvió un código de Android en el RootWindowContainer
isDocument = intención! = nulo & intent.isDocument ()
Este es el tipo de código que puede pasar una revisión de código, ya que a menudo utilizamos operadores bit a bit en las sentencias de asignación para enmascarar los valores. Pero en este caso, el resultado es el mismo que en el ejemplo anterior de la sentencia if. Si la intención es alguna vez nula, se lanzará una NullPointerException.
Muy a menudo nos salimos con la nuestra con esta construcción porque a menudo codificamos a la defensiva y escribimos código redundante. ¡El cheque para! = null puede resultar redundante en la mayoría de los casos de uso.
Se trata de un error cometido por los programadores en el código de producción.
No sé qué tan actuales son los resultados de la búsqueda, pero cuando la ejecuté, aparecieron resultados con código de: Google, Amazon, Apache... y yo.
Una reciente solicitud de extracción en uno de mis proyectos de código abierto fue solucionar exactamente este error.
si (escriba! =nulo y escribe.trim () .length () >0) {
Aceptar MediaTypeDefinitionsList.add (type.trim ());
}
Cómo encontrar esto
Cuando comprobé mi código de muestra en algunos analizadores estáticos, ninguno de ellos detectó este código oculto de autodestrucción.
Como equipo de Secure Code Warrior, hemos creado y revisado una receta de Sensei sencilla que podría responder a esta pregunta.
Como los operadores Bitwise son perfectamente válidos y se utilizan con frecuencia en las asignaciones, nos centramos en el caso de uso de las sentencias if y en el uso de Bitwise & para encontrar el código problemático.
buscar:
expresión:
Cualquiera de:
- en:
condición: {}
valor:
Sensible a mayúsculas y minúsculas: falso
coincidencias: «.* & . *»
Esto usa una expresión regular para que coincida con "&» cuando se usa como expresión de condición, por ejemplo, en una sentencia if.
Para solucionarlo, volvimos a confiar en expresiones regulares. Esta vez, utilizamos la función sed del QuickFix para reemplazar globalmente el & de la expresión por &&.
Correcciones disponibles:
- nombre: «Reemplazar el operador AND bit a bit por el operador AND lógico»
acciones:
- reescribir:
a: «{{#sed}} s/&/&&/g, {{{.}}} {{/sed}}»
Notas finales
Esto cubre el uso indebido más común de un operador bit a bit, es decir, cuando realmente se pretendía utilizar un operador booleano.
Hay otras situaciones en las que esto podría surgir, por ejemplo, en el ejemplo de una tarea, pero al escribir recetas debemos intentar evitar la identificación de falsos positivos; de lo contrario, las recetas se ignorarán o se desactivarán. Creamos recetas para que coincidan con las ocurrencias más comunes. A medida que Sensei , es muy posible que añadamos especificidad adicional a la función de búsqueda para cubrir más condiciones coincidentes.
En su forma actual, esta receta identificaría muchos de los casos de uso actuales y, lo más importante, el que se informó en mi proyecto.
NOTA: Unos pocos guerreros del código contribuyeron a este ejemplo y revisión de recetas: Charlie Eriksen, Matthieu Calie, Robin Claerhaut, Brysen Ackx, Nathan Desmet y Downey Robersscheuten. Gracias por tu ayuda.
---
Puede instalar Sensei IntelliJ mediante «Preferencias\ Plugins» (Mac) o «Configuración\ Plugins» (Windows) y, a continuación, buscar «código seguro de sensei
Tenemos muchos códigos fuente y recetas para estas entradas de blog (incluida esta) en el repositorio `sensei` de la cuenta de GitHub de Secure Code Warrior.
https://github.com/securecodewarrior/sensei-blog-examples
Tabla de contenido
Alan Richardson cuenta con más de veinte años de experiencia profesional en TI, trabajando como desarrollador y en todos los niveles de la jerarquía de pruebas, desde probador hasta jefe de pruebas. Jefe de Relaciones con los Desarrolladores en Secure Code Warrior, trabaja directamente con los equipos, para mejorar el desarrollo de un código seguro de calidad. Alan es autor de cuatro libros, entre ellos "Dear Evil Tester" y "Java For Testers". Alan también ha creado una formación en línea courses para ayudar a la gente a aprender las pruebas técnicas de la web y Selenium WebDriver con Java. Alan publica sus escritos y vídeos de formación en SeleniumSimplified.com, EvilTester.com, JavaForTesters.com, y CompendiumDev.co.uk.

Secure Code Warrior aquí para que su organización le ayude a proteger el código durante todo el ciclo de vida del desarrollo de software y a crear una cultura en la que la ciberseguridad sea una prioridad. Ya sea administrador de AppSec, desarrollador, CISO o cualquier persona relacionada con la seguridad, podemos ayudar a su organización a reducir los riesgos asociados con el código inseguro.
Reserve una demostraciónDescargarRecursos para empezar
Temas y contenido de formación sobre código seguro
Nuestro contenido líder en la industria siempre está evolucionando para adaptarse al cambiante panorama del desarrollo de software teniendo en cuenta su función. Se ofrecen temas que abarcan desde la IA hasta la inyección de XQuery para distintos puestos, desde arquitectos e ingenieros hasta directores de productos y control de calidad. Obtenga un adelanto de lo que ofrece nuestro catálogo de contenido por tema y función.
La Cámara de Comercio establece el estándar para la seguridad impulsada por desarrolladores a gran escala
Kamer van Koophandel comparte cómo ha integrado la codificación segura en el desarrollo diario mediante certificaciones basadas en roles, evaluaciones comparativas de Trust Score y una cultura de responsabilidad compartida en materia de seguridad.
Modelado de amenazas con IA: convertir a cada desarrollador en un modelador de amenazas
Saldrá mejor equipado para ayudar a los desarrolladores a combinar ideas y técnicas de modelado de amenazas con las herramientas de IA que ya utilizan para reforzar la seguridad, mejorar la colaboración y crear software más resistente desde el principio.
Recursos para empezar
Cybermon está de vuelta: las misiones de IA de Beat the Boss ya están disponibles bajo demanda.
Cybermon 2025 Beat the Boss ya está disponible durante todo el año en SCW. Implemente desafíos de seguridad avanzados de IA y LLM para fortalecer el desarrollo seguro de la IA a gran escala.
Explicación de la Ley de Ciberresiliencia: qué significa para el desarrollo de software seguro por diseño
Descubra qué exige la Ley de Ciberresiliencia (CRA) de la UE, a quién se aplica y cómo los equipos de ingeniería pueden prepararse con prácticas de diseño seguras, prevención de vulnerabilidades y desarrollo de capacidades para desarrolladores.
Facilitador 1: Criterios de éxito definidos y medibles
El habilitador 1 da inicio a nuestra serie Enablers of Success, de 10 partes, mostrando cómo vincular la codificación segura con los resultados empresariales, como la reducción del riesgo y la velocidad para lograr la madurez del programa a largo plazo.




%20(1).avif)
.avif)
