메뉴 건너뛰기

app

섞여버린 데이터의 비극: CWE-488 & CWE-543 잘못된 세션 정보 노출

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

    • 글자 크기

1. 잘못된 세션에 의한 정보 노출의 위험성

이 취약점들은 여러 사용자가 동시에 접속하는 웹 환경에서 공유 자원(멤버 변수, 정적 변수 등)을 안전하게 관리하지 못할 때 발생합니다.

  • CWE-488: 서버가 A 사용자의 요청을 처리하던 중 저장한 민감한 정보를 B 사용자의 응답에 포함시켜 보내는 경우입니다.

  • CWE-543: 싱글톤(Singleton) 객체나 서블릿(Servlet) 필드에 사용자별 상태를 저장할 때, 동기화 처리가 미흡하여 데이터 레이스(Data Race)가 발생하고 값이 뒤섞이는 현상입니다. 공격자는 이를 통해 타인의 개인정보, 결제 내역, 혹은 인증 토큰을 탈취할 수 있습니다.

2. 흔히 발생하는 취약한 패턴: "서블릿 필드의 함정"

자바 서블릿(Servlet)이나 스프링의 빈(Bean)은 기본적으로 싱글톤으로 동작한다는 점을 잊을 때 주로 발생합니다.

  • 서블릿 멤버 변수 사용: 서블릿의 멤버 변수에 userIdorderInfo를 저장하면, 모든 사용자가 이 변수를 공유하게 됩니다.

  • 정적(Static) 변수에 사용자 정보 저장: 클래스 수준의 static 변수에 세션 정보를 담아 관리하는 경우.

  • 멀티스레드 비안전 객체 공유: SimpleDateFormat이나 HashMap처럼 스레드에 안전하지 않은 객체를 싱글톤 필드에서 공유하며 사용자 데이터를 처리하는 경우.

3. 실무적 대응: 상태 없는(Stateless) 설계와 지역 변수 활용

사용자별 데이터는 해당 스레드 안에서만 머물도록 설계해야 합니다.

  • 멤버 변수 대신 지역 변수 사용: 사용자 데이터를 메서드 내부의 지역 변수(Local Variable)로 처리하여 스레드 스택(Stack)에만 존재하게 합니다.

  • ThreadLocal 활용: 스레드 단위로 독립적인 저장소를 제공하는 ThreadLocal을 사용하여 공유 객체 내에서도 사용자별 데이터를 격리합니다.

  • Stateless 빈 설계: Spring 컨트롤러나 서비스에서는 상태를 가지는 멤버 변수를 두지 않고, 모든 데이터를 파라미터로 전달받아 처리합니다.

4. CWE-488/543 대응 및 안전한 데이터 처리 자바 코드 예시

Java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;

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

    // [위험] 싱글톤 객체의 멤버 변수는 모든 사용자가 공유함 (CWE-488, CWE-543 유발)
    // private String currentUserId; 

    public void processOrder(HttpServletRequest request) {
        // [CWE-488 조치] 사용자 정보를 메서드 내 지역 변수로 선언하여 스레드 격리
        String userId = request.getParameter("userId");
        String orderId = request.getParameter("orderId");

        // 비즈니스 로직 수행
        logger.debug("Processing order {} for user {}", orderId, userId);
        
        saveToDatabase(userId, orderId);
    }

    // [참고] 만약 공유 객체에서 스레드별 식별자가 필요하다면 ThreadLocal 사용
    private static final ThreadLocal<String> userContext = new ThreadLocal<>();

    public void setContext(String userId) {
        userContext.set(userId);
    }

    public void clearContext() {
        userContext.remove(); // 메모리 누수 방지를 위해 반드시 remove 호출
    }
}

코멘트: 웹 애플리케이션에서 서블릿 인스턴스는 단 하나만 생성됩니다. 멤버 변수에 값을 넣는 행위는 "우리 집 거실에 내 지갑을 두고, 모든 사람이 거실을 지나가게 하는 것"과 같습니다. 반드시 지역 변수를 사용하고, SimpleDateFormat 같은 객체는 매번 새로 생성하거나 ThreadLocal로 관리하십시오. logger.debug()를 통해 현재 스레드 ID와 사용자 ID를 함께 기록해 보면 데이터가 섞이는지 모니터링하는 데 도움이 됩니다.

    • 글자 크기
캡슐화의 구멍을 막아라: CWE-495 Private 배열 반환 (by suritam9) 객체 속에 숨은 트로이 목마: CWE-502 역직렬화 취약점 (by suritam9)

댓글 달기

첨부 (0)
위로