포맷 문자열 취약점
Use of Externally-Controlled Format String
설명
포맷 문자열 취약점은 String.format, System.out.printf, Formatter.format 등에서 포맷 문자열 자리에 신뢰할 수 없는 외부 입력을 그대로 사용할 때 발생합니다. 공격자는 추가 포맷 지정자(예: %s, %d, 위치 지정자 %1$... 등)를 삽입하여 인자 개수/타입 불일치를 유도해 예외를 발생시키거나, 위치 지정자를 악용해 개발자가 의도하지 않은 다른 인자의 내용을 노출시키는 등의 공격을 할 수 있습니다.
잠재적 영향
서비스 장애: 잘못된 포맷 지정으로 MissingFormatArgumentException, IllegalFormatConversionException 등이 발생해 요청 처리 실패 또는 장애 유발
정보 노출: 위치 지정자(%1$..., %2$...) 등을 악용해 다른 인자의 값이 노출될 수 있음
로그 오염/우회: %n 등 제어 문자를 삽입해 로그 포맷을 깨뜨리거나 다중 라인을 유도해 모니터링을 우회
자원 고갈형 DoS: 매우 큰 폭/정밀도(%1000000s 등)를 사용해 과도한 메모리/CPU 사용을 유발할 가능성
해결 방법
포맷 문자열은 항상 상수(고정 문자열)로 사용하고, 사용자 입력은 포맷 인자로만 전달하기
입력을 그대로 출력해야 한다면 포맷 문자열로 "%s"를 사용하기
포맷 패턴을 외부에서 받아야 한다면, 허용 목록(whitelist) 기반으로 제한된 소수 패턴만 허용하고 나머지는 기본 패턴으로 대체
로그 출력 시 SLF4J의 매개변수 바인딩(예: logger.info("User: {}", user))처럼 안전한 API 사용 고려
취약한 코드 및 안전한 코드 예시
취약한 코드
안전한 코드
설명:
취약한 코드: 외부 입력값이 포맷 문자열로 그대로 사용되었습니다. 공격자가 %2$s, %d 등 예기치 않은 포맷 지정자를 넣으면 인자 부족/타입 불일치로 예외가 발생하거나, 위치 지정자를 통해 다른 인자의 값이 노출될 수 있습니다.
안전한 코드: 포맷 문자열을 상수로 고정하고, 필요한 경우에만 허용 목록에 든 안전한 패턴만 사용합니다. 사용자 입력은 항상 포맷 인자로만 전달하거나 "%s"를 사용해 원문 그대로 출력하므로 예외 유발 및 정보 노출을 방지합니다.
참조
Last updated