OPEN HYPER STEP
← 목록으로 (화이트햇 보안)
SECURITY · 79 / 84
security
CHAPTER 79 / 84
읽기 약 2
FUNCTION

SQL Injection: 공격 원리와 방어


핵심 개념

⚠️ 방어 관점. 사용자 입력이 쿼리에 직접 삽입되는 패턴이 왜 위험한지, 파라미터화 쿼리·ORM·검증 3중 방어로 차단하는 법.

본문

SQL Injection 발생 원리

유형동작 방식탐지 난이도
ClassicUNION SELECT로 다른 테이블 데이터 추출쉬움
Error-basedDB 에러 메시지로 정보 누출쉬움
Time-based BlindSLEEP() 응답 지연으로 추론중간
Boolean Blind조건문 분기로 한 비트씩 추출어려움

취약한 코드 vs 안전한 코드

PYTHON📋 코드 (42줄)
# ⚠️ 이 코드는 교육 목적이며 허가된 환경에서만 사용하세요.
import sqlite3

# ❌ 취약: f-string으로 입력값 직접 삽입
def login_vulnerable(username: str, password: str) -> bool:
    conn = sqlite3.connect('users.db')
    cur = conn.cursor()
    query = f"SELECT * FROM users WHERE username='{username}' AND password='{password}'"
    # 공격 입력: username = "admin' --"  → 패스워드 우회
    cur.execute(query)
    return cur.fetchone() is not None


# ✅ 안전 1: 파라미터화 쿼리 (Prepared Statement)
def login_safe_v1(username: str, password: str) -> bool:
    conn = sqlite3.connect('users.db')
    cur = conn.cursor()
    cur.execute(
        'SELECT * FROM users WHERE username=? AND password=?',
        (username, password),
    )
    return cur.fetchone() is not None


# ✅ 안전 2: ORM (SQLAlchemy)
from sqlalchemy.orm import Session
from sqlalchemy import select

def login_safe_v2(session: Session, username: str, password: str) -> bool:
    stmt = select(User).where(
        User.username == username,
        User.password == password,
    )
    return session.execute(stmt).first() is not None


# ✅ 안전 3: 입력 검증 (정규식 화이트리스트)
import re
USERNAME_RE = re.compile(r'^[a-zA-Z0-9_]{3,20}$')

def validate_username(username: str) -> bool:
    return bool(USERNAME_RE.match(username))

취약점 자가 진단 체크리스트

PYTHON📋 코드 (34줄)
# ⚠️ 이 코드는 본인 소유 코드 점검용입니다.
import ast
from pathlib import Path

class SQLInjectionDetector(ast.NodeVisitor):
    def __init__(self):
        self.warnings = []

    def visit_Call(self, node):
        # cursor.execute(f"...") 또는 cursor.execute("..." + var) 탐지
        if (isinstance(node.func, ast.Attribute)
            and node.func.attr in ('execute', 'executemany')):
            for arg in node.args:
                if isinstance(arg, (ast.JoinedStr, ast.BinOp)):
                    self.warnings.append({
                        'line': node.lineno,
                        'issue': '동적 SQL 문자열 (파라미터화 권장)',
                    })
        self.generic_visit(node)


def scan_file(path: Path):
    tree = ast.parse(path.read_text())
    detector = SQLInjectionDetector()
    detector.visit(tree)
    return detector.warnings


for py in Path('src/').rglob('*.py'):
    warnings = scan_file(py)
    if warnings:
        print(f'{py}:')
        for w in warnings:
            print(f"  L{w['line']} {w['issue']}")

방어 우선순위

  1. 파라미터화 쿼리 — 모든 DB 쿼리에 적용 (가장 효과 큼)
  2. ORM 사용 — Django/SQLAlchemy 등 자동 이스케이프
  3. 입력 검증 — 화이트리스트 정규식
  4. 최소 권한 원칙 — DB 사용자에 SELECT만 허용 (UPDATE/DELETE 분리)
  5. WAF (Web Application Firewall) — Cloudflare 등 추가 방어층

AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude

무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6

내 프로젝트의 DB 쿼리 코드를 보여줄게.
동적 SQL 패턴을 모두 찾아내고
파라미터화·ORM 안전 패턴으로 리팩터링해줘.
ChatGPT

무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro

SQL Injection 공격 시나리오 5가지(Classic/UNION/
Error/Time-based/Boolean Blind)와 각각의 방어 코드 패턴을
실제 예시로 비교해서 설명해줘.
Gemini

무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro

내 코드베이스 전체를 스캔해서 SQL Injection 가능성 있는
모든 위치를 라인 번호와 함께 보고하고
우선순위별 수정 가이드를 만들어줘.
Grok

무료: Grok 4.1 / SuperGrok $30/mo

2026년 SQL Injection 관련 최신 CVE Top 10과
실제 침해 사례 + 방어 트렌드(파라미터화 vs WAF vs ORM)를
솔직히 알려줘.

⭐ 이것만 기억하세요
SQL Injection: 공격 원리와 방어 이 3가지만 확실히 잡으세요
1.SQL Injection의 90%는 "동적 문자열로 쿼리를 만든다"는 단일 원인에서 발생 — 파라미터화로 한 번에 차단
2.ORM 사용 시에도 .raw() / .execute() 직접 호출은 동일 위험 — 모든 동적 SQL은 파라미터로
3.다음 챕터에서 XSS — 백엔드 SQL 방어와 별개로 프런트엔드 출력 인코딩이 필요한 이유 학습


공유하기
진행도 79 / 84