빌드는 초록불이었는데 그 라이브러리는 누가 넣었나 · 빨간 줄 여섯 개 중 오늘 고칠 수 있는 것 · 이론
빨간 줄 여섯 개 중 오늘 고칠 수 있는 것
한 줄 요약
스캔 결과를 쓸모 있게 만드는 것은 심각도가 아니라 두 가지 판정입니다 — 이 버전이
정말 그 구간에 들어가는가, 그리고 고칠 판이 있는가.
왜 이게 필요했나
취약점 스캐너를 처음 돌리면 빨간 줄이 수백 개 나옵니다. 그 목록을 그대로 개발팀에
보내면 아무 일도 일어나지 않습니다. 다 고칠 수 없다는 것을 보내는 사람도 받는 사람도
알기 때문입니다. 그러면 목록은 첨부 파일로 남고, 다음 달에 다시 한 번 만들어지고,
또 아무 일도 일어나지 않습니다.
줄어드는 자리는 두 곳뿐입니다. 첫째는 오탐입니다. 이미 고쳐진 버전을 쓰고 있는데도
걸려 나오면, 한두 건만 섞여도 목록 전체의 신뢰가 무너집니다. "저번에도 아니라고 했잖아요"
가 한 번 나오면 그다음부터는 아무도 열어 보지 않습니다. 둘째는 고칠 판이 있는지
입니다. 올릴 판이 나와 있으면 오늘 올리면 되는 일이고, 아직 없으면 완화책과 기한을
적어 두고 지켜보는 일입니다. 이 둘은 성격이 완전히 다른 작업인데, 심각도 하나로만
줄을 세우면 같은 칸에 섞입니다.
어떻게 동작하나
취약점 자료를 기계가 읽을 수 있게 적는 형식이 OSV 스키마입니다. 핵심은 affected
배열이고, 그 안의 ranges 는 버전의 타임라인을 적습니다. 각 events 항목은 넷 중
하나입니다 — introduced(여기서 들어왔다), fixed(여기서 고쳐졌다),last_affected(여기까지는 영향받는 것으로 확인됐다), limit(여기까지만 본다).
문서는 한 이벤트 객체에 종류를 두 개 넣는 것을 명시적으로 금지하고,events 배열에는 introduced 가 적어도 하나 있어야 한다고 적습니다
([OSV 스키마](https://ossf.github.io/osv-schema/)).
여기서 실무자가 자주 틀리는 곳이 셋입니다.
경계 구간은 introduced 이상 fixed 미만이다. fixed 와 같은 버전은 이미 고쳐진 것이라 걸리면 안 된다.last_affected fixed 가 없을 때 쓰는 천장이라 그 값 **자체는 아직 영향받는다.** 경계의 포함 여부가 fixed 와 반대다. 문서는 가능하면 fixed 를 쓰라고 강하게 권한다 — last_affected 는 거짓 음성을 만들 여지가 있다.여러 구간 한 권고에 구간이 둘 이상일 수 있다. 1.x 에서 고쳐지고 2.1 에서 다시 들어온 경우가 그렇다. 첫 구간만 보고 끝내면 판정이 뒤집힌다.그리고 버전 비교 자체가 함정입니다. OSV 의 SEMVER 범위 종류는 선행 v 없는
SemVer 2.0 순서를 따르라고 적고 있는데, 문자열로 비교하면 "1.9.0" 이 "1.10.0" 보다
크다고 나옵니다. 자릿수가 아니라 숫자를 견주어야 합니다. 생태계가 SemVer 를 강제하지
않는 경우를 위해 ECOSYSTEM 종류가 따로 있고, 그때는 정렬 규칙이 생태계마다 다릅니다.
마지막으로 어디에 실려 나가는가 를 갈라야 합니다. CycloneDX 는 구성 요소의scope 로 이것을 표현하고, 실행 시 호출 경로에 닿지 않는 것을 excluded 로 적습니다
([CycloneDX 1.6 JSON](https://cyclonedx.org/docs/1.6/json/)). 같은 심각도라도 배포
산출물에 실리는 것과 빌드 기계에서 끝나는 것은 다른 일입니다.
현장에서 만나는 모습
가장 자주 보는 실패는 면제(waiver)가 만능 열쇠가 되는 것입니다. 처음에는 "지금은
못 고치니 기한을 적고 넘어가자" 로 시작하는데, 몇 달 지나면 고칠 판이 있는 것까지
면제로 넘어갑니다. 그러면 관문은 그날부터 장식입니다. 면제는 고칠 수 없는 것에만
주고, 기한과 담당자와 완화책을 반드시 함께 적어야 그 성질이 유지됩니다.
두 번째는 기준일을 date 로 읽는 것입니다. 면제 만료를 오늘 날짜로 판정하면 어제
통과한 빌드가 오늘 실패합니다. 그 자체는 옳은 동작이지만, 재현이 필요한 검사에서는
기준일을 입력으로 받아야 같은 입력에 같은 답이 나옵니다.
세 번째는 자료가 조용히 낡는 것입니다. 인터넷이 닿지 않는 망에서는 취약점 자료를
사내로 미러해 쓰는데, 미러가 멈춘 것을 알아차리는 장치가 없으면 스캔은 계속 초록불을
냅니다. 걸리는 것이 없어서 초록불인지 자료가 3개월 전 것이어서 초록불인지 구별되지
않습니다. 그래서 자료에 생성 시각을 적어 두고, 관문이 그 시각도 함께 보게 만드는 편이
안전합니다.
그리고 한 가지 더 — 스캐너가 "영향받는다" 고 말한 것과 "악용 가능하다" 는 다릅니다.
결함이 있는 함수를 우리가 한 번도 부르지 않는다면 실제 위험은 낮습니다. 이 구별을
기계가 읽을 수 있게 적는 형식이 VEX 이고, CycloneDX 는 취약점 정보와 그 악용 가능성을
BOM 안에서 함께 표현할 수 있게 해 둡니다
([CycloneDX 개요](https://cyclonedx.org/specification/overview/)). 다만 이 판단은
사람이 코드를 읽어야 나오는 것이라, 목록이 정리되기 전에 손대면 시간만 씁니다.
다음 실습에서 할 것
버전 비교기를 직접 만들어 경계값을 통과시키고, OSV 타임라인대로 대조해 실제로 걸리는
것만 골라 냅니다. 그다음 '고칠 판이 있는가' 와 '사용자에게 닿는가' 두 축으로 갈라
정책 관문을 프로그램으로 적고, 면제가 어디까지 통해야 하는지를 코드로 못박습니다.