본문으로 건너뛰기
피드

해시는 바이트만 증명한다, Collider 1.3.0의 패키지 보안 수리기

security 약 9분
vote
0
댓글
북마크

Collider 1.3.0은 Meson 패키지 관리 과정에서 해시 검증만으로 막을 수 없는 두 가지 문제를 고쳤다. 저장소 인덱스의 패키지명·버전명을 경로로 쓰는 순간 생기는 경로 탐색 문제와, 인증 요청이 교차 출처 리다이렉트될 때 bearer token이 새 호스트로 넘어가는 문제가 핵심이다.

  • 1

    releases.json의 name/version을 신뢰하지 않고 안전한 단일 경로 세그먼트인지 먼저 검증

  • 2

    인증 API 호출에서 리다이렉트 출처가 바뀌면 Authorization 헤더를 제거

  • 3

    해시는 lockfile의 바이트 일치만 증명할 뿐, 누가 만들었는지는 증명하지 못해 signing을 다음 로드맵으로 제시

  • Collider 글의 핵심은 제목 그대로임 — 해시는 “이 바이트가 lockfile에 적힌 바이트와 같다”만 증명함
    • 어떤 이름이 어떤 URL로 해석됐는지, 그 URL이 어디로 리다이렉트됐는지, 누가 게시했는지는 해시만으로 알 수 없음
    • Collider 1.3.0은 해시 검증 전에 벌어지는 두 군데 문제를 고쳤다고 설명함

저장소 인덱스도 입력값이다

  • 첫 번째 문제는 WrapDB 호환 저장소의 releases.json 인덱스였음

    • 이 파일은 패키지 이름과 버전 목록을 제공함
    • 문제는 name/version이 단순 라벨이 아니라 실제 파일 경로 일부가 된다는 점임
    • 예를 들면 subprojects/<name>.wrap, ~/.config/collider/cache/wraps/<name>_<version>.wrap 같은 식임
  • 악의적인 인덱스가 ../../../../etc/cron.d/x 같은 이름을 주면 경로 탐색(path traversal)이 됨

    • Collider가 그 값을 파일명으로 쓰면 캐시 디렉터리 바깥으로 빠져나갈 수 있음
    • version 문자열도 똑같은 공격면이 됨
    • 공개 미러나 동료가 띄운 저장소 URL을 쓴다면 Collider가 제어하지 않는 서버 입력을 그대로 믿는 셈임
  • 그래서 Collider는 인덱스를 파싱하는 한 지점에서 name/version을 먼저 거르도록 바꿨음

    • packages_from_releases가 인덱스를 패키지 엔트리로 만드는 관문이라 여기에 검증을 넣음
    • is_safe_path_segment는 빈 문자열, ., .., 경로 구분자, null byte를 거부함
    • Path(value).name이 원래 값과 달라지는 경우도 거부함

⚠️주의

> 패키지명과 버전명은 UI에 보이는 문자열처럼 보여도, 패키지 매니저 내부에서는 경로가 되는 순간 공격 입력이 됨.

  • 읽기와 쓰기에서 실패 처리는 다르게 가져감

    • 캐시 생성이나 publish 같은 쓰기 경로에서는 traversal 이름을 발견하면 예외를 던짐
    • 검색처럼 외부 releases.json을 읽는 흐름에서는 잘못된 엔트리를 스킵하고 debug 로그만 남김
    • 경로를 만드는 각 sink에도 방어 검사를 남겨 defense in depth로 둠
  • 아카이브 내부 파일명도 똑같이 untrusted input으로 봄

    • wrap이 가리키는 tar/zip 안에 ../../x 같은 멤버가 있으면 추출 디렉터리 밖으로 나갈 수 있음
    • Collider는 meson.build를 스캔하기 위해 임시 추출할 때 Python tar data filter와 zip 경로 정리를 사용함
    • 빌드 시점의 실제 추출은 Meson이 담당하고, archive hash로 보호된다고 설명함

토큰은 리다이렉트에 따라가면 안 된다

  • 두 번째 문제는 collider publishcollider unpublish의 bearer token 처리임

    • 이 명령들은 저장소의 _collider/v1/ 쓰기 API로 Authorization 헤더를 보냄
    • Python 기본 urllib opener는 리다이렉트가 발생해도 요청 헤더를 다시 보냄
    • 즉 저장소가 302 Location: https://another-host/...를 주면 토큰이 다른 호스트로 넘어갈 수 있었음
  • Collider는 인증 호출을 safe_urlopen으로 보내고, 출처가 바뀌면 Authorization을 제거하게 바꿈

    • _origin은 scheme, host, port를 비교함
    • https://hhttps://h:443처럼 기본 포트는 같은 origin으로 정규화함
    • 같은 origin 리다이렉트면 토큰을 유지하고, 다른 origin이면 토큰을 빼서 보냄
  • 이 수정은 토큰을 “안전하게” 만드는 게 아니라, 엉뚱한 호스트로 보내지 않게 하는 좁은 수리임

    • collider serve 자체에는 TLS가 없음
    • 정적 bearer token은 결국 전송 채널이 안전해야 의미가 있음
    • 프로덕션에서는 TLS 종료 reverse proxy를 앞에 둬야 한다고 명시함
sequenceDiagram
    participant 사용자
    participant 콜라이더
    participant 원본저장소
    participant 다른호스트
    사용자->>콜라이더: publish 요청
    콜라이더->>원본저장소: Authorization 포함 쓰기 API 호출
    원본저장소-->>콜라이더: 302 리다이렉트
    콜라이더->>콜라이더: 출처 변경 감지 후 Authorization 제거
    콜라이더->>다른호스트: 토큰 없는 요청
    다른호스트-->>콜라이더: 인증 실패

해시 다음은 서명이다

  • Collider의 기존 hash와 origin pinning은 여전히 중요하지만 한계가 있음

    • hash는 lockfile에 기록된 바이트와 설치할 바이트가 같은지만 보장함
    • origin pinning은 lock 당시의 저장소 URL에서만 설치하게 해서 기본적인 dependency confusion을 막음
    • 하지만 저장소 자체가 뚫렸거나, 처음 lockfile을 만들 때 오염된 인덱스를 봤다면 해시는 그대로 맞아버림
  • 오프라인 캐시 fallback에서도 출처 정보는 약해짐

    • 캐시는 wrap이 어떤 저장소에서 왔는지 알 수 없음
    • 그 상황에서는 content hash만 남음
    • 그래서 “어디서 왔는가”와 “누가 만들었는가”는 별개 문제로 남음
  • 다음 로드맵은 signing임

    • 게시자가 wrap과 archive에 서명함
    • 소비자는 이미 신뢰하는 키로 서명을 검증함
    • 이렇게 해야 패키지가 특정 신뢰 키 보유자에게 묶이고, hash가 못 하는 provenance 검증을 할 수 있음

기술 맥락

  • 이 글이 좋은 이유는 공급망 보안의 레이어를 분리해서 보여주기 때문이에요. hash는 다운로드한 바이트가 lockfile과 같은지만 확인해요. 그런데 어떤 URL을 고를지, 파일명을 어디에 쓸지, 인증 헤더를 어디까지 보낼지는 hash 전에 이미 결정돼요.

  • 경로 탐색을 sink마다 막는 대신 인덱스를 파싱하는 관문에서 먼저 거른 선택도 실용적이에요. 패키지명과 버전이 여러 경로에서 재사용되기 때문에, 매번 파일을 만들기 직전에만 막으면 새 코드가 추가될 때 빠뜨리기 쉽거든요. 그래도 각 sink 검사는 남겨서 방어층을 하나 더 둔 구조예요.

  • Authorization 헤더 제거는 HTTP 클라이언트 구현에서 자주 놓치는 부분이에요. 같은 출처 리다이렉트는 정상 배포 구성에서도 필요할 수 있지만, 출처가 바뀌는 순간 토큰을 따라 보내면 인증한 적 없는 서버에 권한을 넘기는 꼴이 돼요.

  • 마지막으로 signing 로드맵이 중요한 건 hash와 서명이 푸는 문제가 다르기 때문이에요. hash는 무결성, origin pinning은 저장소 혼동 방지, signing은 게시자 신뢰를 담당해요. 패키지 매니저를 만들거나 사내 아티팩트 배포 시스템을 운영한다면 이 셋을 같은 기능으로 뭉개면 안 돼요.

패키지 매니저 보안에서 “해시 찍었으니 끝”이 얼마나 위험한 착각인지 잘 보여주는 글임. 의존성 공급망에서는 바이트 검증, 출처 고정, 경로 정규화, 토큰 전달 정책, 서명까지 각각 막는 공격면이 다르다.

댓글

댓글

댓글을 불러오는 중...

security

아마존 Q 개발자 확장에 고위험 취약점, 악성 저장소만 열어도 클라우드 키 털릴 뻔

보안기업 위즈가 아마존 Q 디벨로퍼 확장 프로그램에서 개발자의 클라우드 자격 증명과 API 키가 유출될 수 있는 심각한 취약점을 발견했다. 악성 저장소를 열고 아마존 Q를 활성화하면 설정 파일 자동 실행, 쉘 생성, 환경 상속이 맞물려 민감 정보가 외부로 빠져나갈 수 있는 구조였다.

security

세일포인트, 레거시 아이덴티티 시스템 클라우드 이전을 AI로 며칠 안에 끝내겠다고 나섬

세일포인트가 온프레미스 아이덴티티 시스템을 클라우드로 이전하는 작업을 자동화하는 AI 기반 방법론을 출시했다. 구성 변환, 워크플로우, 정책 이전 같은 까다로운 작업을 자동화해 기존 수개월짜리 전환 프로젝트를 수일 단위로 줄이는 게 핵심이다.

security

중국 오픈소스 AI가 취약점 탐지에서 미소스급으로 올라왔다는 얘기

지푸AI의 GLM-5.2가 사이버보안 벤치마크에서 앤트로픽의 보안 특화 모델 미소스에 근접했다는 보도가 나왔다. 문제는 이 모델이 오픈소스라 누구나 내려받아 자체 환경에서 돌릴 수 있고, 방어자뿐 아니라 공격자도 같은 속도로 취약점을 찾을 수 있다는 점이다. 미국의 AI 접근 제한이 오히려 중국 오픈웨이트 모델 확산을 밀어준다는 비판도 같이 커지고 있다.

security

유니앱으로 찍어낸 투자 사기 사이트가 20만 개 넘게 발견됨

중국 오픈소스 크로스플랫폼 프레임워크 유니앱이 20만 개 이상의 투자 사기 사이트 템플릿에 악용된 것으로 보도됐다. 정상 개발 도구 자체가 문제라는 뜻은 아니고, 사기 조직들이 같은 프레임워크와 템플릿을 대량으로 재사용하고 있다는 보안 이슈에 가깝다.

security

세온이앤에스, 임베디드 코드에서 숨은 오픈소스까지 잡는 SBOM 분석 도구 출시

세온이앤에스가 임베디드 소스코드 안에 직접 복사돼 들어간 오픈소스까지 찾아내는 Seon Code Analyzer를 출시했다. 의존성 파일만 보는 일반 소프트웨어 구성 분석(SCA)과 달리 코드 자체의 디지털 지문을 대조해 CycloneDX SBOM, CVE 취약점, SPDX 라이선스 리포트를 한 번에 만든다는 게 핵심이다.