Kingdom: Code Quality

Poor code quality leads to unpredictable behavior. From a user's perspective that often manifests itself as poor usability. For an attacker it provides an opportunity to stress the system in unexpected ways.

4 items found
Weaknesses
Abstract
Converting a byte array into a String may lead to data loss.
Explanation
When data from a byte array is converted into a String, it is unspecified what will happen to any data that is outside of the applicable character set. This can lead to data being lost, or a decrease in the level of security when binary data is needed to ensure proper security measures are followed.

Example 1: The following code converts data into a String in order to create a 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
...


Assuming the size of the file is less than BUFSIZE, this works fine as long as the information in myFile is encoded the same as the default character set, however if it's using a different encoding, or is a binary file, it will lose information. This in turn will cause the resulting SHA hash to be less reliable, and could mean it's far easier to cause collisions, especially if any data outside of the default character set is represented by the same value, such as a question mark.
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
Making a comparison with NaN is always an error.
Explanation
When a comparison is made to NaN it is always evaluated as false, except for the != operator, which always evaluates to true since NaN is unordered.

Example 1: The following tries to make sure a variable is not NaN.


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


This attempts to verify that result is not NaN, however using the operator == with NaN always results in a value of false, so this check will never throw the exception.
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
Determining an object's type based on its class name can lead to unexpected behavior or allow an attacker to inject a malicious class.
Explanation
Attackers can deliberately duplicate class names in order to cause a program to execute malicious code. For this reason, class names are not good type identifiers and should not be used as the basis for granting trust to a given object.

Example 1: The following code determines whether to trust input from an inputReader object based on its class name. If an attacker can supply an implementation of inputReader that executes malicious commands, this code cannot differentiate the benign and malicious versions of the object.


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
Determining an object's type based on its class name can lead to unexpected behavior or allow an attacker to inject a malicious class.
Explanation
Attackers can deliberately duplicate class names in order to cause a program to execute malicious code. For this reason, class names are not good type identifiers and should not be used as the basis for granting trust to a given object.

Example 1: The following code determines whether to trust input from an inputReader object based on its class name. If an attacker can supply an implementation of inputReader that executes malicious commands, this code cannot differentiate the benign and malicious versions of the object.


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
Determining an object's type based on its class name can lead to unexpected behavior or allow an attacker to inject a malicious class.
Explanation
Attackers can deliberately duplicate class names in order to cause a program to execute malicious code. For this reason, class names are not good type identifiers and should not be used as the basis for granting trust to a given object.

Example 1: The following code determines whether to trust input from an inputReader object based on its class name. If an attacker can supply an implementation of inputReader that executes malicious commands, this code cannot differentiate the benign and malicious versions of the object.


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
Static methods cannot be overridden, but may appear to be hidden when called as an instance method.
Explanation
Static methods cannot be overridden by definition, since they belong to the class rather than an instance of the class. Although there are cases where it looks like a static method has been overridden in a subclass, which may cause confusion and can lead to the incorrect version of the method being called.

Example 1: The following tries to define an API for authenticating users.


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();
}
}
}
}


At first glance, this code looks fine. However, since we are calling the method getAccessLevel() against the instance user and not against the classes User or RegularUser, it will mean that this condition will always return true, and the restricted operation will be performed even though instanceof was used in order to get into this part of the if/else block.
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