Static Analysis & Security Scanning
코드를 실행하지 않고도 잠재적 버그와 보안 취약점을 수리적으로 찾아내는 정적 분석 기법과 하이브리드 스캐닝 물리학을 다루는 학습 노드입니다.
Article
M
Me
hyunyoun's Blog
software-engineering-devopssoftware-engineeringdev-opsqaquality-assurancestatic-analysissecurity-scanningtesting11 min read
1. Overview
정적 분석과 보안 스캐닝(Static Analysis & Security Scanning)은 인간의 눈(Code Review)으로는 절대 잡아낼 수 없는 미세한 메모리 누수, 암호화 키 하드코딩, 무한 루프의 늪을 코드를 실행하지 않고(Static) 기계의 차가운 두뇌로 샅샅이 해부해 내는 자동화된 품질 통제망을 다룹니다.
학습자는 스페이스바와 탭(Tab)이 뒤섞인 쓰레기 코드를 단숨에 포맷팅하고 널 포인터(Null Pointer) 가능성을 경고하는 **린팅(Linting)과 정적 분석(SAST)**의 메커니즘을 뜯어봅니다. 나아가 "이 함수는 if문이 10개나 겹쳐 있어 인간의 뇌로 디버깅이 불가능하다"고 경고하는 **순환 복잡도(Cyclomatic Complexity)**의 수학적 압박을 장악합니다. 마지막으로, AWS 시크릿 키나 DB 비밀번호가 깃허브(GitHub) 공용 저장소로 유출되는 재앙을 막고, 서버를 띄워놓고 밖에서 해커처럼 공격을 퍼붓는 DAST(동적 보안 스캐닝) 역량을 확보합니다.
2. Scope & Boundaries
In-Scope
- Static Analysis (정적 분석): Linting (스타일 규칙), AST(Abstract Syntax Tree) 파싱 기반의 버그 예측, SonarQube 등 코드 품질 지표 스캐닝.
- Code Metrics: Cyclomatic Complexity (순환 복잡도), Cognitive Complexity (인지 복잡도), Code Duplication (중복도).
- SAST vs DAST: 소스코드를 텍스트로 읽고(SAST, Static) 취약점을 잡는 방식과, 런타임에 켜진 서버의 API를 무차별 공격(DAST, Dynamic)하여 취약점을 찾는 방식의 트레이드오프.
- Secret Scanning: 하드코딩된 API Key, Token, Password를 정규식이나 엔트로피 분석으로 커밋 전에 차단하는 파이프라인.
Out-of-Scope
- 네트워크 방화벽 및 인프라 보안: WAF(웹 방화벽) 설정, DDoS 방어 기법, 서브넷 격리 10-02 Network & Infrastructure Security 영역으로 위임 (본 문서는 '애플리케이션 소스코드 레벨'의 방어에 집중).
- 컴파일러 최적화 이론: AST를 머신 코드로 내리기 위한 컴파일러 백엔드의 레지스터 할당 기법 05-02 Compilers & Execution 영역에서 기학습.
Boundaries
- Static Analysis (SAST) vs Dynamic Analysis (DAST): 정적 분석(SAST)은 "건물 설계도"를 보고 "아, 이 얇은 기둥은 지진 나면 부러지겠네"라고 예측(White-box)하는 것입니다. 코드를 실행하지 않으므로 빠르고 초기(Shift-Left)에 잡지만, 오탐(False Positive)이 많습니다. 동적 분석(DAST)은 건물을 일단 다 지어놓고 바깥에서 대포를 쏴보며(Black-box) 뚫리는지 보는 것입니다. 실제 런타임 환경의 취약점을 완벽히 잡지만 느리고 배포 후반부에 쓰인다는, 공략 시점(Phase)의 경계를 명확히 긋습니다.
3. Counterexample
- 시크릿 하드코딩 유출 재앙: 스타트업 신입 개발자가 "AWS 접근 잘 되는지 로컬에서 잠깐 테스트해봐야지"라며 소스코드에
AWS_SECRET_KEY="AKIA..."를 박아놓고 무심코git push를 헸습니다. 정적 스캐너(Secret Scanner)가 파이프라인에 없었습니다. 5초 뒤 전 세계 봇(Bot)들이 깃허브를 긁어갔고, 주말 사이 해커들이 이 키로 최고사양 비트코인 채굴 서버 100대를 띄웠습니다. 월요일 아침 청구서에 5억 원이 찍힌, 끔찍한 Shift-Left 보안의 부재입니다. - 스파게티 괴물의 탄생 (순환 복잡도 무시): 1,000줄짜리 결제 함수 안에
if가 20개,for루프가 5중첩으로 꼬여 있습니다. 정적 분석기(SonarQube)가 "이 함수의 순환 복잡도가 150입니다(기준치 15)"라며 시뻘건 경고를 날렸지만, 개발팀은 "일정 바쁘니까 무시(Ignore)해"라고 덮어뒀습니다. 다음 달, 특정 카드로 결제 시 포인트가 마이너스가 되는 버그가 터졌으나 분기(Branch)가 수만 개로 뻗어나가 아무도 버그 원인을 찾지 못해 시스템을 아예 새로 짜야 했던 기술 부채의 폭발입니다.
4. Prerequisites
- 코드 리뷰 (Basic): 인간이 코드를 검토하는 방식의 한계. (09-01-04 Software Construction)
- 컴파일러 파싱 트리 (Basic): AST(추상 구문 트리)의 개념. (05-02 Compilers)
5. Learning Map
6. Learning Topics
Basic
Core Topic 01: 문법 경찰과 추상 구문 트리 (The Mechanics of Linting & AST)
- Why to Learn: 탭 썼냐 스페이스 썼냐, 변수명 낙타봉(CamelCase)으로 지었냐 뱀(snake_case)으로 지었냐로 인간끼리 감정싸움(Code Review) 하는 낭비를 기계에게 던져버리기 위함입니다.
- What to Learn:
- Concepts: Linting, Code Formatting, AST (Abstract Syntax Tree), Static Analysis (정적 분석).
- Skills: 단순 텍스트 정규식 검색을 넘어,
if (x = 10)처럼 할당 연산자(=)를 비교 연산자(==)로 잘못 쓴 치명적 논리 오류를 AST(트리) 파싱 단계에서 잡아내는 린터(Linter) 규칙 적용하기.
- How to Learn:
- 1단계: 가장 멍청한 논쟁: PR 리뷰에 "여기 들여쓰기 2칸 말고 4칸이요" 따위의 댓글이 달립니다. 린터(ESLint, Prettier)를 도입하면, 소스코드를 저장(
Ctrl+S)하는 순간 기계가 팀의 표준 포맷으로 강제 변환(Formatting)합니다. 인간은 비즈니스 로직만 봅니다. - 2단계: 정규식의 한계: 린터는 코드의 글자만 읽는 게 아닙니다. 코드를 의미 단위의 나무(AST, 추상 구문 트리)로 쪼갭니다.
- 3단계: 논리 오류의 선제 타격: "어? 선언은 해놨는데 한 번도 안 쓴 변수(Dead Code)네?", "어?
String인데Integer용 메서드를 썼네?" 런타임(서버)에 올리지 않고도, 코드를 짜는 텍스트 에디터 창에 빨간 줄을 쫙쫙 그어버리는 기계의 무자비한 통찰력을 해부합니다.
- 1단계: 가장 멍청한 논쟁: PR 리뷰에 "여기 들여쓰기 2칸 말고 4칸이요" 따위의 댓글이 달립니다. 린터(ESLint, Prettier)를 도입하면, 소스코드를 저장(
- Implement: AST 기반 커스텀 Lint Rule 모사.
Bad Code:try { risk(); } catch (Exception e) { }(예외를 꿀꺽 삼키고 아무 처리 안 함).AST 파서: CatchBlock(Empty) 노드 탐지[Error] 예외를 무시하지 마십시오. 최소한 로깅(Log)이 필요합니다.인간의 눈으론 쉽게 놓치는 '비어있는 괄호'의 공포를 정적 분석기가 완벽히 차단하는 시각화 렌더링.
Recommended
Core Topic 02: 두뇌 용량의 한계선, 복잡도 (Complexity & The Cognitive Load)
- Why to Learn: 코드가 돌아가기만 하면 장땡이라는 주니어를 멈추고, 함수 내부의 분기점(Branch) 개수가 유지보수자(인간)를 미치게 만드는 임계점을 수학적으로 증명(SonarQube)하기 위함입니다.
- What to Learn:
- Concepts: Cyclomatic Complexity (순환 복잡도), Cognitive Complexity (인지 복잡도), Code Duplication, SonarQube Quality Gate.
- Skills:
if,for,switch문이 중첩될 때마다 기하급수적으로 늘어나는 복잡도 수치를 계산하고, 임계치(예: 15)를 넘는 함수를 조기 리턴(Early Return)이나 다형성(Polymorphism)으로 쪼개어 복잡도를 5 이하로 떨어뜨리기.
- How to Learn:
- 1단계: 순환 복잡도 (Cyclomatic Complexity): 함수의 기본 점수는 1점입니다.
if문이 1개 추가되면 2점,for문이 1개 추가되면 3점이 됩니다. 점수가 20점이다? 이 함수의 로직이 빠짐없이 도는지 검증(Unit Test)하려면 최소 20개의 테스트 케이스를 짜야 한다는 수학적(Graph Theory) 계산이 나옵니다. - 2단계: 인지 복잡도 (Cognitive Complexity): 인간의 뇌는 멍청합니다. 1차원
if문 10개(순환 복잡도 10)는 읽을 만합니다. 하지만if안에if안에for루프가 중첩(Depth 3)되면, 똑같이 순환 복잡도가 10이어도 인간의 뇌는 스택 메모리가 꽉 차서 터져버립니다. 중첩을 가중치로 때려버리는(Penalty) 더 잔인한 잣대입니다. - 3단계: 가드 클로즈 (Guard Clauses): 중첩된
if (isValid) { if (isAdmin) { doWork(); } }코드를, 맨 앞에서if (!isValid) return;으로 쳐내버려 인지 복잡도를 절반으로 박살 내는 극적인 리팩터링을 뜯어봅니다.
- 1단계: 순환 복잡도 (Cyclomatic Complexity): 함수의 기본 점수는 1점입니다.
- Implement: 복잡도(Complexity) 시각화 엔진 모사.
입력: 5중첩
for/if문.엔진 분석: "Cyclomatic = 25 (테스트 25개 필요), Cognitive = 50 (인간 한계 초과)".조치: 다형성(OCP)과 Early Return 리팩터링 적용. 출력: "Cyclomatic = 5, Cognitive = 3". 복잡도가 낮아질수록 버그 발생률(Defect Rate) 곡선이 급격히 떨어지는 상관관계 차트 렌더링.
Practical
Core Topic 03: 백색 상자와 흑색 상자, SAST vs DAST (Security Shifts Left)
- Why to Learn: 완성된 앱을 배포하기 직전에 해커(모의해킹)를 불러 취약점을 잡으려다 런칭이 3달 지연되는 고통을 버리고, 개발자가 코드를 치는 순간순간(Shift-Left) 보안을 끼워 넣기 위함입니다.
- What to Learn:
- Concepts: SAST (Static Application Security Testing), DAST (Dynamic Application Security Testing), Shift-Left Security, False Positives (오탐지), SQL Injection, XSS.
- Skills: 소스코드의 텍스트(AST)를 까보며 "SQL 쿼리에 문자열 덧셈(+)을 썼으니 인젝션 위험이 있다"고 예측하는 SAST(화이트박스)와, 가동 중인 서버에
' OR 1=1 --같은 공격 페이로드를 쏴보며 진짜 뚫리는지 검증하는 DAST(블랙박스)의 조합 설계하기.
- How to Learn:
- 1단계: SAST (돋보기 들고 텍스트 읽기): 개발자가 코드를
Commit하자마자 CI 봇이 코드를 쫙 훑습니다. "사용자 입력값(Tainted Data)이 정제(Sanitize)되지 않고 DB 쿼리로 바로 들어가는 흐름(Data Flow) 발견!" 코드가 실행되기도 전에(Static) 위험을 잡습니다. 단점은 "사실 방화벽에서 막혀서 안전한데?" 같은 거짓 경보(False Positive)가 너무 많습니다. - 2단계: DAST (대포 쏘기): 테스트 서버에 앱을 띄웁니다. DAST 봇이 크롤러처럼 돌아다니며 모든
input박스에 해킹 스크립트(XSS)를 수천 개 때려 넣습니다(Dynamic). 진짜 팝업이 뜨면(취약점 폭발) 경고를 날립니다. 소스코드가 없어도(Black-box) 외부망 공격을 잡지만, 어딘가 깊숙이 숨겨진 관리자 페이지 같은 곳은 크롤러가 도달하지 못하는 한계를 지닙니다. - 3단계: Shift-Left: 과거엔 배포 직전(Right)에 DAST만 돌렸습니다. 이제는 개발자의 IDE 창(Left)에 SAST를 달아 타이핑하는 순간 빨간 줄을 긋습니다. 보안을 생명주기의 극초반으로 당겨버리는 DevSecOps의 웅장한 사상을 해부합니다.
- 1단계: SAST (돋보기 들고 텍스트 읽기): 개발자가 코드를
- Implement: SAST 데이터 흐름 오염(Taint Analysis) 추적 시뮬레이터.
Source (오염원):String input = request.getParameter("name");Trace:String sql = "SELECT * FROM users WHERE name = " + input;Sink (폭발 지점):db.execute(sql);SAST 엔진이 이 세 줄의 연결 고리를 AST 상에서 찾아내어 "SQL Injection 99% 확정" 판정을 내리고 CI 파이프라인(Build)을 박살 내는(Fail) 흐름 시각화.
Advanced
Core Topic 04: 은밀한 유출 차단, 시크릿 스캐닝 (Blocking the Secrets Leak)
- Why to Learn: 5천만 원짜리 방화벽과 최신 SAST를 다 발라놨는데, 개발자가 깃허브 공용 레포(Public Repo)에 DB 마스터 비밀번호를 올려서 회사가 하루아침에 증발하는 황당한 멸망을 막기 위함입니다.
- What to Learn:
- Concepts: Secret Scanning, Pre-commit Hook, Regular Expressions (정규식), Shannon Entropy (정보 엔트로피), Credential Leak.
- Skills:
git commit명령어를 치는 순간, 로컬 노트북 환경(Pre-commit Hook)에서 파일 텍스트를 정규식(AWS Key 패턴)과 엔트로피(무작위성) 알고리즘으로 검사하여 시크릿 유출을 원천 봉쇄(Block)하기.
- How to Learn:
- 1단계: 기계 봇들의 스캐닝: 깃허브(GitHub)에 AWS 키(
AKIA...)나 Slack 토큰(xoxb...)이 올라가는 순간, 전 세계 해커들의 스크래핑 봇이 1초 만에 이를 채갑니다. "잠깐 올렸다가 5분 뒤에 지워야지"는 안 통합니다. 이미 털렸고, Git의 특성상(불변 히스토리) 과거 커밋 기록을 뜯어보면 영원히 남아있습니다. - 2단계: 정규식과 엔트로피 (탐지 기술): AWS 키는 특정 패턴(
AKIA로 시작하는 20자리)이 정해져 있어 정규식으로 잡기 쉽습니다. 하지만DB_PASS="asdfQWER1234!@"같은 건 어떻게 잡을까요? 시크릿 스캐너는 문자열의 '무작위성(Shannon Entropy)'을 수학적으로 계산합니다. 영단어가 아닌 복잡하고 무작위 한 기호의 조합이 발견되면 "이거 비밀번호 아니야?"라고 의심합니다. - 3단계: Pre-commit 방벽: 커밋이 중앙 서버로 넘어가기 전, 개발자의 로컬 맥북(Pre-commit Hook)에서 스캐너가 먼저 낚아챕니다. 키가 발견되면
Commit Failed에러를 뿜으며 기계적으로 개발자의 실수를 막아냅니다. 휴먼 에러를 시스템의 철조망으로 옭아매는 가장 단순하고 위대한 보안망을 뜯어봅니다.
- 1단계: 기계 봇들의 스캐닝: 깃허브(GitHub)에 AWS 키(
- Implement: Shannon Entropy 기반 무작위 문자열 탐지기 모사.
Text 1:String msg = "Hello World!";규칙적인 단어, 엔트로피 낮음 (Pass).Text 2:String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";(JWT 토큰) 대소문자/숫자 무작위 짬뽕, 엔트로피 극도로 높음 (Block). 로컬 환경에서 코드 커밋(Commit)이 실패하고, 개발자가 환호(회사 파산 모면)하는 아이러니한 안전장치 렌더링.
7. Terminology
8. References
Primary
- [P1] CS2023 - Software Engineering (SE) - Software Verification and Validation (Static Analysis, Security Testing)
- [P5] SFIA - Testing (TEST) - Test execution and automated security scanning
Secondary
- [Clean Code] Robert C. Martin - Complexity and Formatting
- [Secure by Design] Dan Bergh Johnsson - Shifting Security Left
Industry
- [SonarQube Documentation] - Code Complexity and Quality Gates
- [OWASP] - Static Code Analysis (SAST) vs Dynamic Application Security Testing (DAST)
9. Final Checklist
Primary
- 개발자 간의 소모적인 코드 리뷰(Code Review) 시간(예: "들여쓰기 탭 쓰지 마세요")을 줄이고 비즈니스 로직에만 집중하기 위해, Git Commit 훅(Pre-commit)에 린터(Linter)와 포맷터(Formatter)를 강제하는 자동화 파이프라인을 구축할 수 있는가?
- 정적 분석 툴이 코드 텍스트를 추상 구문 트리(AST)로 파싱하여, 선언만 하고 한 번도 호출되지 않은 데드 코드(Dead Code)나 Null 객체 접근(NullPointerException) 가능성을 런타임 이전에 어떻게 짚어내는지 설명할 수 있는가?
Secondary
- 함수 내부의
if/else분기가 20개가 넘어 순환 복잡도(Cyclomatic Complexity)가 기준치를 초과했을 때, 다형성(Polymorphism)이나 조기 리턴(Early Return) 기법을 활용하여 복잡도를 낮추는 리팩터링을 수행할 수 있는가? - 5중첩
for/if문이 순환 복잡도는 5에 불과하지만, 인간의 두뇌 메모리를 꽉 채워버리는 인지 복잡도(Cognitive Complexity) 측면에서는 치명적인 기술 부채임을 구별하고 평가할 수 있는가?
Industry
- 소스코드가 서버에 배포되기 전 화이트박스(White-box) 형태로 취약점을 분석하는 SAST와, 런타임 서버의 API 엔드포인트를 때려보며 블랙박스(Black-box)로 분석하는 DAST를 CI/CD의 어느 단계(Stage)에 각각 배치할지 양동 전략을 설계할 수 있는가?
- 깃허브(GitHub) 공용 저장소에 AWS Secret Key나 DB Password가 하드코딩되어 유출되는 대참사를 막기 위해, 정보 엔트로피(Shannon Entropy)와 정규식을 결합한 시크릿 스캐닝(Secret Scanning) 도구를 로컬 커밋 단계(Shift-Left)에 매설하는 방어선을 논증할 수 있는가?