콘텐츠로 바로가기

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 방어 기법, 서브넷 격리 \rightarrow 10-02 Network & Infrastructure Security 영역으로 위임 (본 문서는 '애플리케이션 소스코드 레벨'의 방어에 집중).
  • 컴파일러 최적화 이론: AST를 머신 코드로 내리기 위한 컴파일러 백엔드의 레지스터 할당 기법 \rightarrow 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

Sequence Core Cluster Objective & Description Evidence (BoK)
1 The Mechanics of Linting & AST 정규식을 넘어, 컴퓨터가 내 코드를 나무(AST)로 분해하고 문법적/논리적 쓰레기를 1초 만에 쳐내는 정적 분석의 뼈대를 쥡니다. P1
2 Complexity & The Cognitive Load if문 하나를 추가할 때마다 폭발하는 순환 복잡도의 끔찍한 수학을 이해하고, 기계가 인간의 뇌 용량(인지 복잡도)을 통제하는 방식을 해부합니다. P5
3 SAST vs DAST (Security Shifts Left) 코드만 보고 취약점을 잡는 돋보기(SAST)와, 서버를 띄워놓고 대포를 쏘는(DAST) 보안 스캐닝의 양동 작전을 뜯어봅니다. Industry
4 Blocking the Secrets Leak 소스코드에 무심코 적어둔 비밀번호 하나가 회사를 파산시키는 나비효과를 차단하기 위해, 커밋 방어선에 지뢰 탐지기(Secret Scanner)를 매설합니다. Industry

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용 메서드를 썼네?" 런타임(서버)에 올리지 않고도, 코드를 짜는 텍스트 에디터 창에 빨간 줄을 쫙쫙 그어버리는 기계의 무자비한 통찰력을 해부합니다.
  • Implement: AST 기반 커스텀 Lint Rule 모사. Bad Code: try { risk(); } catch (Exception e) { } (예외를 꿀꺽 삼키고 아무 처리 안 함). AST 파서: CatchBlock(Empty) 노드 탐지 \rightarrow [Error] 예외를 무시하지 마십시오. 최소한 로깅(Log)이 필요합니다. 인간의 눈으론 쉽게 놓치는 '비어있는 괄호'의 공포를 정적 분석기가 완벽히 차단하는 시각화 렌더링.

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;으로 쳐내버려 인지 복잡도를 절반으로 박살 내는 극적인 리팩터링을 뜯어봅니다.
  • 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의 웅장한 사상을 해부합니다.
  • Implement: SAST 데이터 흐름 오염(Taint Analysis) 추적 시뮬레이터. Source (오염원): String input = request.getParameter("name"); \rightarrow Trace: String sql = "SELECT * FROM users WHERE name = " + input; \rightarrow 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 에러를 뿜으며 기계적으로 개발자의 실수를 막아냅니다. 휴먼 에러를 시스템의 철조망으로 옭아매는 가장 단순하고 위대한 보안망을 뜯어봅니다.
  • Implement: Shannon Entropy 기반 무작위 문자열 탐지기 모사. Text 1: String msg = "Hello World!"; \rightarrow 규칙적인 단어, 엔트로피 낮음 (Pass). Text 2: String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"; (JWT 토큰) \rightarrow 대소문자/숫자 무작위 짬뽕, 엔트로피 극도로 높음 (Block). 로컬 환경에서 코드 커밋(Commit)이 실패하고, 개발자가 환호(회사 파산 모면)하는 아이러니한 안전장치 렌더링.

7. Terminology

Term (EN / ko, abbr) 1문장 정의 단계(기본/권장/실무/심화) 역할/맥락 관련 개념 유사/대비/함께 사용 오해 포인트 Evidence(Primary/Secondary/Industry) Flags(core)
Linting (린팅) 스페이스/탭 혼용이나 미사용 변수 같은 문법적, 스타일적 쓰레기를 런타임 전에 텍스트나 AST 수준에서 싹 밀어버려 코드의 외형과 기본기를 통일하는 가장 싼 정적 분석입니다. 기본 코드 포맷팅 강제 및 기초 에러 방어 AST / Prettier / ESLint SAST (정적 보안 스캐닝) 린터는 "안 이쁜 코드"를 잡아내는 것에 그치지 않고, "if문 안에 할당 연산자(=) 씀" 같은 치명적 논리 버그까지 잡아내는 훌륭한 방패임 P1:CS2023 core
Cyclomatic Complexity (순환 복잡도) 함수 안에 분기(if, for, switch)가 하나 생길 때마다 점수를 올려, "이 함수는 수십 갈래의 평행 우주를 가져서 인간의 뇌로는 절대 디버깅할 수 없다"고 경고하는 수학적 복잡도 지표입니다. 권장 코드 유지보수성 및 인지 부하 측정 Cognitive Complexity / Code Smell Cognitive Complexity 순환 복잡도는 1차원적인 분기 개수만 따지므로, 중첩된(Nested) if문이 뇌를 터지게 만드는 '인지적 부하'는 Cognitive Complexity로 따로 보정해야 함 P5:SFIA core
SAST (정적 애플리케이션 보안 테스팅) 서버를 띄우지 않고 텍스트 형태의 소스코드(AST)만 샅샅이 파싱하여, 사용자 입력값이 쿼리로 직행하는(SQL Injection) 위험한 흐름(Taint Analysis)을 예측하는 화이트박스 보안 스캐너입니다. 실무 소스코드 레벨의 취약점 조기(Shift-Left) 발견 DAST / White-box Testing / Shift-Left DAST (동적 테스팅) 코드를 실행하지 않고 예측만 하므로 "방화벽이 막아주는데도 에러라고 우기는" 오탐(False Positive)이 매우 많아 튜닝이 필수적임 Industry core
DAST (동적 애플리케이션 보안 테스팅) 소스코드가 어떻게 생겨 먹었든 신경 안 쓰고(Black-box), 실제 가동 중인 테스트 서버를 향해 해커처럼 XSS나 인젝션 스크립트 대포를 수만 발 쏴보며 진짜 뚫리는지 보는 동적 스캐너입니다. 심화 런타임 환경의 실질적 취약점 및 구성 오류 검증 SAST / Black-box Testing SAST / IAST 배포 파이프라인의 후반부(Right)에 켜진 서버를 상대로 돌리기 때문에, 매우 느리고 버그를 발견해도 고치기 위한 피드백 루프가 긺 Industry core

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)에 매설하는 방어선을 논증할 수 있는가?

Testing & QA

3 / 5