Reino: Code Quality

Códigos de baixa qualidade levam a comportamentos imprevisíveis. Da perspectiva do usuário, isso normalmente se manifesta como usabilidade ruim. Para um invasor, trata-se de uma oportunidade para atacar o sistema de formas imprevistas.

4 itens encontrados
Vulnerabilidades
Abstract
A conversão de um array de bytes em uma String pode levar à perda de dados.
Explanation
Quando os dados de um array de bytes são convertidos em uma String, não fica claro o que acontecerá com os dados que estiverem fora do conjunto de caracteres aplicável. Isso pode provocar perda de dados ou uma diminuição no nível de segurança quando dados binários são necessários para assegurar que medidas de segurança adequadas sejam seguidas.

Exemplo 1: O código a seguir converte dados em uma String para criar um hash.


...
FileInputStream fis = new FileInputStream(myFile);
byte[] byteArr = byte[BUFSIZE];
...
int count = fis.read(byteArr);
...
String fileString = new String(byteArr);
String fileSHA256Hex = DigestUtils.sha256Hex(fileString);
// use fileSHA256Hex to validate file
...


Isso funciona muito bem supondo que o tamanho do arquivo seja menor que BUFSIZE, desde que as informações em myFile sejam codificadas da mesma maneira que o conjunto de caracteres padrão. Porém, se uma codificação diferente estiver em uso, ou se o arquivo for binário, haverá perda de informações. Isso por sua vez fará com que o hash SHA resultante seja menos confiável e pode implicar que colisões podem ser provocadas com muito mais facilidade, especialmente se os dados fora do conjunto de caracteres padrão forem representados pelo mesmo valor, como um ponto de interrogação.
References
[1] STR03-J. Do not encode noncharacter data as a string CERT
[2] When 'EFBFBD' and Friends Come Knocking: Observations of Byte Array to String Conversions GDS Security
[3] Standards Mapping - Common Weakness Enumeration CWE ID 486
desc.semantic.java.code_correctness_byte_array_to_string_conversion
Abstract
Fazer uma comparação com NaN é sempre um erro.
Explanation
Quando é feita uma comparação com NaN, ela é sempre avaliada como false, exceto para o operador !=, que sempre é avaliado como true, já que NaN não está ordenado.

Exemplo 1: O exemplo a seguir tenta garantir que uma variável não é NaN.


...
if (result == Double.NaN){
//something went wrong
throw new RuntimeException("Something went wrong, NaN found");
}
...


Isso tenta verificar se result não é NaN, mas o uso do operador == com NaN sempre resulta em um valor de false, e, portanto, essa verificação nunca lançará a exceção.
References
[1] NUM07-J. Do not attempt comparisons with NaN CERT
[2] Java Language Specification Chapter 4. Types, Values, and Variables Oracle
[3] INJECT-9: Prevent injection of exceptional floating point values Oracle
[4] Standards Mapping - Common Weakness Enumeration CWE ID 486
desc.structural.java.code_correctness_comparison_with_nan
Abstract
Determinar o tipo de um objeto com base em seu nome de classe pode provocar comportamentos inesperados ou permitir que um invasor injete uma classe mal-intencionada.
Explanation
Os invasores podem duplicar deliberadamente os nomes das classes para fazer com que um programa execute um código mal-intencionado. Por esse motivo, os nomes das classes não são bons identificadores de tipo e não devem ser usados como base para conceder confiança a determinado objeto.

Exemplo 1: O código a seguir determina se a entrada de um objeto inputReader é confiável com base em seu nome de classe. Se um invasor puder fornecer uma implementação de inputReader que executa comandos mal-intencionados, esse código não poderá diferenciar as versões bem-intencionadas das mal-intencionadas do objeto.


if (inputReader.GetType().FullName == "CompanyX.Transaction.Monetary")
{
processTransaction(inputReader);
}
References
[1] Standards Mapping - Common Weakness Enumeration CWE ID 486
desc.dataflow.dotnet.code_correctness_erroneous_class_compare
Abstract
Determinar o tipo de um objeto com base em seu nome de classe pode provocar comportamentos inesperados ou permitir que um invasor injete uma classe mal-intencionada.
Explanation
Os invasores podem duplicar deliberadamente os nomes das classes para fazer com que um programa execute um código mal-intencionado. Por esse motivo, os nomes das classes não são bons identificadores de tipo e não devem ser usados como base para conceder confiança a determinado objeto.

Exemplo 1: O código a seguir determina se a entrada de um objeto inputReader é confiável com base em seu nome de classe. Se um invasor puder fornecer uma implementação de inputReader que executa comandos mal-intencionados, esse código não poderá diferenciar as versões bem-intencionadas das mal-intencionadas do objeto.


if (inputReader.getClass().getName().equals("com.example.TrustedClass")) {
input = inputReader.getInput();
...
}
References
[1] OBJ09-J. Compare classes and not class names CERT
[2] Standards Mapping - Common Weakness Enumeration CWE ID 486
desc.dataflow.java.code_correctness_erroneous_class_compare
Abstract
Determinar o tipo de um objeto com base em seu nome de classe pode causar um comportamento inesperado ou permitir que um invasor injete uma classe mal-intencionada.
Explanation
Os invasores podem duplicar deliberadamente os nomes das classes para fazer com que um programa execute um código mal-intencionado. Por esse motivo, os nomes das classes não são bons identificadores de tipo e não devem ser usados como base para conceder confiança a determinado objeto.

Exemplo 1: O código a seguir determina se a entrada de um objeto inputReader é confiável com base em seu nome de classe. Se um invasor puder fornecer uma implementação de inputReader que executa comandos mal-intencionados, esse código não poderá diferenciar as versões bem-intencionadas das mal-intencionadas do objeto.


if (inputReader::class.qualifiedName == "com.example.TrustedClass") {
input = inputReader.getInput()
...
}
References
[1] OBJ09-J. Compare classes and not class names CERT
[2] Standards Mapping - Common Weakness Enumeration CWE ID 486
desc.dataflow.kotlin.code_correctness_erroneous_class_compare
Abstract
Os métodos estáticos não podem ser substituídos, mas podem parecer ocultos quando chamados como um método de instância.
Explanation
Métodos estáticos não podem ser substituídos por definição, uma vez que pertencem à classe e não a uma instância da classe. Mesmo assim, existem casos em que parece que um método estático foi substituído em uma subclasse, o que pode causar confusão e fazer com que uma versão incorreta do método seja chamada.

Exemplo 1: O exemplo a seguir tenta definir uma API para a autenticação de usuários.


class AccessLevel{
public static final int ROOT = 0;
//...
public static final int NONE = 9;
}
//...
class User {
private static int access;
public User(){
access = AccessLevel.ROOT;
}
public static int getAccessLevel(){
return access;
}
//...
}
class RegularUser extends User {
private static int access;
public RegularUser(){
access = AccessLevel.NONE;
}
public static int getAccessLevel(){
return access;
}
public static void escalatePrivilege(){
access = AccessLevel.ROOT;
}
//...
}
//...
class SecureArea {
//...
public static void doRestrictedOperation(User user){
if (user instanceof RegularUser){
if (user.getAccessLevel() == AccessLevel.ROOT){
System.out.println("doing a privileged operation");
}else{
throw new RuntimeException();
}
}
}
}


À primeira vista, esse código parece bom. No entanto, como estamos chamando o método getAccessLevel() em relação à instância user, e não contra as classes User ou RegularUser, isso significa que essa condição sempre retornará true e a operação restrita será realizada mesmo que instanceof tenha sido usado para entrar nessa parte do bloco if/else.
References
[1] MET07-J. Never declare a class method that hides a method declared in a superclass or superinterface CERT
[2] Java Language Specification Chapter 8. Classes Oracle
[3] Standards Mapping - Common Weakness Enumeration CWE ID 486
desc.structural.java.code_correctness_hidden_method