Critical 취약점이 공개되고 권고가 퍼지면, 한 시간도 지나지 않아 누군가 사내 채팅에서 묻습니다. 우리는 영향을 받았나요? 이 질문을 유명하게 만든 것은 Log4Shell입니다. CVE-2021-44228은 Log4j Core 2.0-beta9부터 2.15.0까지에 영향을 주었습니다. 이 라이브러리는 수많은 Java 제품의 종속성 트리 여러 계층 아래에 자리하고 있었고, 대부분의 팀은 그것이 어디에 있는지 힘겹게 찾아내야 했습니다.

질문은 단순해 보입니다. 실제로는 세 가지 질문입니다.

  1. 취약한 구성 요소가 우리가 빌드하거나 출시하는 것에 들어 있는가?
  2. 들어 있다면, 우리 제품에서 악용될 수 있는가?
  3. 언제부터, 어떤 릴리스에 들어 있었는가?

대부분의 프로세스는 앞의 두 질문에 답합니다. 고객, 감사인, 규제 기관이 다음으로 묻는 것은 세 번째 질문이며, 사후에 답하기 가장 어려운 질문이기도 합니다.

1단계: 구성 요소가 있는지 확인하기

기업들은 대개 네 가지 방법 중 하나로 답에 이르며, 대략 성숙도 순서는 다음과 같습니다.

수소문하고 검색하기. 누군가 Slack에 글을 올리고, 엔지니어들이 리포지토리와 잠금 파일에서 패키지 이름을 검색하고, 스프레드시트에 답변을 모읍니다. 지금도 가장 흔한 방법입니다. 느리고, 누가 답하느냐에 좌우되며, 파일에 선언되지 않은 것은 모두 놓칩니다. 종속성의 종속성, 벤더링된 라이브러리, 베이스 이미지, 빌드 중에 설치되는 도구가 그렇습니다.

스캐너 대시보드 확인하기. 종속성 스캐너는 몇 시간 안에 리포지토리별로 CVE를 표시합니다. 더 빠르지만, 스캐너는 오늘 눈앞에 있는 코드, 대개 기본 브랜치에 대해 보고합니다. 고객이 어떤 릴리스를 실행하고 있는지, 또는 석 달 전의 빌드가 실제로 무엇을 가져왔는지는 알려 주지 않습니다.

SBOM 인벤토리 조회하기. 모든 릴리스의 소프트웨어 자재 명세서(SBOM)를 보관하는 팀은 전체를 대상으로 하나의 질문을 던질 수 있습니다. 이 패키지의 영향받는 버전이 들어 있는 제품과 버전은 무엇인가? 리포지토리 안의 소프트웨어만이 아니라 출시한 소프트웨어에 대해 답하는 첫 번째 방법입니다.

지속적으로 대조하기. SBOM을 취약점 데이터와 대조해 모니터링하면, 누군가 묻기 전에 영향받는 제품 목록이 이미 존재합니다. 채팅 스레드가 질문이 아니라 답으로 시작됩니다.

모든 방법의 품질은 인벤토리에 실제로 무엇이 들어 있느냐에 달려 있습니다. 흔한 사각지대는 다음과 같습니다.

  • 전이적 종속성. 취약한 패키지는 직접 추가한 것인 경우가 드뭅니다. 서너 계층 아래에서 들어옵니다.
  • 매니페스트가 선언하지 않는 모든 것. 빌드 스크립트가 설치하는 패키지, npx 도구, Dockerfile 단계, 복원된 캐시, 벤더링된 C 및 C++ 코드입니다.
  • 오래된 릴리스. 더 이상 빌드되지 않는 브랜치는 다시 스캔할 수 없지만, 그 브랜치로 만든 제품은 여전히 현장에서 쓰이고 있을 수 있습니다.

2단계: 중요한지 판단하기

구성 요소가 있더라도 실제 위험이 아닐 수 있으므로, 다음 단계는 분류입니다.

  • 버전과 구성. 버전이 정확히 영향받는 범위에 속하는가? 취약한 기능이 컴파일되어 활성화되어 있는가?
  • 도달 가능성. 코드가 취약한 함수를 호출하기는 하는가?
  • 노출. 구성 요소가 네트워크나 신뢰할 수 없는 입력에서 도달 가능한가, 아니면 빌드 시점에만 쓰이는가?
  • 완화 조치. 익스플로잇을 막는 샌드박스, 네트워크 제한, 구성이 있는가?
  • 악용 신호. CVSS는 심각도를 알려 주고, EPSS는 CVE가 향후 30일 안에 악용될 확률을 추정하며, CISA의 Known Exploited Vulnerabilities 카탈로그는 이미 실제로 악용된 취약점을 나열합니다. 이들을 함께 보고 무엇을 먼저 살펴볼지 정합니다.

3단계: 결정 기록하기

결과는 제품과 버전별로 기록되며, 점점 더 VEX(Vulnerability Exploitability eXchange) 문서 형태로 기록됩니다. CISA의 VEX 최소 요구 사항은 not affected, affected, fixed, under investigation의 네 가지 상태를 정의합니다. "not affected" 문서에는 이유를 밝혀야 합니다. 예를 들어 취약한 코드가 존재하지 않거나 공격자가 도달할 수 없기 때문이라는 식입니다.

그 기록은 이후의 모든 일에 쓰입니다. 수정과 수정을 담은 릴리스, 고객을 위한 보안 권고, 규제 기관이 기대하는 모든 보고서입니다. 예를 들어 EU Cyber Resilience Act에 따라 제조사는 자사 제품에서 실제로 악용되고 있는 취약점을 인지한 후 24시간 안에 조기 경보를 보내야 합니다.

4단계: 노출 기간 산정하기

"우리는 영향을 받았는가?"에는 흔히 건너뛰는 후반부가 있습니다. 얼마나 오랫동안 영향을 받았는가?

취약점은 CVE가 게시되기 훨씬 전부터 존재했습니다. Log4Shell은 누군가 공개하기 몇 년 전에 나온 2.0-beta9부터 Log4j에 있었습니다. 여러분의 노출은 빌드가 취약한 버전을 처음 가져온 날 시작되었고, 그 버전이 들어 있는 마지막 빌드가 교체된 날 끝났습니다. 그 기간을 알아야 다음을 할 수 있습니다.

  • 최신 릴리스만이 아니라 고객이 실행하는 릴리스 중 어느 것이 영향을 받는지 알릴 수 있습니다
  • 취약점이 악용되었을 가능성이 있다면 사고 조사의 범위를 올바른 기간으로 정할 수 있습니다
  • 문제가 언제 제품에 들어왔고 수정이 언제 출시되었는지 감사인이나 규제 기관에 보여 줄 수 있습니다

오늘의 코드를 스캔해서는 이를 알 수 없습니다. 현재 잠금 파일은 리포지토리가 지금 원하는 것을 말할 뿐, 과거의 각 빌드가 무엇을 설치했는지는 말해 주지 않습니다. 신뢰할 수 있는 유일한 출처는 빌드가 실행되는 동안 만들어져 이후에도 보관되는 모든 빌드의 기록입니다.

CRACI의 답

CRACI는 GitHub Actions 작업을 CRACI 러너에서 실행하고, 스크립트가 설치하거나 캐시에서 복원된 패키지를 포함해 각 빌드가 실제로 가져오는 직접 및 전이적 패키지를 모두 기록합니다. 각 빌드의 SBOM이 보관되므로, CVE가 게시될 때 기록은 이미 준비되어 있습니다.

새 CVE가 나오면 답은 이미 있습니다. 과거의 모든 빌드와 그 SBOM, 그중 어느 빌드에 취약한 종속성이 직접 또는 전이적으로 들어 있었는지, 그리고 영향을 받은 기간입니다. 스프레드시트도, 재스캔도, 잠금 파일로부터의 재구성도 필요 없습니다. 취약점이 처음 들어간 빌드와 그것을 제거한 빌드가 보존 기간이 허용하는 범위까지 노출 기간을 알려 줍니다(기본 180일, Enterprise에서는 사용자 지정 보존 기간).

일단 파악하고 나면, 정책 게이트로 이 CVE가 포함된 빌드를 차단할 수 있으므로 이후의 종속성 업데이트나 복원된 캐시가 취약한 버전을 몰래 릴리스에 다시 들여오는 일이 없습니다.

그때부터 나머지 프로세스는 디딜 기반을 갖게 됩니다.

  • CRACI는 SBOM을 지속적으로 모니터링하므로, 누가 묻지 않아도 새 CVE가 빌드와 대조됩니다.
  • 보안 팀은 발견 사항을 분류해 수정을 담당하는 팀에 보내며, CRACI는 결과를 기록하는 VEX를 지원합니다.
  • CRACI의 인벤토리는 어떤 소프트웨어 버전이 어떤 제품에 배포되었는지 보여 줍니다.
  • CRA와 관련해 CRACI는 조기 경보, 통지, 최종 보고서의 내용을 준비하고, 귀사의 담당자가 Single Reporting Platform을 통해 제출합니다.

답을 알게 되면 고객에게 알리세요. 공급망 공격 후 고객에게 답하는 방법에 첫 공지와 각 결과별 템플릿이 있습니다. 문의가 수백 건씩 들어온다면 PSIRT 확장하기를 참고하세요.

데모를 예약하고 여러분의 리포지토리 하나의 빌드 기록을 확인해 보세요.