본문으로 건너뛰기
Kreath Archive
TechProjectsBooksAbout
TechProjectsBooksAbout

내비게이션

  • Tech
  • Projects
  • Books
  • About
  • Tags

카테고리

  • AI / ML
  • 웹 개발
  • 프로그래밍
  • 개발 도구

연결

  • GitHub
  • Email
  • RSS
© 2026 Kreath Archive. All rights reserved.Built with Next.js + MDX
홈TechProjectsBooksAbout
//
  1. 홈
  2. 테크
  3. 7장: 보안 취약점 분석과 자동 수정
2026년 3월 17일·AI / ML·

7장: 보안 취약점 분석과 자동 수정

SAST와 LLM을 결합한 보안 취약점 탐지, OWASP Top 10 자동 검출, 취약점 자동 수정 제안과 CI/CD 보안 게이트 구축을 학습합니다.

16분1,115자8개 섹션
code-qualityaillmdevtools
공유
code-analysis7 / 10
12345678910
이전6장: 코드 마이그레이션 자동화다음8장: 아키텍처 분석과 시각화

학습 목표

  • SAST와 LLM의 하이브리드 보안 분석 접근법을 이해합니다
  • OWASP Top 10 취약점을 LLM으로 탐지하는 기법을 학습합니다
  • 취약점 자동 수정 제안과 검증 파이프라인을 구축합니다
  • CI/CD 파이프라인에 보안 게이트를 통합하는 방법을 파악합니다

SAST + LLM 하이브리드 보안 분석

SAST(Static Application Security Testing)정적 애플리케이션 보안 테스트는 소스 코드를 실행하지 않고 보안 취약점을 탐지하는 기법입니다. 전통적인 SAST 도구는 규칙 기반으로 동작하며, 높은 오탐율(false positive)이 가장 큰 문제입니다.

전통 SAST의 한계

문제설명
높은 오탐율실제 위험이 아닌 코드에도 경고 발생 (30-70%)
맥락 무시입력 검증이 다른 레이어에서 수행되는 경우를 인식 못함
비즈니스 로직 취약점인증/인가 논리 결함은 탐지 불가
수정 제안 부재문제를 지적하지만 구체적 수정안은 제공하지 못함

LLM은 이 한계들을 보완합니다. 코드의 맥락을 이해하여 오탐을 줄이고, 수정 코드까지 생성할 수 있습니다.

하이브리드 아키텍처


OWASP Top 10 탐지

OWASP Top 10은 웹 애플리케이션에서 가장 빈번하게 발생하는 보안 위험 10가지입니다. LLM 기반 분석은 이 취약점들을 맥락 인식 방식으로 탐지합니다.

SQL Injection 탐지와 수정

vulnerable_query.py
python
# 취약한 코드: SQL Injection
def get_user(username: str) -> dict | None:
    query = f"SELECT * FROM users WHERE username = '{username}'"
    cursor.execute(query)
    return cursor.fetchone()

전통 SAST는 문자열 포매팅을 사용한 SQL 쿼리를 탐지합니다. LLM은 여기서 한 단계 더 나아가 수정 코드를 생성하고, 호출하는 모든 코드의 영향까지 분석합니다.

secure_query.py
python
# 수정된 코드: 매개변수화된 쿼리
def get_user(username: str) -> dict | None:
    query = "SELECT * FROM users WHERE username = %s"
    cursor.execute(query, (username,))
    return cursor.fetchone()

XSS 탐지와 수정

vulnerable-component.tsx
typescript
// 취약한 코드: Stored XSS
function CommentDisplay({ comment }: { comment: string }) {
  return <div dangerouslySetInnerHTML={{ __html: comment }} />;
}
secure-component.tsx
typescript
// 수정된 코드: 안전한 렌더링
import DOMPurify from "dompurify";
 
function CommentDisplay({ comment }: { comment: string }) {
  const sanitized = DOMPurify.sanitize(comment);
  return <div dangerouslySetInnerHTML={{ __html: sanitized }} />;
}

LLM 기반 보안 분석기 구현

security_analyzer.py
python
from dataclasses import dataclass
from enum import Enum
 
 
class VulnerabilityType(Enum):
    SQL_INJECTION = "A03:2021-Injection"
    XSS = "A03:2021-Injection"
    BROKEN_AUTH = "A07:2021-Authentication"
    SENSITIVE_DATA = "A02:2021-Cryptographic Failures"
    BROKEN_ACCESS = "A01:2021-Broken Access Control"
    SSRF = "A10:2021-SSRF"
    INSECURE_DESERIALIZATION = "A08:2021-Software Integrity"
 
 
class Severity(Enum):
    CRITICAL = "critical"
    HIGH = "high"
    MEDIUM = "medium"
    LOW = "low"
    INFO = "info"
 
 
@dataclass
class Vulnerability:
    vuln_type: VulnerabilityType
    severity: Severity
    file_path: str
    line_number: int
    description: str
    fix_suggestion: str
    fix_code: str | None
    confidence: float
    is_false_positive: bool
 
 
SECURITY_ANALYSIS_PROMPT = """보안 전문가로서 다음 코드를 분석하세요.
 
파일: {filepath}
코드:
---
{code}
---
 
SAST 도구가 탐지한 잠재적 취약점:
{sast_findings}
 
호출 컨텍스트:
{call_context}
 
각 SAST 발견에 대해 다음을 판단하세요:
1. 실제 취약점인지 오탐인지 (이유 포함)
2. 실제 취약점이라면 심각도 (critical/high/medium/low)
3. OWASP 분류
4. 구체적인 수정 코드
5. 확신도 (0.0-1.0)
 
추가로 SAST가 놓친 취약점이 있다면 보고하세요:
- 비즈니스 로직 취약점
- 인증/인가 결함
- 경쟁 조건(race condition)
- 안전하지 않은 기본 설정"""
 
 
class SecurityAnalyzer:
    """SAST + LLM 하이브리드 보안 분석기"""
 
    def __init__(self, sast_scanner, llm_client):
        self.sast_scanner = sast_scanner
        self.llm_client = llm_client
 
    async def analyze(
        self, filepath: str, source: str, call_context: str = ""
    ) -> list[Vulnerability]:
        # 1단계: SAST 스캔
        sast_findings = self.sast_scanner.scan(filepath, source)
 
        # 2단계: LLM 컨텍스트 분석
        prompt = SECURITY_ANALYSIS_PROMPT.format(
            filepath=filepath,
            code=source,
            sast_findings=self._format_findings(sast_findings),
            call_context=call_context,
        )
 
        response = await self.llm_client.generate(prompt)
        vulnerabilities = self._parse_response(response)
 
        # 3단계: 오탐 필터링
        real_vulns = [
            v for v in vulnerabilities
            if not v.is_false_positive and v.confidence > 0.7
        ]
 
        return sorted(
            real_vulns,
            key=lambda v: v.severity.value,
        )
 
    def _format_findings(self, findings: list[dict]) -> str:
        return "\n".join(
            f"- [{f['rule_id']}] {f['message']} (줄 {f['line']})"
            for f in findings
        )
 
    def _parse_response(self, response: str) -> list[Vulnerability]:
        # LLM 응답 파싱 (간략화)
        return []
Info

LLM이 SAST 결과를 필터링하면 오탐율을 30-70%에서 5-10%로 줄일 수 있습니다. 이는 보안 팀의 업무 부담을 극적으로 감소시킵니다. 다만 보안 분야에서는 미탐(false negative)이 더 위험하므로, LLM이 "안전하다"고 판단한 코드도 주기적으로 사람이 검토해야 합니다.


취약점 자동 수정 파이프라인

수정 코드 생성과 검증

취약점을 탐지하는 것만으로는 충분하지 않습니다. 수정 코드를 자동으로 생성하고 검증하는 파이프라인이 필요합니다.

security_fixer.py
python
@dataclass
class SecurityFix:
    vulnerability: Vulnerability
    original_code: str
    fixed_code: str
    explanation: str
    breaking_changes: list[str]
    test_cases: list[str]
 
 
FIX_GENERATION_PROMPT = """다음 보안 취약점을 수정하는 코드를 생성하세요.
 
취약점: {vuln_description}
심각도: {severity}
OWASP 분류: {owasp_category}
 
원본 코드:
---
{original_code}
---
 
규칙:
1. 최소한의 변경으로 취약점을 수정합니다
2. 기존 기능을 유지합니다
3. 새로운 취약점을 도입하지 않습니다
4. 수정 이유를 설명합니다
5. 변경으로 인한 영향(breaking changes)을 나열합니다
6. 수정을 검증하는 테스트 케이스를 제안합니다"""
 
 
class SecurityFixer:
    """보안 취약점 자동 수정기"""
 
    def __init__(self, llm_client):
        self.llm_client = llm_client
 
    async def generate_fix(
        self, vulnerability: Vulnerability, source: str
    ) -> SecurityFix:
        prompt = FIX_GENERATION_PROMPT.format(
            vuln_description=vulnerability.description,
            severity=vulnerability.severity.value,
            owasp_category=vulnerability.vuln_type.value,
            original_code=source,
        )
 
        response = await self.llm_client.generate(prompt)
        parsed = self._parse_fix(response)
 
        # 수정된 코드가 새로운 취약점을 도입하지 않는지 검증
        await self._verify_no_new_vulnerabilities(
            parsed["fixed_code"],
            vulnerability.file_path,
        )
 
        return SecurityFix(
            vulnerability=vulnerability,
            original_code=source,
            fixed_code=parsed["fixed_code"],
            explanation=parsed["explanation"],
            breaking_changes=parsed["breaking_changes"],
            test_cases=parsed["test_cases"],
        )
 
    async def _verify_no_new_vulnerabilities(
        self, fixed_code: str, filepath: str
    ):
        """수정된 코드에 새로운 취약점이 없는지 검증"""
        # SAST 재스캔
        new_findings = self.sast_scanner.scan(filepath, fixed_code)
        if new_findings:
            raise SecurityError(
                "수정된 코드에서 새로운 취약점이 발견되었습니다: "
                + str(new_findings)
            )
 
    def _parse_fix(self, response: str) -> dict:
        return {
            "fixed_code": "",
            "explanation": "",
            "breaking_changes": [],
            "test_cases": [],
        }

코드 리뷰 보안 자동화

PR(Pull Request) 코드 리뷰에 보안 분석을 자동으로 통합할 수 있습니다.

security_reviewer.py
python
@dataclass
class SecurityReviewComment:
    file_path: str
    line_number: int
    severity: str
    comment: str
    suggestion: str | None
 
 
class SecurityReviewer:
    """PR 보안 자동 리뷰"""
 
    def __init__(self, security_analyzer, github_client):
        self.analyzer = security_analyzer
        self.github = github_client
 
    async def review_pr(self, pr_number: int) -> list[SecurityReviewComment]:
        # PR의 변경된 파일 목록 가져오기
        changed_files = await self.github.get_pr_files(pr_number)
        comments = []
 
        for file_info in changed_files:
            if not self._is_code_file(file_info["filename"]):
                continue
 
            # 변경된 코드만 분석
            patch_content = file_info.get("patch", "")
            added_lines = self._extract_added_lines(patch_content)
 
            if not added_lines:
                continue
 
            # 보안 분석 실행
            vulns = await self.analyzer.analyze(
                filepath=file_info["filename"],
                source=added_lines,
            )
 
            for vuln in vulns:
                comments.append(SecurityReviewComment(
                    file_path=vuln.file_path,
                    line_number=vuln.line_number,
                    severity=vuln.severity.value,
                    comment=(
                        f"[{vuln.severity.value.upper()}] "
                        f"{vuln.description}"
                    ),
                    suggestion=vuln.fix_code,
                ))
 
        # GitHub PR에 코멘트 작성
        if comments:
            await self._post_review(pr_number, comments)
 
        return comments
 
    def _is_code_file(self, filename: str) -> bool:
        code_extensions = {
            ".py", ".ts", ".tsx", ".js", ".jsx",
            ".java", ".go", ".rs",
        }
        return any(filename.endswith(ext) for ext in code_extensions)
 
    def _extract_added_lines(self, patch: str) -> str:
        lines = []
        for line in patch.splitlines():
            if line.startswith("+") and not line.startswith("+++"):
                lines.append(line[1:])
        return "\n".join(lines)
 
    async def _post_review(
        self,
        pr_number: int,
        comments: list[SecurityReviewComment],
    ):
        review_body = self._build_review_summary(comments)
        await self.github.create_review(
            pr_number=pr_number,
            body=review_body,
            comments=[
                {
                    "path": c.file_path,
                    "line": c.line_number,
                    "body": f"{c.comment}\n\n제안: {c.suggestion}"
                    if c.suggestion else c.comment,
                }
                for c in comments
            ],
        )
 
    def _build_review_summary(
        self, comments: list[SecurityReviewComment]
    ) -> str:
        critical = sum(1 for c in comments if c.severity == "critical")
        high = sum(1 for c in comments if c.severity == "high")
        medium = sum(1 for c in comments if c.severity == "medium")
 
        return (
            f"보안 분석 결과: "
            f"Critical {critical}건, High {high}건, Medium {medium}건"
        )

CI/CD 보안 게이트

Checkmarx와 Snyk AI 통합

Checkmarx와 Snyk는 AI를 통합한 보안 분석 플랫폼입니다. 이들을 CI/CD 파이프라인에 통합하면 코드가 머지되기 전에 보안을 자동으로 검증할 수 있습니다.

security-gate.yml
yaml
# GitHub Actions 보안 게이트 예시
name: Security Gate
 
on:
  pull_request:
    branches: [main]
 
jobs:
  security-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
 
      - name: SAST 스캔
        uses: checkmarx/ast-github-action@v2
        with:
          project_name: my-project
          cx_tenant: ${{ secrets.CX_TENANT }}
 
      - name: 의존성 취약점 스캔
        uses: snyk/actions/node@master
        with:
          args: --severity-threshold=high
 
      - name: LLM 보안 분석
        run: |
          python scripts/llm_security_review.py \
            --pr-number=${{ github.event.pull_request.number }} \
            --threshold=medium
 
      - name: 보안 게이트 판정
        run: |
          python scripts/security_gate.py \
            --block-on=critical,high \
            --warn-on=medium

보안 게이트 정책

security_gate.py
python
from dataclasses import dataclass
 
 
@dataclass
class GatePolicy:
    block_severities: list[str]
    warn_severities: list[str]
    max_open_vulns: int
    require_fix_plan: bool
 
 
class SecurityGate:
    """CI/CD 보안 게이트"""
 
    def __init__(self, policy: GatePolicy):
        self.policy = policy
 
    def evaluate(self, vulnerabilities: list[dict]) -> dict:
        blocked = [
            v for v in vulnerabilities
            if v["severity"] in self.policy.block_severities
        ]
        warnings = [
            v for v in vulnerabilities
            if v["severity"] in self.policy.warn_severities
        ]
 
        passed = len(blocked) == 0
 
        return {
            "passed": passed,
            "blocked_count": len(blocked),
            "warning_count": len(warnings),
            "message": self._build_message(passed, blocked, warnings),
        }
 
    def _build_message(
        self,
        passed: bool,
        blocked: list[dict],
        warnings: list[dict],
    ) -> str:
        if passed and not warnings:
            return "보안 게이트 통과: 취약점이 발견되지 않았습니다."
 
        parts = []
        if blocked:
            parts.append(
                f"차단: {len(blocked)}건의 심각한 취약점이 발견되었습니다."
            )
        if warnings:
            parts.append(
                f"경고: {len(warnings)}건의 중간 수준 취약점이 있습니다."
            )
 
        return " ".join(parts)
Warning

보안 게이트는 "차단(block)"과 "경고(warn)"를 구분해야 합니다. Critical/High 취약점은 머지를 차단하고, Medium은 경고만 표시하되 추적합니다. 모든 수준을 차단하면 개발 속도가 지나치게 저하되므로, 조직의 보안 성숙도에 맞게 정책을 조정해야 합니다.


정리

SAST와 LLM의 하이브리드 접근은 전통 보안 분석의 높은 오탐율을 극적으로 줄이면서, SAST가 탐지하지 못하는 비즈니스 로직 취약점까지 커버합니다. LLM은 취약점 탐지를 넘어 수정 코드 생성, PR 보안 리뷰 자동화, 그리고 CI/CD 보안 게이트 구축까지 지원합니다.

핵심은 도구의 조합입니다. SAST가 1차 탐지를 수행하고, LLM이 맥락 분석으로 오탐을 필터링하며, 자동화된 검증 파이프라인이 수정의 안전성을 보장합니다. Checkmarx, Snyk 같은 플랫폼이 AI를 통합하면서 이 파이프라인이 더욱 성숙해지고 있습니다.

다음 장 미리보기

8장에서는 코드 분석의 거시적 관점인 아키텍처 분석과 시각화를 다룹니다. 모듈 의존성 분석, 순환 의존성 감지, 레이어 위반 탐지, 마이크로서비스 경계 제안, 그리고 Mermaid/PlantUML을 활용한 아키텍처 다이어그램 자동 생성을 학습합니다.

이 글이 도움이 되셨나요?

관련 주제 더 보기

#code-quality#ai#llm#devtools

관련 글

AI / ML

8장: 아키텍처 분석과 시각화

LLM을 활용한 아키텍처 분석, 순환 의존성 감지, 레이어 위반 탐지, 마이크로서비스 경계 제안과 아키텍처 다이어그램 자동 생성을 학습합니다.

2026년 3월 19일·17분
AI / ML

6장: 코드 마이그레이션 자동화

LLM을 활용한 언어/프레임워크 마이그레이션 자동화를 학습합니다. Java에서 Kotlin, React Class에서 Hooks로의 전환과 의미 보존 검증 기법을 다룹니다.

2026년 3월 15일·16분
AI / ML

9장: CI/CD 통합과 지속적 코드 품질 관리

LLM 기반 코드 분석을 CI/CD 파이프라인에 통합하는 방법을 학습합니다. PR별 자동 분석, 품질 게이트, 기술 부채 대시보드와 GitHub Actions 구축을 다룹니다.

2026년 3월 21일·16분
이전 글6장: 코드 마이그레이션 자동화
다음 글8장: 아키텍처 분석과 시각화

댓글

목차

약 16분 남음
  • 학습 목표
  • SAST + LLM 하이브리드 보안 분석
    • 전통 SAST의 한계
    • 하이브리드 아키텍처
  • OWASP Top 10 탐지
    • SQL Injection 탐지와 수정
    • XSS 탐지와 수정
    • LLM 기반 보안 분석기 구현
  • 취약점 자동 수정 파이프라인
    • 수정 코드 생성과 검증
  • 코드 리뷰 보안 자동화
  • CI/CD 보안 게이트
    • Checkmarx와 Snyk AI 통합
    • 보안 게이트 정책
  • 정리
  • 다음 장 미리보기