오픈소스 인사이트
home
오픈소스 기술 동향
home
💡

[오픈소스 보안 대응 전략 1] 정적분석만으로는 부족합니다

정적분석을 성실히 돌리는데 왜 사고는 터질까?

매 커밋마다 정적분석도구를 돌리고, 코드 리뷰도 꼼꼼히 진행했습니다. 보안 체크리스트도 철저히 확인해가며 배포 파이프라인까지 무사히 통과했습니다. 코드에는 SQL 인젝션도, XSS도, 하드코딩된 비밀번호도 없었습니다. 그런데 왜 보안사고는 계속 터질까요?
원인은 의외로 우리 코드 밖에 있습니다. 2021년 12월, 전 세계를 혼란에 빠뜨렸던 Log4Shell 사태를 떠올려 보면 이해가 빠릅니다. 당시 수많은 기업에서 정적분석을 운영하고 있었지만, 동시다발적으로 취약한 컴포넌트 식별과 신속한 대응에 어려움을 겪었습니다. 취약점은 자사 코드가 아닌 의존성 트리 깊숙한 곳에 숨어 있던 Log4j, 오픈소스 컴포넌트에 있었기 때문입니다. 정적분석을 잘못한게 아니라 애초에 바라보는 범위가 달랐던 것입니다.
이제 소프트웨어 개발은 더 이상 직접 작성한 코드가 중심이 아닙니다. 패키지 매니저, 프레임워크 등 오픈소스와 서드파티 컴포넌트를 조합해 빠르게 만드는 '조립형 구조'로 전환되었습니다.
그래서 질문은 이렇게 바뀝니다. “애플리케이션의 대부분을 차지하는, 우리가 작성하지 않은 코드는 누가 보고 있으며 어떻게 관리되고 있는가?” 이 글에서는 정적분석의 역할과 구조적 한계를 짚어보고, 이를 보완하는 현실적인 접근법을 살펴보겠습니다.

코드 구성의 역전이 바꾼 보안의 중심축

통계에 따르면 현대 애플리케이션 코드베이스의 약 70-90% 이상이 오픈소스와 서드파티 컴포넌트로 구성되며, 개발자가 직접 작성하는 코드는 전체의 10-20%에 불과합니다.
<2025 오픈소스 보안 및 위험분석 보고서, 블랙덕>
이 변화가 의미하는 바는 단순히 “남의 코드가 많아졌다”가 아니라 보안의 중심축도 함께 이동했다는 것입니다. 예전에는 “우리 코드에 버그가 있는가?”가 핵심이었다면, 지금은 "우리가 가져다 쓴 코드는 안전한가?"라는 질문에도 답해야 합니다.
자동차에 비유하면 이렇습니다. 과거에는 자사에서 엔진부터 타이어까지 모두 만들었기에, 자체 품질 검수만 하면 됐습니다. 하지만 지금은 80%의 부품을 외부에서 조달합니다. 아무리 우리가 만든 20%가 완벽해도, 외부 공급업체가 제공한 브레이크에 결함이 있다면 사고는 필연적입니다.
소프트웨어 품질검사도 마찬가지입니다. 많은 기업들이 정적분석 도구로 자사 코드는 철저히 검수하지만, 외부에서 유입되는 오픈소스는 막연히 신뢰하며 사용하고 있습니다.

정적분석이 잘하는 것과 못하는 것

정적분석(SAST, Static Application Security Testing)은 애플리케이션을 실행하지 않은 상태에서 소스코드 또는 바이트코드/바이너리를 분석해, 취약한 패턴과 흐름을 찾아내는 정적 분석 기법입니다. 소스 코드를 읽어 추상 구문 트리를 만들고 미리 정의된 규칙(룰셋)과 패턴 매칭을 기반으로 위험 신호를 찾으며, 제어 흐름(Control Flow)과 데이터 흐름(Data Flow)을 분석합니다. 또한 사용자 입력이 검증없이 위험한 지점으로 전달되는지(Taint Analysis)도 추적합니다.
이 메커니즘은 “개발자가 작성한 코드 내부의 취약 패턴 탐지에 강합니다. SQL 인젝션, XSS, 취약한 인증/인가, 하드코딩된 비밀정보, 위험한 암호화 사용처럼 코드 레벨에서 드러나는 잠재적 결함을 개발단계에서 미리 잡을 수 있습니다. 그래서 정적분석도구는 여전히 ‘자사 코드 보안’의 핵심 도구라고 할 수 있습니다.
하지만 오픈소스 중심의 개발 환경에서는 구조적인 사각지대가 존재합니다. 핵심은 '문맥(Context)의 부재'입니다. 정적분석은 코드의 동작 방식을 분석하지만, 그 코드가 무엇이며 어디서 왔는지는 알기 어렵습니다. 예를 들어 import org.apache.commons.io.FileUtils; 라는 구문을 만나도, 외부 라이브러리를 호출한다는 사실만 알 뿐, 어느 저장소에서 다운로드 되었는지, 어떤 버전(2.6인지 2.8인지)인지, 어떤 라이선스(Apache 2.0인지 GPL인지)를 가졌는지, 알려진 취약점(CVE)이 있는지 등의 정보는 소스코드만으로 판단하기 어렵습니다. 결과적으로 외부에서 가져다 쓴 오픈소스 영역이 정적분석의 사각지대에 놓이게 됩니다.

정적분석의 사각지대를 만드는 현실적인 시나리오 3가지

이번 챕터에서는 실무에서 마주치는 전형적인 3가지 상황을 통해 정적분석만으로는 보안 위협에 대응하기 어려운 구조적 한계를 살펴보겠습니다.
<시나리오 1: “내가 선언하지 않은 라이브러리의 배신”>
개발팀이 Spring 기반 서비스에 로깅과 모니터링을 붙이기 위해 익숙한 스타터를 추가합니다. 코드에 단순히 logger.info()를 호출하였습니다. 정적분석 보고서는 깔끔합니다. 입력값 검증 누락, 위험 함수 호출, 하드코딩 된 비밀정보 모두 문제 없습니다.
그런데 배포 직후 문제가 시작됩니다. 외부 문자열이 로그로 남는 평범한 흐름이, 특정 라이브러리의 취약한 기능을 건드리면서 원격 코드 실행으로 이어집니다. 이 대표적인 예가 바로 2021년 Log4Shell 사태(CVE-2021-44228)입니다. 이 때 개발자는 “그 라이브러리를 직접 선언한 적이 없다”는 사실입니다.
애플리케이션은 직접 의존성 한두 개로 끝나지 않습니다. 의존성 A가 B를, B가 C를 끌어오는 방식으로 트리가 깊어집니다. 문제의 취약점이 바로 그 ‘깊은 곳’에 숨어 있으면, 소스코드 레벨의 정적분석은 구조적으로 여기까지 시야가 닿지 않습니다.
프로젝트
└─ spring-boot-starter-web (직접 선언)
└─ spring-boot-starter-logging (간접)
└─ log4j-to-slf4j (간접)
└─ log4j-api 2.14.1 (간접)
<시나리오 2: “어제는 정상, 오늘은 취약?”>
개발팀은 매일 아침 CI/CD 파이프라인으로 빌드합니다. 월요일 빌드는 문제없이 통과했고 배포도 성공했습니다. 그런데 수요일 아침, 똑같은 코드로 빌드했는데 갑자기 취약점이 경고가 떴습니다. 분명 코드 한 줄 안 바꿨는데 왜 이런 일이 생길까요? 이러한 이유는 다음과 같습니다.
월요일: example-lib 2.3.0 사용 중. 당시 공개된 취약점 정보가 없어 “정상” 판정.
화요일 밤: 외부에서 해당 라이브러리의 취약점이 발견됨(아직 비공개 또는 검증 단계).
수요일 오전: 취약점이 공개되고(CVE 등록), 보안 DB가 업데이트됨.
수요일 오전: 우리 시스템은 변화가 없는데도, “example-lib 2.3.0 취약” 경고가 새로 발생.
정적분석은 이와 같은 시간의 변화에 본질적으로 둔감합니다. 정적분석도구는 코드의 문법 구조와 흐름을 분석하는 도구이기에, 빌드 시점에 실제로 설치된 정확한 버전과 그 버전에 새로 맵핑된 취약점 정보를 연결해 지속적으로 추적하는 역할과는 거리가 있습니다.
<시나리오 3: “제가 만든게 아니라서…”>
정적분석 리포트에 드디어 외부 라이브러리 관련 경고가 하나 떴습니다. "commons-io 2.6 버전에서 취약점 발견." 개발자는 이슈 트래커에 티켓을 생성하고, '수정안함' 태그를 붙입니다. 실무에서 오픈소스의 보안취약점에 대해 개발자들이 보이는 전형적인 반응입니다.
"고치려면 라이브러리 전체를 이해해야 하는데 시간이 없어요."
“내가 작성한 코드가 아닙니다.”
“오픈소스 고치면 공개해야 하잖아요. 귀찮아요”
"코딩 컨벤션도 다르고 난독화까지 되어 있어, 손대기 싫어요.”
이러한 반응은 게으름이라기보다 오너십과 비용의 문제에 가깝습니다. 외부 컴포넌트 취약점은 ‘발견’과 ‘수정’ 사이가 멉니다. 특히 하위 의존성일수록 누가 책임지고 버전을 올릴지 애매해지고, 당장 장애가 나지 않으면 우선순위에서 밀리기 쉽습니다.

그래서 소프트웨어 구성요소 분석이 필요합니다!

앞 서 살펴본 3가지 시나리오(간접 의존성, 빌드 시점마다 바뀌는 구성 요소, 그리고 수정하기 어려운 외부 코드)의 공통점은 무엇일까요? 모두 정적분석이 "우리가 작성하지 않은 코드"를 다루는데 구조적 한계를 가진다는 점입니다. 이 문제들은 코드 품질을 점검하는 정적분석만으로는 해결할 수 없으며, 오픈소스 구성요소 자체를 식별하고 관리하는 새로운 접근이 필요함을 시사합니다.
이러한 구조적 공백을 메우기 위해 등장한 접근이 소프트웨어 구성요소 분석이며 이를 수행하는것이 바로 SCA(Software Composition Analysis) 도구입니다. 핵심 기능은 우리가 사용 중인 구성요소를 식별하고 지속적으로 추적하는 것입니다.
다양한 스캔 기술(직/간접적 종속성 매니페스트 분석, 파일/스니핏 분석, 바이너리 분석 등)을 활용하여 포괄적인 탐지
소프트웨어 구성품 명세서(SBOM)를 생성
SCA 도구는 구성 요소의 라이선스를 식별하고 알려진 보안취약점 탐지
SDLC 전반에 걸쳐 거버넌스와 정책 시행을 자동화
지속적인 모니터링과 공급망 가시성을 지원
그렇다면 SAST와 SCA는 어떤 관계일까요? 결론부터 말하면 이들은 대체가 아닌 보완 관계입니다. 정적분석도구는 "코드가 안전하게 작성되었는가"에 집중합니다. 입력값이 어디로 흘러가고, 위험한 함수로 도달하는지 추적하며, 비즈니스 로직의 결함을 드러내는데 강합니다. 반면 SCA는 "무엇을 사용하고 있으며, 그것이 안전한가"에 답합니다. 컴포넌트의 신원과 버전, 알려진 취약점과 라이선스를 다룹니다.
건축에 비유하자면 정적분석도구는 "건물 구조가 튼튼하게 설계되었는지" 확인하는 감리 역할이라면, SCA 도구는 "사용된 철근과 시멘트가 불량품은 아닌지" 확인하는 자재 검수 역할입니다. 직접 짠 코드의 결함(SQL 인젝션 등)은 정적분석도구로, 가져다 쓴 외부 라이브러리의 결함(CVE)은 SCA로 대응할 때, 비로소 현대 개발환경에 적합한 보안 체계를 구성할 수 있습니다.

SCA 도입시 알아두면 좋은 솔루션 유형별 특징

SCA가 필요하다는 건 이제 명확해졌습니다. 현실적인 고민으로 어떤 도구를 도입해야 효과가 날까?인데, 시장에는 다양한 SCA 솔루션이 존재하고, 각각 강조하는 기능도 다릅니다.
도입에 앞서 알아두면 유용한 SCA 도구의 주요 유형과 특징을 살펴보면 다음과 같습니다.

다음화 예고

지금까지 현대 소프트웨어 개발에서 정적분석도구의 포지션과 구조적 한계와 이를 보완하기 위한 SCA 도구의 필요성을 살펴봤습니다. 그렇다면 성능 좋은 SCA 도구를 도입해서 전체 프로젝트를 스캔하면 모든 보안 문제가 해결될까요? 현실은 그렇지 않습니다. SCA를 처음 도입한 조직이 마주하는 첫번째 감정은 '안도감'이 아니라 압도감입니다. 첫 스캔을 돌리는 순간, 수백에서 수천 개의 보안취약점이 알람이 홍수처럼 쏟아지기 때문입니다.
Critical 500개, High 2,000개... "도대체 뭐부터 고쳐야 하지?, 이거 다 고치려면 개발은 언제 하나?"
SCA 도구 도입은 새로운 문제의 시작입니다. 너무 많은 알람 속에서 진짜 위험한 놈을 어떻게 골라낼것인가? 다음 2부에서는 이러한 '경보 피로(Alert Fatigue)' 문제를 해결하고, 현실적인 우선순위를 수립하는 방법에 대해 이야기해 보겠습니다.
References:
https://apiiro.com/glossary/static-application-security-testing/
http://fossa.com/blog/sca-vs-sast-comparing-security-tools/
https://snyk.io/articles/application-security/sast-vs-sca-testing/
https://licens.io/2022/04/05/sca-supply-chain-issues/#:~:text=Image%3A%20java
전재웅 프로
오픈소스 거버넌스 전문 컨설턴트로서, 삼성 그룹 계열사를 비롯한 국내 주요 기업들의 오픈소스 관리 체계 구축 프로젝트를 다수 수행하고 있습니다.