5 개 항목 찾음
취약점
Abstract
바이트 배열을 String으로 변환하면 데이터가 손실될 수 있습니다.
Explanation
바이트 배열의 데이터를 String으로 변환할 때 해당되는 문자 집합 외부의 데이터가 어떻게 변환되는지는 지정되지 않습니다. 따라서 데이터가 손실되거나, 적절한 보안 대책을 따르기 위해 이진 데이터가 필요할 때 보안 수준이 낮아질 수 있습니다.

예제 1: 다음 코드는 해시를 만들기 위해 데이터를 String으로 변환합니다.


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


파일 크기가 BUFSIZE보다 작다고 가정할 때 myFile의 정보를 기본 문자 집합과 같이 인코딩하면 이 코드는 문제 없이 작동합니다. 그러나 이 파일이 다른 인코딩을 사용하거나 이진 파일인 경우에는 정보가 손실됩니다. 그러면 결과로 생성되는 SHA 해시의 안정성이 떨어질 수 있으며, 충돌이 발생하기가 훨씬 쉬워집니다. 특히 기본 문자 집합 외부의 모든 데이터가 물음표 등의 같은 값으로 표현되는 경우에는 더욱 그러합니다.
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
NaN 비교에서 항상 오류가 발생합니다.
Explanation
NaN과의 비교는 항상 false로 평가됩니다. 단, NaN은 순서가 지정되지 않으므로 != 연산자를 사용하는 경우에는 항상 true로 평가됩니다.

예제 1: 다음 코드는 변수가 NaN이 아님을 확인합니다.


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


이 코드는 resultNaN이 아님을 확인하려고 합니다. 그러나 NaN에서 == 연산자를 사용하는 경우 결과 값은 항상 false이므로 이 검사에서는 예외가 발생하지 않습니다.
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
해당 클래스 이름을 기반으로 개체 유형을 결정하면 예상치 못한 동작이 나타나거나 공격자가 악성 클래스를 삽입할 수 있습니다.
Explanation
공격자는 프로그램이 악성 코드를 실행하도록 만들기 위해 의도적으로 클래스 이름을 복제할 수 있습니다. 이러한 이유로 클래스 이름은 좋은 형식 식별자가 아니며 지정된 개체에 대한 신뢰를 부여하는 기준으로 사용해서는 안 됩니다.

예제 1: 다음 코드에서는 inputReader 개체의 입력을 신뢰할지 여부를 해당 클래스 이름을 기준으로 결정합니다. 공격자가 악성 명령을 실행하는 inputReader의 구현을 제공할 수 있는 경우, 이 코드는 개체의 양성 버전과 악성 버전을 구별할 수 없습니다.


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
해당 클래스 이름을 기반으로 개체 유형을 결정하면 예상치 못한 동작이 나타나거나 공격자가 악성 클래스를 삽입할 수 있습니다.
Explanation
공격자는 프로그램이 악성 코드를 실행하도록 만들기 위해 의도적으로 클래스 이름을 복제할 수 있습니다. 이러한 이유로 클래스 이름은 좋은 형식 식별자가 아니며 지정된 개체에 대한 신뢰를 부여하는 기준으로 사용해서는 안 됩니다.

예제 1: 다음 코드에서는 inputReader 개체의 입력을 신뢰할지 여부를 해당 클래스 이름을 기준으로 결정합니다. 공격자가 악성 명령을 실행하는 inputReader의 구현을 제공할 수 있는 경우, 이 코드는 개체의 양성 버전과 악성 버전을 구별할 수 없습니다.


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
개체 클래스 이름을 기준으로 개체의 형식을 결정하면 예기치 못한 동작이 발생하거나 공격자가 악성 클래스를 삽입하도록 허용할 수 있습니다.
Explanation
공격자는 프로그램이 악성 코드를 실행하도록 만들기 위해 의도적으로 클래스 이름을 복제할 수 있습니다. 이러한 이유로 클래스 이름은 좋은 형식 식별자가 아니며 지정된 개체에 대한 신뢰를 부여하는 기준으로 사용해서는 안 됩니다.

예제 1: 다음 코드에서는 inputReader 개체의 입력을 신뢰할지 여부를 해당 클래스 이름을 기준으로 결정합니다. 공격자가 악성 명령을 실행하는 inputReader의 구현을 제공할 수 있는 경우, 이 코드는 개체의 양성 버전과 악성 버전을 구별할 수 없습니다.


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
정적 메서드는 재정의할 수는 없지만, 인스턴스 메서드로 호출하는 경우 숨겨진 것으로 표시될 수 있습니다.
Explanation
정적 메서드는 클래스의 인스턴스가 아닌 클래스 자체에 속하므로 원칙적으로 오버라이드할 수 없습니다. 정적 메서드가 하위 클래스에서 오버라이드된 것처럼 표시되는 경우도 있는데, 이로 인해 혼동을 하여 잘못된 메서드 버전을 호출하게 될 수도 있습니다.

예제 1: 다음 코드는 사용자 인증을 위한 API를 정의합니다.


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


이 코드는 처음 보기에는 아무 문제가 없는 것 같습니다. 그러나 User 또는 RegularUser 클래스가 아닌 user 인스턴스에 대해 getAccessLevel() 메서드를 호출하므로 이 조건에서는 항상 true가 반환됩니다. 그리고 이 if/else 블록 부분으로 진입하기 위해 instanceof를 사용했더라도 제한된 작업이 수행됩니다.
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
Abstract
프로그램은 클래스 로더를 사용하여 Enterprise JavaBeans 규격을 위반합니다.
Explanation
Enterprise JavaBeans 규격에 따르면 모든 bean 공급자는 bean이 이식 가능하고 EJB 컨테이너에서 일관성 있게 동작하도록 하기 위한 프로그래밍 지침을 따라야 합니다[1].

이 경우, 프로그램은 다음 EJB 지침을 위반합니다.

"Enterprise Bean은 클래스 로더 생성, 컨텍스트 클래스 로더 설정, 보안 관리자 설정, 새 보안 관리자 생성, JVM 중단 또는 입력, 출력 및 오류 스트림 변경을 할 수 없습니다."

규격에서 다음과 같이 정당화하는 요구 사항입니다.

"이러한 함수는 Enterprise Bean 컨테이너용으로 예약되어 있습니다. Enterprise Bean이 이러한 함수를 사용하면 보안이 약해지고 컨테이너가 런타임 환경을 올바로 관리하는 기능이 저하됩니다."
References
[1] Jakarta Enterprise Beans 4.0 Eclipse Foundation
[2] Standards Mapping - Common Weakness Enumeration CWE ID 578
desc.structural.java.ejb_bad_practices_use_of_classloader