1. 부적절한 자원 관리의 위험성
CWE-416은 이미 메모리나 시스템 자원(파일 핸들, 소켓 등)을 **해제(Free/Close)**한 후에도 해당 자원을 다시 참조하려고 할 때 발생합니다.
-
보안 위협: 이미 해제된 메모리 영역에 다른 민감한 데이터가 할당될 경우, 공격자는 이전 참조를 통해 그 데이터를 읽거나 실행 흐름을 조작할 수 있습니다.
-
가용성 위협: 자원을 제때 해제하지 않는 경우(자원 누수, Resource Leak) 시스템의 한정된 자원이 바닥나 결국 서비스가 중단되는 서비스 거부(DoS) 상태에 빠집니다.
2. 흔히 발생하는 취약한 패턴
주로 예외 상황이 발생했을 때 자원 해제 로직을 건너뛰면서 문제가 생깁니다.
-
에러 발생 시 Close 누락: 파일을 읽거나 DB 연결을 시도하다 에러가 나면,
close()메서드가 호출되지 않아 연결이 그대로 유지되는 경우. -
조기 반환(Return)에 의한 누수: 함수 중간에 조건에 따라
return할 때, 앞서 오픈한 자원을 닫지 않고 나가는 경우. -
Double Free: 동일한 자원을 두 번 해제하여 메모리 관리 구조를 파괴하는 경우.
3. 실무적 대응: Try-with-resources와 구조적 해제
자바 환경에서는 가비지 컬렉터(GC)가 메모리를 관리하지만, 파일이나 네트워크 소켓 같은 외부 자원은 반드시 수동으로 닫아주어야 합니다.
-
Try-with-resources 활용: Java 7 이상이라면
AutoCloseable을 구현한 객체들을try (...)구문 안에서 선언하여 로직이 끝나면 자동으로 닫히도록 합니다. -
Finally 블록 사용: 고전적인 방식에서는 반드시
finally절에서 자원을 해제하여 에러 발생 여부와 상관없이close()가 실행되게 합니다. -
해제 후 참조 제거: 자원을 해제한 직후에는 해당 변수를
null로 설정하여 다시 참조하는 실수를 방지합니다.
4. CWE-416/404 대응 및 안전한 자원 관리 자바 코드 예시
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
public class ResourceManager {
private static final Logger logger = LoggerFactory.getLogger(ResourceManager.class);
// [CWE-404 조치] Try-with-resources를 사용한 자동 자원 해제
public void readFileSafe(String path) {
// try-with-resources 구문은 블록을 벗어날 때 자동으로 close()를 호출함
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
String line = br.readLine();
logger.debug("First line of file: {}", line);
} catch (IOException e) {
logger.debug("I/O Error during file processing: {}", e.getMessage());
}
// 이 지점에서는 br이 이미 안전하게 닫혀 있음
}
// [CWE-416 조치] 명시적 해제 및 참조 제거
public void processManualResource(CustomResource res) {
try {
res.doWork();
} finally {
if (res != null) {
res.close();
// 해제 후 즉시 null 처리하여 이후의 부적절한 사용(Use-After-Free) 방지
res = null;
logger.debug("Resource manually closed and nullified.");
}
}
}
}
코멘트: 자원 관리는 "빌린 물건은 반드시 제자리에 돌려놓는 것"과 같습니다. 특히 반복적으로 실행되는 로직에서 자원 누수가 발생하면 서버는 서서히 죽어가는 시한폭탄이 됩니다. logger.debug()를 통해 자원 할당과 해제 시점을 추적하되, 최신 Java 문법인 Try-with-resources를 적극 활용하여 실수할 여지 자체를 없애는 것이 가장 영리한 시큐어 코딩입니다.
댓글 달기