메뉴 건너뛰기

app

존재하지 않는 대상을 향한 참조: CWE-476 Null Pointer 역참조

suritam92026.01.18 08:09조회 수 0댓글 0

    • 글자 크기

1. Null Pointer 역참조의 위험성

CWE-476은 애플리케이션이 null 값을 가진 객체 참조를 사용하여 속성에 접근하거나 메서드를 호출하려고 할 때 발생합니다. 자바에서는 그 유명한 NullPointerException(NPE)이 발생하며 프로그램이 예외 처리가 되어 있지 않을 경우 즉시 중단됩니다. 공격자는 의도적으로 null을 유발하는 입력값을 주입하여 시스템을 서비스 거부(DoS) 상태로 만들거나, 예외 발생 시 출력되는 스택 트레이스(Stack Trace)를 통해 시스템 내부 구조 정보를 수집할 수 있습니다.

2. 흔히 발생하는 취약한 패턴

주로 외부 시스템과의 연동 결과나 사용자 입력값이 "반드시 존재할 것"이라고 가정할 때 나타납니다.

  • 메서드 반환값 미검증: DB 조회 결과나 API 호출 결과가 null일 수 있음에도 즉시 .toString()이나 .equals()를 호출하는 경우.

  • 조건문 순서 오류: if (data.equals("A") && data != null)와 같이 null 체크보다 사용을 먼저 하는 경우.

  • 복잡한 객체 그래프 탐색: user.getAddress().getCity() 처럼 중간 단계의 객체가 null일 가능성을 배제하고 연쇄적으로 호출하는 경우.

3. 실무적 대응: 방어적 코딩과 옵셔널 활용

가장 확실한 방어법은 "객체는 언제든 null일 수 있다"고 가정하고 코드를 작성하는 것입니다.

  • 선 검증 후 사용: 객체를 참조하기 직전에 반드시 null 여부를 확인합니다.

  • Optional 클래스 도입: Java 8 이상이라면 Optional<T>를 사용하여 값이 없을 수 있음을 명시적으로 표현하고 안전하게 처리합니다.

  • Null-Safe 라이브러리 활용: Apache Commons Lang의 StringUtils.equals(a, b)와 같이 null 입력에도 안전한 유틸리티 메서드를 사용합니다.

  • 정적 분석 도구 사용: IDE의 경고 설정이나 SonarQube 등을 통해 잠재적인 null 참조 지점을 배포 전 찾아냅니다.

4. CWE-476 대응 및 안전한 객체 참조 자바 코드 예시

Java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Optional;

public class NullSafetyManager {
    private static final Logger logger = LoggerFactory.getLogger(NullSafetyManager.class);

    // [CWE-476 조치] 전통적인 방어적 코딩 방식 (Null Check)
    public void processOrder(String orderId) {
        // 외부 입력을 받는 orderId가 null인지 먼저 확인
        if (orderId == null || orderId.trim().isEmpty()) {
            logger.debug("Security Event: Received null or empty order ID. Aborting process.");
            return;
        }

        // 이후 로직 수행
        logger.debug("Processing order: {}", orderId.toUpperCase());
    }

    // [CWE-476 조치] Optional을 활용한 안전한 처리 (Java 8+)
    public void updateUserName(User user) {
        // user 객체가 null일 가능성에 대비
        Optional<User> userOpt = Optional.ofNullable(user);

        // 값이 존재할 때만 실행되도록 보장
        userOpt.ifPresent(u -> {
            String name = u.getName();
            if (name != null) {
                logger.debug("Updating user name to: {}", name);
                // 업데이트 로직...
            }
        });
        
        if (userOpt.isEmpty()) {
            logger.debug("Security Event: Attempted to update a null user object.");
        }
    }
}

코멘트: "이 값은 절대 null이 아닐 거야"라는 확신이 시큐어 코딩에서는 가장 위험합니다. 특히 클라이언트에서 넘어오는 데이터나 외부 API의 응답은 언제든 비어있을 수 있음을 명시하십시오. logger.debug()를 통해 null 발생 상황을 기록하되, 예외가 발생하여 사용자에게 시스템 내부 정보가 노출되거나 서비스가 멈추지 않도록 꼼꼼한 그물망(검증 로직)을 치는 것이 기본입니다.

    • 글자 크기
끝맺음의 중요성: CWE-416 해제된 자원 사용 & 자원 고갈 방지 (by suritam9) 시스템을 멈추게 하는 굴레: CWE-835 & CWE-674 자원 고갈 방지 (by suritam9)

댓글 달기

첨부 (0)
위로