SCW图标
英雄背景无分隔线
博客

Los errores de Java: operadores bitwise frente a operadores booleanos

艾伦-理查德森
2021 年 2 月 7 日 发布
最后更新于 2026年3月6日

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

有三栏是a,一栏是b,最后一栏是(a^b)。


@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.


O Tabla de la verdad


三列是a,一列是b,最后一列是(a v b)。


@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 el herramienta de tabla de la 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.

Un 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 bastante 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 evolucione, 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 desde 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-blog-examples` de la cuenta de GitHub de Secure Code Warrior.

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

Más información sobre Sensei


查看资源
查看资源

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 al que hace que nuestro código sea vulnerable y cómo podemos usar Sensei para corregir y detectar el problema.

感兴趣了解更多吗?

Alan Richardson拥有超过20年的专业IT经验,他曾作为一名开发人员,在测试层次的各个层面工作,从测试员到测试主管。在Secure Code Warrior ,他是开发者关系主管,直接与团队合作,以改善高质量安全代码的开发。Alan是四本书的作者,包括 "Dear Evil Tester "和 "Java For Testers"。艾伦还创建了在线培训courses ,帮助人们学习技术网络测试和用Java编写的Selenium WebDriver。Alan在SeleniumSimplified.com、EvilTester.com、JavaForTesters.com和CompendiumDev.co.uk上发布他的写作和培训视频。

了解更多

Secure Code Warrior 您的组织在软件开发全生命周期中保护代码安全,并营造将网络安全置于首位的企业文化。无论您是应用安全管理员、开发人员、首席信息安全官,还是任何与安全相关的工作人员,我们都能助力您的组织降低不安全代码带来的风险。

预约演示
分享到:
领英品牌社交x 标志
作者
艾伦-理查德森
2021年2月7日出版

Alan Richardson拥有超过20年的专业IT经验,他曾作为一名开发人员,在测试层次的各个层面工作,从测试员到测试主管。在Secure Code Warrior ,他是开发者关系主管,直接与团队合作,以改善高质量安全代码的开发。Alan是四本书的作者,包括 "Dear Evil Tester "和 "Java For Testers"。艾伦还创建了在线培训courses ,帮助人们学习技术网络测试和用Java编写的Selenium WebDriver。Alan在SeleniumSimplified.com、EvilTester.com、JavaForTesters.com和CompendiumDev.co.uk上发布他的写作和培训视频。

分享到:
领英品牌社交x 标志

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

有三栏是a,一栏是b,最后一栏是(a^b)。


@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.


O Tabla de la verdad


三列是a,一列是b,最后一列是(a v b)。


@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 el herramienta de tabla de la 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.

Un 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 bastante 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 evolucione, 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 desde 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-blog-examples` de la cuenta de GitHub de Secure Code Warrior.

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

Más información sobre Sensei


查看资源
查看资源

请填写以下表格以下载报告

我们希望获得您的许可,以便向您发送有关我们产品或安全编码相关主题的信息。我们将始终以最高标准谨慎处理您的个人数据,绝不会出于营销目的将其出售给其他公司。

发送
scw 成功图标
SCW 错误图标
要提交表单,请启用「分析」cookie。完成后请随时将其重新禁用。

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

有三栏是a,一栏是b,最后一栏是(a^b)。


@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.


O Tabla de la verdad


三列是a,一列是b,最后一列是(a v b)。


@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 el herramienta de tabla de la 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.

Un 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 bastante 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 evolucione, 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 desde 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-blog-examples` de la cuenta de GitHub de Secure Code Warrior.

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

Más información sobre Sensei


观看网络研讨会
开始
了解更多

点击下方链接,下载此资源的PDF文件。

Secure Code Warrior 您的组织在软件开发全生命周期中保护代码安全,并营造将网络安全置于首位的企业文化。无论您是应用安全管理员、开发人员、首席信息安全官,还是任何与安全相关的工作人员,我们都能助力您的组织降低不安全代码带来的风险。

查看报告预约演示
查看资源
分享到:
领英品牌社交x 标志
感兴趣了解更多吗?

分享到:
领英品牌社交x 标志
作者
艾伦-理查德森
2021年2月7日出版

Alan Richardson拥有超过20年的专业IT经验,他曾作为一名开发人员,在测试层次的各个层面工作,从测试员到测试主管。在Secure Code Warrior ,他是开发者关系主管,直接与团队合作,以改善高质量安全代码的开发。Alan是四本书的作者,包括 "Dear Evil Tester "和 "Java For Testers"。艾伦还创建了在线培训courses ,帮助人们学习技术网络测试和用Java编写的Selenium WebDriver。Alan在SeleniumSimplified.com、EvilTester.com、JavaForTesters.com和CompendiumDev.co.uk上发布他的写作和培训视频。

分享到:
领英品牌社交x 标志

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

有三栏是a,一栏是b,最后一栏是(a^b)。


@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.


O Tabla de la verdad


三列是a,一列是b,最后一列是(a v b)。


@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 el herramienta de tabla de la 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.

Un 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 bastante 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 evolucione, 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 desde 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-blog-examples` de la cuenta de GitHub de Secure Code Warrior.

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

Más información sobre Sensei


目录

下载PDF
查看资源
感兴趣了解更多吗?

Alan Richardson拥有超过20年的专业IT经验,他曾作为一名开发人员,在测试层次的各个层面工作,从测试员到测试主管。在Secure Code Warrior ,他是开发者关系主管,直接与团队合作,以改善高质量安全代码的开发。Alan是四本书的作者,包括 "Dear Evil Tester "和 "Java For Testers"。艾伦还创建了在线培训courses ,帮助人们学习技术网络测试和用Java编写的Selenium WebDriver。Alan在SeleniumSimplified.com、EvilTester.com、JavaForTesters.com和CompendiumDev.co.uk上发布他的写作和培训视频。

了解更多

Secure Code Warrior 您的组织在软件开发全生命周期中保护代码安全,并营造将网络安全置于首位的企业文化。无论您是应用安全管理员、开发人员、首席信息安全官,还是任何与安全相关的工作人员,我们都能助力您的组织降低不安全代码带来的风险。

预约演示下载
分享到:
领英品牌社交x 标志
资源中心

入门资源

更多出版物
资源中心

入门资源

更多出版物