FlawOpen

flawopen.com/Ruby YAML/Ruby YAML

신뢰할 수 없는 입력에 YAML.load를 사용해도 안전한가요?

CWE-502: Deserialization of Untrusted Data참고 페이지
간단한 설명

애플리케이션이 실제로 불러오는 Psych 버전을 확인하세요. Ruby 3.1에 포함된 Psych 4는 YAML.load가 기본적으로 안전하게 역직렬화하도록 변경했습니다. 이전 Psych 버전은 제한 없이 객체를 생성했고, Psych는 Ruby와 별도로 업그레이드할 수도 있습니다. YAML.unsafe_load와 Marshal.load는 Ruby 객체를 역직렬화하므로 신뢰할 수 없는 입력에 사용하면 안 됩니다.

VULNERABLE
# Psych < 4: YAML.load used unsafe
# object construction by default.
YAML.load(params[:config])

# Every Psych version: explicitly unsafe.
YAML.unsafe_load(user_input)
Psych.unsafe_load(user_input)

# Marshal has no restricted safe-load API.
Marshal.load(cookie_value)
FIXED
# Explicit restricted types; keep this list minimal.
require "yaml"
require "date"

data = YAML.safe_load(
  input,
  permitted_classes: [Date],
  permitted_symbols: [],
  aliases: false
)

# For ordinary external data, prefer JSON and
# validate its shape, values, and input size.
data = JSON.parse(input)

YAML이 위험할 수 있는 이유

YAML 태그는 Psych를 통해 Ruby 객체로 변환될 수 있습니다. 안전하지 않은 로드에서는 태그가 붙은 문서가 클래스를 생성하고 직렬화된 상태의 값을 지정할 수 있습니다. 영향은 사용 가능한 클래스와 동작에 따라 달라지며, 이것이 역직렬화 gadget chain의 기반입니다. 신뢰할 수 없는 YAML에는 안전한 로드를 사용하고 반환된 데이터도 별도로 검증하세요. 유사한 일반 위험은 Python pickle, PHP unserialize, Ruby Marshal.load에도 있습니다.

Rails 등은 많은 의존성을 불러올 수 있어 안전하지 않은 역직렬화 체인이 활용할 수 있는 클래스와 동작이 늘어날 수 있습니다. 이는 배포 환경에 따라 달라지며 모든 Rails 애플리케이션이나 YAML 문서에 해당하지 않습니다.

버전 변경이 혼란을 일으킨 이유

Psych 4는 YAML.load를 기본 안전 로드로 바꾸고 이전 객체 생성 동작을 위한 unsafe_load를 추가했습니다. Ruby 3.1에 Psych 4가 포함됐지만 앱은 다른 Psych gem 버전을 선택할 수 있습니다. Ruby 버전만 보지 말고 실제 해결된 의존성과 런타임을 확인하세요. 안전 로드가 앱 전용 클래스나 alias를 거부할 수 있지만 unsafe_load로 전환하지 말고 최소 명시적 허용 목록으로 이전하세요.

업그레이드로 unsafe_load가 도입되면 입력이 신뢰된 배포 경계 밖에서 영향을 받을 수 있을 때 보안 문제로 처리하세요. 최소한의 permitted_classes만 지정한 safe_load를 우선하고, 호환성 오류를 숨기려고 허용 범위를 넓히지 마세요.

FAQ

자주 묻는 질문

YAML.safe_load는 완전히 안전한가요?

Psych.safe_load는 역직렬화 허용 클래스를 제한하며(기본은 단순 스칼라와 컬렉션) alias를 거부합니다. 하지만 앱의 데이터 구조, 크기, 업무 규칙은 검증하지 않습니다. 필요한 클래스만 허용하고 입력 크기를 제한한 뒤 반환 데이터를 검증하세요. 일부 YAML 구현과 처리 과정에서 alias 확장 DoS가 발생한 적이 있으며, CVE-2024-35221은 RubyGems 메타데이터 처리 사례를 기록합니다. 모든 Psych.safe_load 호출이 취약하다는 뜻은 아닙니다.

직접 관리하는 설정 파일은 어떤가요?

신뢰할 수 있고 무결성이 보호된 앱 아티팩트에 포함된 파일은 사용자 업로드나 테넌트가 제어하는 파일과 출처가 다릅니다. 내부 설정도 safe_load를 우선하고 필요한 클래스만 허용하세요. unsafe_load는 고정되어 있고 신뢰성을 입증할 수 있는 데이터에만 사용하고, 사용자나 요청의 영향을 받는 콘텐츠에는 쓰지 마세요.

Marshal은 사용해도 되나요?

별도의 Ruby 위험: Marshal.load

YAML과 별개로 Ruby 문서는 Marshal.load가 프로세스에 로드된 거의 모든 클래스를 복원할 수 있으며, 신뢰할 수 없는 데이터에서는 원격 코드 실행으로 이어질 수 있다고 경고합니다. Marshal 데이터는 신뢰 경계 안에 두고, 사용자 제공 또는 공격자 영향을 받은 바이트를 역직렬화하지 마세요.

참고 자료

함께 보기 안전하지 않은 역직렬화: 위험과 대응 | flawopen.com .NET BinaryFormatter: 위험과 마이그레이션 Java ObjectInputStream 보안과 안전한 역직렬화 Newtonsoft.Json TypeNameHandling: 안전한 설정 PHP unserialize()와 신뢰할 수 없는 입력 Python pickle.load(): 신뢰할 수 없는 데이터 위험