강력한 라이프사이클 후크, 조용한 공격 표면 (번역)
원문: https://blog.gitguardian.com/how-to-explore-opensource-supply-chain-risks-1/
오픈소스 생태계의 속도는 현대 소프트웨어의 토대가 됐다. 앱 절반은 몇 주 만에 출시되고, 라이브러리는 하루 만에 업데이트된다. 문제는 공격자도 같은 속도로 움직인다는 점이다. 전통적인 해킹은 물리적 보안이나 복잡한 네트워크 침투를 요구했지만, 지금의 공격은 공급망 침투다. 신뢰하는 업스트림 소프트웨어에 악성 코드를 심어두면, 잠재 피해자가 직접 npm install을 실행해준다. 이 글은 Sonatype이 매달 기록하는 200억 건 이상의 악성 패키지 요청이라는 숫자에서 출발해, 개발자가 어디서 노출되고 어떻게 탐색할 수 있는지를 짚는다.
1. 현대 소프트웨어의 생명줄
소프트웨어 공급망이란 앱 개발자가 실제 기능 대부분을 조달하는 디지털 시장이다. 공급망이 커지면서, 공격자는 “위쪽(공급자)을 공략해 아래쪽(수요자)을 감염시키는” 방향을 선호한다. 이유는 간단하다. 대상이 보안의 핵심인 저장소가 아니라 보통 개발자니까.
저장소 간의 의존성은 나무에 비유된다. 중간 저장소는 자작나무 숲의 통나무 길목과 같아서, 한 그루가 쓰러지면 연결된 모든 것이 같이 움직인다. 그래서 전체 업데이트 흐름을 추적하려면 흐름의 맨 위를 봐야 한다. 특히 신뢰를 주장하는 패키지가 그렇다. 하지만 의존성 그래프는 방대해서, 효율적인 선택이 필요하다.
공급망 위에서 피해자는 골고루 분포하지 않는다
Java 개발자는 비즈니스 로직과 데이터 처리에 Maven을 쓰고, 풀스택이나 데이터 사이언스는 npm과 PyPI에 기운다. 그리고 조직은 자기 생태계 안에서도 취약한 곳과 그렇지 않은 곳이 갈린다. 이 글의 목표는 흐름 전체를 확인하는 일종의 카메라를 쥐여주는 것이다.
데이터 수집 방법은 두 가지다.
- 에이전트 방식: 개발자 장비에 설치해 실행을 감시한다. 실시간에 가깝지만 모든 개발자 기기에 설치해야 하고, 스케일업이 어렵고 보안 관점에서 불편하다.
- 주입 방식: 네트워크 어플라이언스나 회사 프록시에 붙어 지나가는 패키지 트래픽을 관찰한다. 사용자 환경에 도입이 쉽고 확장성이 좋다. 이 글에서 선택한 방식이다.
회사 프록시에 분석기를 배치하면 공개 저장소 요청을 관찰할 수 있다. 데이터를 수집해야 노출 정도를 평량할 수 있고, 수집한 데이터는 두 갈래로 쓰인다. 하나는 상위 N개 요청 구성의 정량 분석이고, 다른 하나는 요청에서 나타나는 이상 행위의 정성 분석이다.
인터넷으로의 개방이 공격 표면을 넓힌다
먼저 인터넷을 통해 자발적으로 노출되는 정보를 정리해보자.
- 패키지 관리자 도구는 설치하려는 패키지를 요청한다. 어떤 개발자가 어떤 패키지를 쓰는지는 노출된다.
- 저장소와 미러는 사용자가 패키지를 요청할 수 있게 해준다. 회사 생태계 바깥에서 만들어졌고, 공격자가 무작위 저장소를 미러 주소로 정해두면 회사 프록시가 실제로 요청을 처리하게 된다.
- 패키지 관리자에는 기본값이 아닌 설정에 의존하는 대안 저장소 기능이 있다. 이 기능은 위험할 수 있는데, 저장소 자체에 의존하는 보안 조치가 이런 미러에는 적용되지 않을 수 있기 때문이다.
이 정보는 개인 개발자에게는 유용한 피드백이지만, 조직 전체 관점에서는 사내 IP와 사용자별 요청이 노출된다. 이는 조직의 공격 표면을 넓히는 방향으로 작동한다. 궁극적으로 문제의 핵심은 사용자 설정이다. 서드파티 위험 관리의 관점에서, 회사 밖의 보안 정책이 회사 안으로 그대로 들어온다.
2. 어디서나 하는 오해: 저장소를 통제하면 안전하다
많은 사람이 패키지 저장소가 서드파티 코드를 선별하는 관문이라고 생각한다. 하지만 저장소의 역할은 호스팅이다. 새로 오는 코드가 환영받는지 아닌지에 관계없이 전부 받아준다. Sonatype의 연구팀이 올해 중반까지 200만 개가 넘는 악성 패키지를 기록했다. 게다가 잘 알려진 저장소에서조차 심각한 취약점이 발견됐다.
- 2019년 Justin Gardner가 발견한 것: 저장소가 패키지 압축 파일 안의
--config와 같은 값을 옵션으로 그대로 넘겨준다는 사실. 개발자가 로컬에서 설정 파일을 조작할 수 있다는 뜻이다. - 2021년 소스코드의 디렉터리 순회 취약점.
~/같은 상위 디렉터리 참조로 압축 파일을 풀 때 목표 경로 밖에 파일을 쓸 수 있게 하는 것으로, 전체 저장소를 무력화할 수 있었다. - 그리고 회사 프록시에 배치된 미러가 무분별하게 요청을 받아주는 문제. 위생 상태가 좋지 않은 회사 인프라에서 얼마든지 이런 일이 벌어진다.
이해하기 쉬운 결론이 하나 있다. 저장소에서 패키지를 받는 것과, 신뢰하는 패키지를 받는 것은 다른 문제다. 저장소는 멀웨어 배포를 막지 못한다. 오픈소스 생태계가 커진 지금, 위험도 그림자처럼 따라온다.
3. 저장소 위의 숨은 지뢰
표적을 골라내는 정밀한 사냥
오픈소스 생태계의 계층 구조 자체가 공격자에게 유리하다. 회사 프록시와 같은 관문을 지나는 트래픽을 관찰하면, 조직 내부에서 어떤 패키지가 살아 움직이는지 알 수 있다. 정직한 관찰자에게도 그렇지만, 공격자에게도 그렇다.
이제 신뢰 경계 안쪽에서 공격자가 움직이는 방식을 살펴보자.
- 오픈소스 패키지는 사실상 전부 서드파티에 의존한다. 패키지 자체의 취약점을 찾는 대신, 공격자는 그 패키지가 의존하는 것을 공략한다.
- 테스트 환경도 프로덕션 자격이 있다. 로컬 실행은 그저 실행일 뿐이라는 안이한 생각이 있다. 하지만 파일시스템 접근, API 토큰, 네트워크 포트는 프로덕션과 같은 위험을 그대로 품는다.
- 정적 분석은 절반의 그림만 보여준다. 코드 스캔으로도 좋은 인사이트를 얻지만, 히스토리·설정·런타임 행위는 다른 차원의 위험 요소다.
공격자는 이런 저강성 영역을 기회의 창으로 삼는다. 관찰자 입장에서 중요한 건 두 가지다. 무엇이 관찰 가능한지, 그리고 위험의 강도를 어떻게 재는지.
4. 숨어 있는 개발 도구, 조용한 공격 표면
공격이 항상 번쩍이지 않는다. 가장 조용한 공격은 개발 도구 안에 앉아 기다린다. 이 글에서 짚은 핵심을 정리하면 다음과 같다.
| 관찰 항목 | 위험 신호 |
|---|---|
| CI/CD 시크릿 | 빌드·배포 파이프라인의 토큰이 로그에 흘러다니는지 |
| 도커 환경 변수 | 이미지 안에 .env가 그대로 구워지는지 |
| 개발자 문서 | 샘플 코드에 하드코딩된 자격 증명이 있는지 |
| 패키지 매니페스트 | .npmrc, requirements.txt 안의 토큰 |
특히 CI 파이프라인은 손대기 쉬운 표적이다. 파이프라인을 이해하는 공격자는 전체 조직에 영향을 주는 단 하나의 변경을 만들 수 있다. 그리고 오픈소스 생태계에서 그런 변경은 코드 리뷰 하나 없이도 PR로 스며들 수 있다.
5. 공격 표면을 좁히는 요령
관찰이 끝났다면 이제 줄일 차례다.
- 프록시와 미러를 정리한다. 회사 프록시가 요청하는 저장소를 화이트리스트로 좁히면, 위험한 미러가 아예 통과하지 못한다.
- 최소 권한의 자격 증명을 쓴다. 조직 구성원이 장기 토큰 대신 짧은 수명의 토큰을 쓰면, 유출돼도 만료가 곧 방어가 된다.
- 관찰은 한 번으로 끝나지 않는다. 새 패키지가 올라올 때마다 위험 점수가 바뀐다. 자동화된 파이프라인이 필요한 이유다.
마치며
이 글은 오픈소스 공급망 위험을 “찾아나서는” 관점을 제안한다. 기다리는 대신 요청 트래픽을 관찰하고, 상위 의존성을 정량화하고, 위험 신호를 분류하는 방식이다. 저장소를 신뢰하는 습관에서 벗어나, 내 조직이 실제로 무엇을 끌어오는지 보는 습관으로 옮겨가는 것. 그것이 이 글이 제안하는 첫걸음이다.