소프트웨어 공급망 보안은 전담 보안 조직을 갖춘 회사만의 문제처럼 들리지만, 그런 구도 자체가 오해를 부릅니다. 서비스 몇 개를 운영하는 소규모 팀도 보통 수백 개의 패키지에 의존하며, 그중 어느 것도 팀원이 직접 읽어 본 적이 없습니다. 이 패키지들은 빌드 시점에 팀이 통제하지 못하는 레지스트리에서 내려받아지고, 배포 자격 증명이 들어 있는 장비 위에서 설치 스크립트를 실행합니다.
노출 정도는 회사 규모에 비례하지 않습니다. 의존성의 개수와 빌드 자동화 수준에 비례하며, 소규모 팀은 이 문제를 공개적으로 걱정하는 큰 조직보다 앞의 것은 더 많이 가지고 있고 뒤의 것은 덜 들여다보는 경우가 많습니다.
불편한 산수: 여러분의 애플리케이션에는 직접 의존성이 열 개 남짓, 전이 의존성이 수백 개 있을 것입니다. 열 개 남짓은 여러분이 직접 골랐습니다. 나머지는 고른 적이 없고, 그중 어느 것도 읽어 본 적이 없으며, 그 가운데 하나라도 설치 스크립트를 실행하면 여러분의 빌드 프로세스와 똑같은 권한을 갖습니다. 이것이 실제 공격 표면이고, 여러분이 직접 쓴 의존성 목록에서는 전혀 보이지 않습니다.
공급망 보안은 설치 시점에서 시작된다
위험한 순간은 대개 코드를 실행할 때가 아닙니다. 코드를 설치할 때입니다.
패키지 매니저는 설치 과정에서 스크립트가 실행되도록 허용합니다. 탈취되었거나 악의적으로 만들어진 패키지가 설치를 실행한 사람의 권한으로 그대로 돌아간다는 뜻입니다. 개발자 장비라면 그 사람의 자격 증명이고, 빌드 파이프라인이라면 배포 키입니다. 뒤쪽이 훨씬 더 나쁜 상황입니다.
실제 사고의 대부분은 세 가지 공격 형태로 설명됩니다.
타이포스쿼팅. 널리 쓰이는 패키지와 이름이 한 글자만 다른 패키지를 올려 두고, 누군가 설치 명령을 잘못 입력하기를 기다리는 방식입니다. 준비 비용이 거의 들지 않으면서 규모가 커질수록 잘 통합니다.
정상 패키지의 계정 탈취. 널리 쓰이는 패키지의 관리자 계정 자격 증명이 유출되어, 해로운 코드가 더해진 채로 새 버전이 배포되는 경우입니다. 방어하기가 가장 어렵습니다. 이름도 다운로드 수도 이상해 보이는 구석이 전혀 없기 때문입니다.
의존성 혼동(dependency confusion). 여러분의 내부 패키지 이름으로 공개 패키지를 올려 두면, 잘못 설정된 리졸버가 사설 레지스트리 대신 공개 레지스트리를 우선하는 상황입니다. 전적으로 설정의 문제이며, 전적으로 막을 수 있습니다.
이 가운데 어느 것도 누군가가 여러분만 콕 집어 노려야 성립하지 않습니다. 바로 그 점이 핵심입니다. 기회주의적이고, 아주 잘 확장됩니다.
작은 규모에서도 값어치를 하는 통제
락파일(lockfile)을 저장소에 커밋하고 거기서 설치하십시오. 락파일은 정확한 버전과 그에 딸린 해시를 고정합니다. 반대로 매니페스트에서 설치하면 빌드 시점에 새 버전이 다시 해석되고, 빌드가 재현 불가능해지며, 상위 패키지의 변경이 아무 검토 없이 운영 환경까지 도달합니다. 락파일과 내용이 맞지 않을 때 조용히 갱신해 버리는 명령이 아니라, 실패로 멈추는 설치 명령을 쓰십시오.
가능한 곳에서는 설치 스크립트를 꺼 두십시오. 많은 생태계가 이 옵션을 제공하고, 대부분의 패키지는 설치 스크립트가 필요하지도 않습니다. 추가 도구 없이 얻을 수 있는 가장 큰 단일 노출 감소이며, 그것 때문에 깨지는 소수의 패키지야말로 여러분이 알아 두어야 할 패키지입니다.
취약점 알림을 자동화한 뒤 분류하십시오. 스캐너는 소규모 팀이 처리할 수 있는 것보다 훨씬 많은 결과를 쏟아냅니다. 실패는 알림을 놓치는 데서 오지 않고, 대부분이 무관하다는 이유로 전부 무시하는 데서 옵니다. 여러분의 코드에서 실제로 도달 가능한 것만 걸러 내고 그것만 처리하십시오. 아무도 읽지 않는 대기열은 대기열이 아예 없는 것보다 나쁩니다.
빌드 도구도 함께 고정하십시오. 컨테이너 이미지, 런타임 버전, 파이프라인이 호출하는 액션이나 플러그인 역시 전부 의존성입니다. 불변 다이제스트 대신 바뀔 수 있는 태그를 참조한다는 것은 빌드가 여러분 모르게 달라진다는 뜻입니다.
빌드 자격 증명을 나머지 전부와 분리하십시오. 배포를 수행할 수 있는 파이프라인이 그 이상을 할 수 있는 자격 증명까지 들고 있어서는 안 되고, 탈취된 빌드가 운영 데이터에 닿을 수 있어서도 안 됩니다.
SBOM이 알려주는 것과 알려주지 않는 것
소프트웨어 자재 명세서, 줄여서 SBOM은 애플리케이션 안에 무엇이 들어 있는지를 나열한 목록이며, 그 값어치는 단 하나의 질문에 빠르게 답하는 데 있습니다. 우리도 영향을 받는가?
예전에는 이 질문에 답하는 데 며칠이 걸렸습니다. 널리 쓰이는 구성 요소에서 취약점이 드러났을 때, 최신 목록을 가진 조직은 몇 분 만에 답하고 목록이 없는 조직은 일주일을 찾는 데 씁니다. 이 차이가 근거의 전부이고, SBOM 도입이 권장되는 이유도 그것이 고급 통제가 아니라 기본 관행이기 때문입니다.
반대로 SBOM이 해 주지 않는 일은 여러분을 안전하게 만드는 것입니다. 목록은 목록일 뿐 방어가 아닙니다. 나열된 취약점이 여러분의 코드에서 도달 가능한지, 여러분의 설정에서 실제로 문제가 되는지, 이미 침해가 일어났는지는 알려주지 않습니다. 하나 만들어서 어딘가에 보관해 둔 팀은 통제가 아니라 문서를 하나 늘린 것입니다.
매니페스트가 주장한 내용이 아니라 실제로 배포된 내용을 기술하도록, 빌드 과정에서 생성하십시오. 릴리스마다 그에 대응하는 것을 함께 보관하십시오. 그리고 그 값어치가 압박 속에서 받게 될 질문에 답하는 속도에 전적으로 달려 있다는 점을 받아들이십시오.
소규모 팀이 실제로 다치는 지점
대개는 이국적인 패키지 침해 때문이 아닙니다. 평범한 것들 때문입니다.
저장소 안의 시크릿. 지운 뒤에도 이력에 그대로 남고, 푸시한 지 몇 분 안에 자동 스캐너가 찾아냅니다. 삼 년 동안 갱신되지 않은 의존성. 공개된 익스플로잇이 있는데 업그레이드 경로는 없습니다. 버전 올리는 일을 계속 미루다 보니 그 자체로 하나의 프로젝트가 되어 버렸기 때문입니다. 권한이 지나치게 넓은 빌드 파이프라인. 포크에서 올라온 풀 리퀘스트가 가져서는 안 될 접근 권한으로 실행됩니다. 아무도 보고 있지 않다는 사실. 어떤 알림도 사람에게 도달하지 않으니 침해가 오래 지속됩니다.
화려하지 않은 결론은, 실무에서 공급망 보안의 대부분이 의존성을 최신 상태로 유지하는 일이라는 것입니다. 팀들이 선택 사항처럼 다루는 소프트웨어 유지보수 비용이 바로 같은 작업이며, 그것을 미루면 일상적인 업그레이드가 익스플로잇이 딸린 비상 상황으로 바뀝니다.
규모에 맞는 출발점
소규모 팀이라면 이 순서로 하십시오. 저장소에서 시크릿을 빼내고 노출된 것은 전부 교체합니다. 락파일을 커밋하고 엄격하게 거기서만 설치합니다. 의존성 알림을 켜고 상시가 아니라 주 단위로 분류합니다. 빌드 도구를 불변 참조에 고정합니다. 파이프라인 권한을 필요한 최소한으로 줄입니다. 나머지가 자리를 잡은 뒤에 릴리스마다 SBOM을 생성합니다.
이 순서면 전담 보안 조직 없이도 현실적인 위협을 덮을 수 있고, 각 단계는 몇 주가 아니라 몇 시간 단위로 끝납니다. 그 너머의 통제, 즉 출처 증명과 재현 가능한 빌드, 서명된 아티팩트는 실제로 가치가 있지만 기본기가 이미 안정적으로 돌아가는 단계에 속합니다.
Mecanik은 애플리케이션 보안 분석 작업의 일부로 빌드 파이프라인을 점검하고 강화합니다. 발견되는 것은 거의 언제나 정교한 침해가 아닙니다. 저장소에 남은 토큰 하나, 그리고 고른 날 이후로 아무도 갱신하지 않은 의존성 하나입니다.
자주 묻는 질문
왜 패키지를 설치하는 순간이 위험한가요? 패키지 매니저가 설치 과정에서 스크립트를 실행하도록 허용하고, 그 스크립트는 설치를 실행한 사람의 권한으로 돌아가기 때문입니다. 개발자 장비라면 그 사람의 자격 증명이고, 빌드 파이프라인이라면 배포 키입니다. 해당 코드가 여러분의 애플리케이션에서 호출되지 않아도 피해를 입힐 수 있습니다.
의존성 혼동(dependency confusion)이란 무엇인가요? 여러분의 내부 패키지 이름으로 공개 패키지가 배포되고, 잘못 설정된 리졸버가 사설 레지스트리보다 공개 레지스트리를 우선하는 공격입니다. 누군가 여러분만 노려야 성립하는 것이 아니며, 리졸버 설정을 바로잡는 것만으로 전적으로 막을 수 있습니다.
SBOM은 실제로 무엇을 주나요? 단 하나의 질문에 대한 빠른 답을 줍니다. 우리도 영향을 받는가? 최신 목록이 있으면 몇 분이면 되고, 없으면 일주일을 찾는 데 씁니다. 나열된 취약점이 여러분의 코드에서 도달 가능한지, 이미 침해가 일어났는지는 알려주지 않으므로, 만들어서 보관만 해 둔 SBOM은 통제가 아니라 문서에 그칩니다.
락파일을 저장소에 커밋해야 하나요? 네, 그리고 락파일과 내용이 맞지 않을 때 갱신해 버리는 명령이 아니라 실패로 멈추는 명령으로 엄격하게 설치하십시오. 매니페스트에서 설치하면 빌드 시점에 새 버전이 다시 해석되어 빌드가 재현 불가능해지고, 상위 패키지의 변경이 아무 검토 없이 운영 환경까지 도달합니다.
소규모 팀은 어디에서 시작해야 하나요? 저장소에서 시크릿을 빼내고 노출된 것은 전부 교체하고, 락파일을 커밋해 엄격하게 설치하고, 의존성 알림을 켜서 주 단위로 분류하고, 빌드 도구를 불변 참조에 고정하고, 파이프라인 권한을 줄인 다음, 릴리스마다 SBOM을 생성하십시오. 각 단계는 몇 주가 아니라 몇 시간 단위로 끝납니다.
댓글