의존성 고정의 실제 효과:lockfile이 막는 것과 막지 못하는 것
지나치게 신뢰받는 장치
“저희는 lockfile을 쓰고 있어서 의존성이 고정되어 있습니다.” 이 문장은 보안 심사에서 자주 등장하고, 대개 논의를 끝내는 답으로 취급됩니다.
lockfile은 분명 중요합니다. 하지만 그것이 해결하는 것은 빌드 일관성입니다. 오늘의 빌드와 석 달 뒤의 빌드가 완전히 같은 의존성 트리를 가져오게 하는 것. 거기서 “의존성이 안전하다”까지는 여러 개의 다른 문제가 사이에 놓여 있습니다.
lockfile이 막는 것
버전 표류. lockfile이 없으면 ^1.2.0 같은 시맨틱 버전 범위는 설치할 때마다 최신 호환 버전으로 해석됩니다. 개발자끼리, 또는 개발 환경과 CI가 서로 다른 코드를 받을 수 있다는 뜻입니다. lockfile은 이 불확실성을 제거합니다.
간접 의존성의 예기치 않은 변화. 직접 의존성은 그대로인데 그것의 전이 의존성이 새 버전을 공개한 경우 — lockfile이 없으면 이것이 조용히 빌드에 들어옵니다. 이런 변화는 “어제까지는 잘 되던” 장애의 주요 원인 중 하나입니다.
일부 오염 시나리오. 공격자가 새로운 악성 버전을 공개하는 방식으로 오염시킬 때(가장 흔한 수법 중 하나), 예전 버전에 고정된 프로젝트는 자동으로 영향을 받지 않습니다. 이것이 lockfile이 제공하는 실제 보안 가치입니다. 다만 수동적이고 조건부입니다.
lockfile이 막지 못하는 것
이미 고정되어 들어온 취약점. 가장 직접적인 지점입니다. 고정한 그 버전 자체에 취약점이 있다면, lockfile은 충실하게, 재현 가능하게, 매번 그 취약점을 설치합니다. 고정은 안전과 같은 말이 아니라 일관성과 같은 말입니다. 게다가 lockfile이 있으면 알아차리기가 더 어려워집니다. 버전 변화라는 확인 계기가 사라지기 때문입니다.
도입 시점에 이미 악성이었던 패키지. lockfile이 고정하는 것은 이미 쓰기로 결정한 것입니다. 도입 판단 자체가 틀렸다면 — 타이포스쿼팅 패키지, AI가 만들어낸 존재하지 않는 패키지명 — lockfile은 그 잘못을 굳힐 뿐입니다.
같은 버전 안에서의 내용 교체. 대부분의 생태계는 lockfile에 무결성 해시를 기록합니다(npm의 integrity 필드 등). 이는 변조를 막습니다. 하지만 lockfile이 이미 오염된 환경에서 생성되었거나 해시 자체가 악성 내용으로 계산되었다면 고정은 의미를 잃습니다. 신뢰 사슬의 시작점이 깨끗해야 합니다.
의존성 트리 바깥의 공격면. 빌드 스크립트, CI 설정, 레지스트리 미러, 컴파일러 자체. lockfile은 이들에 전혀 관여하지 않습니다. SolarWinds식 빌드 단계 공격은 의존성 트리를 건드릴 필요조차 없습니다.
낡아가는 것 자체의 리스크. 역설적이게도 lockfile을 잘 쓸수록 새로운 문제가 생깁니다. 의존성이 오래 갱신되지 않아 보안 수정이 도달하지 못하는 것입니다. 고정과 갱신은 양극에서 하나를 고르는 것이 아니라 균형을 잡아야 하는 대상입니다.
함께 필요한 실무
1. 고정과 지속적 스캔은 분리할 수 없습니다.
lockfile은 정확한 의존성 목록을 제공하며, 이는 지속적 취약점 대조에 이상적인 입력입니다. lockfile을 SCA의 스캔 대상으로 삼으면 새 취약점 정보가 도착했을 때 “우리가 영향을 받는가”에 즉시 답할 수 있습니다. 고정의 가치는 모니터링과 결합해야 온전히 실현됩니다. 그렇지 않으면 리스크를 제자리에 굳혀두는 것일 뿐입니다.
2. lockfile 변경을 코드 리뷰에 올립니다.
lockfile의 모든 변경은 의존성 트리가 바뀌었음을 뜻합니다. 이는 빌드 시점의 부산물이 아니라 사람이 보는 명시적 판단이어야 합니다. 리뷰에서 물을 것은 누가 도입했는지, 왜인지, 전이 의존성으로 무엇이 딸려왔는지입니다.
3. 단계별 업데이트 정책.
패치 버전은 자동 갱신(보안 수정은 보통 이 층에 옵니다), 마이너는 테스트 통과 후, 메이저는 반드시 사람이 평가합니다. Dependabot이나 Renovate와 결합하면 업데이트는 연례 대청소가 아니라 일상의 잔걸음이 됩니다.
4. 내부 미러와 무결성 검증.
모든 의존성을 내부 아티팩트 저장소를 거쳐 받고 lockfile의 무결성 해시와 결합하면 “내용이 확정되고 출처가 통제된” 이중 보장이 됩니다. 이는 의존성 혼동 공격에 대한 대응도 겸합니다.
5. 개발 의존성과 런타임 의존성을 구분합니다.
lockfile에는 보통 둘 다 들어 있지만 리스크 성격은 다릅니다. 런타임 의존성은 운영 공격면에 직접 들어가고, 개발 의존성은 빌드 환경에 영향을 줍니다. 갱신 주기와 심사 강도를 나눠 설정하면 한정된 주의를 더 중요한 쪽에 둘 수 있습니다.
기대치를 바르게 맞추기
lockfile은 재현 가능 빌드의 기반이자 의존성 관리의 필요조건입니다. 하지만 충분조건은 아닙니다. 이것을 '보안 도구'가 아니라 '결정성 도구'로 이해하면, 실제로 부족한 부분 — 지속적인 취약점 모니터링, 명시적인 도입 판단, 그리고 빌드 환경 자체의 보호 — 을 자연스럽게 채우러 가게 됩니다.
한 문장으로 정리하면, lockfile은 매번 같은 것이 설치되도록 보장하고, 그것에 문제가 있는지 알려주는 것은 SCA입니다.
---
관련 글: CI 파이프라인에서 SCA 게이트 설정 · npm 악성 패키지의 4가지 은닉 기법 · 오픈소스·SBOM 가이드의 의존성 관리 항목
