메뉴 건너뛰기

app

찰나의 순간을 노리는 공격: CWE-367 TOCTOU 경쟁 조건

suritam92026.01.18 08:05조회 수 1댓글 0

    • 글자 크기

1. TOCTOU의 위험성

CWE-367은 자원의 상태를 **검사(Check)**하는 시점과 이를 실제로 **사용(Use)**하는 시점 사이에 짧은 시간적 간격이 존재할 때 발생합니다. 공격자는 이 찰나의 간극을 이용해 자원의 상태를 변경함으로써, 검사 단계를 통과한 후 부적절한 권한으로 자원에 접근하거나 시스템을 오작동하게 만듭니다. 주로 파일 시스템 접근, 공유 메모리 참조, DB 트랜잭션 처리에서 빈번하게 발생하며, 멀티스레드 환경에서 특히 위험합니다.

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

가장 대표적인 사례는 파일 권한 확인과 파일 쓰기 사이의 간극을 노리는 공격입니다.

  • 파일 시스템 공격: 특정 파일에 쓸 권한이 있는지 if(file.canWrite())로 검사한 직후, 실제 데이터를 쓰기(file.write()) 직전에 공격자가 해당 파일을 관리자 권한이 필요한 민감한 파일(예: /etc/passwd)에 대한 심볼릭 링크로 바꿔치기하는 경우입니다.

  • 중복 결제/인출: 계좌 잔액이 충분한지 검사한 후 인출 로직이 실행되기 전, 아주 짧은 시간에 여러 개의 요청을 동시에 보내 잔액보다 많은 금액을 인출하는 경우입니다.

3. 실무적 대응: 원자적 연산과 잠금(Locking)

검사와 사용이 분리되지 않도록 하나로 묶는 것이 핵심입니다.

  • 원자적(Atomic) 연산 사용: 검사와 사용을 동시에 수행하는 API를 사용합니다. 예를 들어, 파일이 없을 때만 생성하도록 하는 O_EXCL 플래그를 사용하여 열기 연산을 수행합니다.

  • 자원 잠금(Resource Locking): 자원을 검사하기 전에 해당 자원에 배타적인 잠금(Lock)을 걸어, 사용이 끝날 때까지 다른 프로세스나 스레드가 개입하지 못하도록 보호합니다.

  • 임시 복사본 활용: 공유 자원을 직접 다루지 않고, 로컬 복사본을 만들어 검증 및 수정한 후 원본에 한 번에 반영합니다.

4. CWE-367 대응 및 안전한 파일 처리 자바 코드 예시

Java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.file.*;
import java.util.EnumSet;

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

    // [CWE-367 조치] 검사 후 사용 대신 원자적 옵션을 사용하여 파일 생성
    public void createSecureFile(String pathString) {
        Path path = Paths.get(pathString);

        try {
            // [위험한 방식] 
            // if (!Files.exists(path)) { // Check
            //     Files.createFile(path); // Use (이 사이에 파일이 생성될 수 있음)
            // }

            // [안전한 방식] CREATE_NEW 옵션은 파일이 존재하면 예외를 발생시킴 (원자적 연산)
            Files.write(path, "Secure Data".getBytes(), 
                        StandardOpenOption.CREATE_NEW, 
                        StandardOpenOption.WRITE);
            
            logger.debug("File created atomically: {}", pathString);

        } catch (FileAlreadyExistsException e) {
            // 검사 시점과 사용 시점 사이에 이미 파일이 생성된 경우
            logger.debug("Security Event: File already exists. Potential race condition prevented.");
        } catch (IOException e) {
            logger.debug("I/O error during atomic file operation: {}", e.getMessage());
        }
    }
}

코멘트: "검사했을 때는 괜찮았다"는 변명은 시큐어 코딩에서 통하지 않습니다. 멀티태스킹 환경에서 자원의 상태는 언제나 가변적입니다. 특히 파일 시스템이나 데이터베이스를 다룰 때는 **'동기화(Synchronization)'**와 **'원자성(Atomicity)'**을 최우선으로 고려하십시오. logger.debug()를 통해 예외 상황을 기록하되, 공격자가 끼어들 틈을 주지 않는 단단한 로직을 설계하는 것이 고도화된 보안의 시작입니다.

    • 글자 크기
시스템을 멈추게 하는 굴레: CWE-835 & CWE-674 자원 고갈 방지 (by suritam9) 멈추지 않는 공격자: CWE-307 반복된 인증 시도 제한 기능 부재 (by suritam9)

댓글 달기

첨부 (0)
위로