Lockfile에 취약점이 숨어 있나요?
lockfile은 저장소에서 가장 정직한 문서입니다. 빌드가 실제로 설치하는 모든 패키지의 정확한 버전을 범위도, "latest"도, 놀라움도 없이 나열합니다. 동시에 조용히 공격 표면의 목록이기도 합니다. 고정된 모든 버전은 고정한 이후로 누군가 구멍을 찾았을지도 모르는 버전입니다. 이 글은 스캐너가 그 목록을 어떻게 답으로 바꾸는지 설명합니다. OSV 데이터베이스가 버전을 알려진 취약점과 대조하는 방식, CISA KEV 플래그가 CVSS 점수보다 중요한 이유, 그리고 "취약점을 찾지 못했습니다"가 코드에 대한 진술이 아니라 데이터베이스에 대한 진술인 이유입니다. 검사는 SBOM 취약점 스캐너에서 직접 실행할 수 있으며, lockfile을 브라우저에서 파싱하고 업로드하지 않습니다.
lockfile이 고정하는 것 — 그리고 그것이 공격 표면인 이유
현대 소프트웨어는 대부분 다른 사람의 코드로 이루어져 있습니다. 일반적인 웹 애플리케이션은 수백 개의 패키지를 가져오고, 그 각각이 더 많은 패키지를 가져옵니다. 웹 프레임워크에 대한 직접 의존성이 선택한 적도 검토한 적도 없는 200개의 전이 패키지가 되는 일은 흔합니다. lockfile은 그 트리의 기록입니다. npm의 package-lock.json, 완전히 고정된 Python의 requirements.txt, Go의 go.mod와 go.sum이 있어 모든 머신에서 매번 같은 트리가 설치되도록 기록되어 있습니다. 이것이 없으면 "내 컴퓨터에서는 되는데"는 사실이 아니라 희망입니다.
바로 그 정확성 때문에 lockfile은 알려진 취약점을 찾기에 적절한 곳입니다. 취약점 데이터베이스는 패키지 이름, 에코시스템, 정확한 버전을 키로 합니다. lodash 4.17.20은 취약하고, lodash 4.17.21은 취약하지 않으며, 그 차이는 한 번의 조회로 알 수 있습니다. 유동적인 범위는 그런 식으로 판단할 수 없습니다. 스캐너는 실제로 설치된 버전을 추측해야 하며, 추측은 보안 관행이 아닙니다. 따라서 lockfile 위생의 첫 번째 규칙은 평범하지만 양보할 수 없습니다. lockfile을 커밋하고, 고정된 상태로 유지하고, 매니페스트의 희망 목록이 아니라 고정된 트리를 스캔하는 것입니다.
OSV가 버전을 알려진 취약점과 대조하는 방식
OSV.dev는 GitHub, NVD, 각 언어 에코시스템의 권고를 하나의 조회 가능한 인덱스로 모은 공개 취약점 데이터베이스입니다. 스캐너는 이름, 에코시스템, 버전의 세 쌍 묶음(lodash, npm, 4.17.20)을 보내고, 그 정확한 버전에 영향을 주는 취약점 ID를 돌려받습니다. 그 ID는 이후 전부 가져옵니다. 요약, 수정 버전이 포함된 영향 범위, CVSS 벡터로 나타낸 심각도, CVE 별칭입니다. 조회에는 프로젝트에 대한 정보가 전혀 포함되지 않습니다. 공개 패키지의 공개 좌표만 전송됩니다.
대조는 의도적으로 단순하며, 그것이 강점입니다. 코드를 읽지도 않고, 취약한 함수를 호출하는지 판단하지도 않으며, 패키지가 어떻게 사용되는지도 신경 쓰지 않습니다. 권고가 4.17.21 이전 버전이 영향을 받는다고 하고 당신이 4.17.20을 고정했다면, 일치합니다. 코드가 취약한 함수에 전혀 닿지 않더라도 말입니다. 그 과잉 보고는 기능입니다. 도달 가능성 분석은 더 어렵고 더 느린 문제이며, 저렴한 질문("이 버전이 알려진 불량 버전인가?")만으로도 3년 전에 업그레이드를 잊은 의존성을 잡아낼 수 있습니다.
스캐너가 볼 수 없는 것
버전 대조 검사에는 단단한 경계가 있으며, 솔직히 말할 가치가 있습니다. 찾을 수 있는 것은 누군가 이미 보고한 취약점 중 데이터베이스가 알고 있는 버전에 대한 것뿐입니다. 어제 발견되어 아직 공개되지 않은 취약점은 보이지 않습니다. 취약하지 않았지만 악성인 패키지(인기 있는 이름의 타이포스쿼트, 손상된 릴리스, 외부로 통신하는 의존성)에는 CVE가 전혀 없으며, 이런 종류의 스캐너는 이를 플래그하지 않습니다. 자신의 코드도 마찬가지입니다. 스캐너는 설치하는 패키지를 판단하지, 작성하는 코드를 판단하지 않습니다.
그래서 "취약점을 찾지 못했습니다"라는 결과는 신중하게 읽어야 합니다. 그 의미는 이 정확한 버전에 대해, 이 데이터베이스에서, 이 시점에, 기록된 것이 없다는 것입니다. 유용한 부정입니다. 새 lockfile의 깨끗한 스캔은 진정으로 좋은 소식입니다. 하지만 증명서는 아닙니다. 스캐너가 볼 수 없는 것에 대한 방어는 다른 도구입니다. 새 의존성이 트리에 들어가기 전에 고정하고 검토하는 것, 새 권고를 분기가 아니라 지속적으로 주시하는 것, 조용하던 패키지의 갑작스러운 새 릴리스를 의심하는 것입니다. 스캐너는 연기 감지기이지 소방대가 아닙니다.
KEV 플래그가 높은 CVSS 점수보다 중요한 이유
CVSS 점수는 가정에 답합니다. 이 취약점이 악용된다면 얼마나 심각할까? CISA의 알려진 악용 취약점(Known Exploited Vulnerabilities) 카탈로그는 사실에 답합니다. 현실 세계에서, 지금 이 순간, 누군가 악용하고 있는가? 두 답은 일상적으로 어긋납니다. 9.8점을 받았지만 아무도 무기화하지 않은 취약점은 다음 계획된 업그레이드까지 기다릴 수 있습니다. 반면 5.3점을 받았지만 KEV 목록에 있고 CISA가 정한 수정 기한이 있는 취약점은 이번 주에 패치해야 합니다. 익스플로잇이 이미 존재하고 이미 사용되고 있기 때문입니다.
그 역전 때문에 스캐너는 KEV 행을 심각도 정렬에 합치지 않고 별도로 배지 표시합니다. 정렬 순서는 무엇이 나쁜지 알려주고, KEV 배지는 무엇이 긴급한지 알려줍니다. 실제 트리아지는 짧습니다. 먼저 KEV 항목에 패치하고, 그다음 공개된 수정 버전이 있는 치명적인 항목에 패치하고, 나머지는 다음 업그레이드 주기에 넣으세요. 이 사이트의 Bulk CVE Triage는 같은 CVE를 악용 맥락에 둡니다. 하나의 배지만으로는 팀에 작업을 정당화하기 어려울 때 KEV 상태, EPSS 확률, CVSS를 함께 보여줍니다.
lockfile을 커밋하고 CI에서 스캔하세요 — 분기에 한 번이 아니라
커밋되지 않은 lockfile은 존재하지 않는 lockfile입니다. 한 개발자의 컴퓨터에만 존재한다면 다른 모든 컴퓨터는 그날 "latest"가 가리키는 것을 설치하고, 스캔한 트리는 배포하는 트리가 아닙니다. 커밋하는 것은 가장 저렴한 공급망 통제입니다. 설치를 재현 가능하게 하고, 스캐너의 답을 모두에게 진실로 만들며, 의존성 업그레이드를 조용한 표류가 아니라 검토 가능한 차이로 바꿉니다.
후반부는 빈도입니다. 취약점은 매일 공개되므로 분기에 한 번의 스캔은 며칠 만에 낡아버리는 스냅샷입니다. 유용한 형태는 lockfile을 건드리는 모든 풀 리퀘스트에서의 스캔에 주기적인 main 브랜치 스캔을 더한 것입니다. 테스트 스위트와 같은 루프이며, 같은 속성을 가집니다. 새 권고가 공개된 그날 녹색 빌드가 빨간색으로 바뀌고, 그때 수정은 버전 올리기이지 사후 검토가 아닙니다. 이 사이트의 브라우저 스캐너는 그 루프의 수동 버전입니다. dependabot 업데이트 후나 릴리스 전에 lockfile을 붙여넣고 배포하려는 트리를 확인하세요.
수정 버전, 호환성 깨짐, 패치할 때와 고정할 때
스캔의 모든 일치 항목에는 수정 버전(취약점이 사라진 첫 번째 릴리스)이 붙거나, 정직한 "공개된 수정 버전 없음" 표시가 붙습니다. 일반적인 경우는 패치 또는 마이너 릴리스이며, 업그레이드는 lockfile의 한 줄 변경입니다. 하지만 수정 버전이 항상 안전하게 적용할 수 있는 버전은 아닙니다. 메이저 버전 점프는 코드가 의존하는 동작을 바꿀 수 있고, 어제 릴리스된 수정은 현실 세계에서 하루밖에 테스트되지 않았습니다. 판단은 다른 의존성 업그레이드와 같습니다. 변경 로그를 읽고, 테스트를 실행하고, 실제로 가져오는 패키지부터 업그레이드하세요.
수정 버전이 없을 때 선택지는 세 가지로 좁혀집니다. 필요하지 않다면 의존성을 제거하거나, 유지보수되는 대안으로 교체하거나, 취약한 코드 경로를 완화하는 것(신뢰할 수 없는 입력을 영향받는 함수에 전달하지 않거나, 권고가 설명하는 검사 뒤에 호출을 두는 것)이며, 권고 업데이트를 주시하세요. 해서는 안 될 일은 취약한 버전을 고정하고 잊어버리는 것입니다. 고정은 결정이며, lockfile이나 이슈 트래커에 이유와 재검토 날짜를 주석으로 남길 가치가 있습니다. 변경 후 다시 스캔하세요. 스캐너는 몇 초면 끝나고, 두 번째 스캔만이 첫 번째 스캔의 결과가 사라졌다는 유일한 증명입니다.