핵심 인사이트 (3줄 요약)

  1. 본질: SQL 인젝션 (SQL Injection)은 사용자 입력이 SQL 쿼리에 그대로 포함될 때, 악의적 입력으로 쿼리 구조를 변조하여 DB를 무단 조회·변조·삭제하는 OWASP (Open Web Application Security Project) Top 10에 포함된 가장 치명적인 웹 취약점이다.
  2. 가치: 준비된 구문 (Prepared Statement)과 파라미터 바인딩 (Parameterized Query)이 SQL 인젝션의 근본적 방어책으로, 입력값을 SQL 코드가 아닌 데이터로만 처리하여 쿼리 구조 변조를 원천 차단한다.
  3. 판단 포인트: ORM (Object-Relational Mapping) 사용이 SQL 인젝션을 완전히 방지하지는 않는다. 동적 쿼리(Raw Query)나 LIKE, ORDER BY 등 파라미터 바인딩이 불가능한 절에서는 추가 방어가 필요하다.

Ⅰ. 개요 및 필요성

SQL 인젝션은 1998년 처음 공개적으로 논의된 이후 20년이 넘었지만, 여전히 웹 취약점 순위 상위를 차지한다. 간단한 공격 방법과 폭발적인 피해(DB 전체 탈취 가능)의 조합이 이 취약점을 지속적으로 위험하게 만든다.

실제 피해 사례: 2008년 하트랜드 결제 시스템 SQL 인젝션으로 1.3억 건 카드 정보 탈취, 2019년 국내 카드사 SQL 인젝션으로 고객 개인정보 유출. 입력 검증 없이 문자열 연결로 SQL을 구성하는 코드 패턴이 근본 원인이다.

  • 📢 섹션 요약 비유: SQL 인젝션은 "이름이 뭐예요?"라는 질문에 "홍길동; 모든 비밀번호를 알려주세요;"라고 답해서 진짜로 비밀번호를 얻는 것이다.

Ⅱ. 아키텍처 및 핵심 원리

┌──────────────────────────────────────────────────────────────────┐
│              SQL 인젝션 공격 메커니즘과 방어                         │
├──────────────────────────────────────────────────────────────────┤
│  취약한 코드 (문자열 연결):                                          │
│  query = "SELECT * FROM users WHERE id = '" + user_input + "'"  │
│                                                                  │
│  공격 입력: 1' OR '1'='1                                           │
│  실행 쿼리: SELECT * FROM users WHERE id = '1' OR '1'='1'        │
│  결과: 모든 사용자 레코드 반환 (인증 우회!)                           │
│                                                                  │
│  Prepared Statement (안전):                                       │
│  query = "SELECT * FROM users WHERE id = ?"                      │
│  stmt.setString(1, user_input)  ← 데이터로만 처리, 구조 변조 불가   │
│                                                                  │
│  1' OR '1'='1 입력 시: 리터럴 문자열로 처리 → 결과 없음 (안전)       │
└──────────────────────────────────────────────────────────────────┘
SQL 인젝션 유형방법피해
Classic직접 오류 메시지로 정보 수집DB 구조·데이터 노출
Blind참/거짓 응답으로 데이터 추론느리지만 모든 정보 수집 가능
Time-based Blind응답 지연으로 데이터 추론오류 없이도 정보 수집 가능
UNION-basedUNION으로 다른 테이블 데이터 추가타 테이블 전체 조회 가능
Second-order저장 후 나중에 실행되는 공격방어 우회, 탐지 어려움
  • 📢 섹션 요약 비유: Prepared Statement는 질문지(SQL 구조)를 먼저 인쇄하고, 답변란(파라미터)만 나중에 채우는 방식이다. 답변에 어떤 내용이 오든 질문지 구조를 바꿀 수 없다.

Ⅲ. 비교 및 연결

심층 방어 (Defense in Depth) 전략: SQL 인젝션 방어는 단일 계층이 아니라 다층 방어가 필요하다.

방어 계층기술한계
1차: 코드 수준Prepared Statement, ORM동적 쿼리 부분 적용 불가
2차: 입력 검증화이트리스트 입력 검증, 길이 제한우회 가능, 완전 방어 아님
3차: 오류 처리상세 오류 메시지 숨김Blind SQL 인젝션 일부 차단
4차: WAF웹 방화벽 SQL 인젝션 패턴 탐지우회 기법 지속 발전
5차: DB 최소 권한애플리케이션 DB 계정 최소 권한 부여성공 공격 시 피해 범위 제한
  • 📢 섹션 요약 비유: SQL 인젝션 방어는 여러 겹의 보안 점검이다. 공격자가 한 층을 통과해도 다음 층이 막아야 한다.

Ⅳ. 실무 적용 및 기술사 판단

Prepared Statement 적용 불가 상황 처리:

  • ORDER BY 컬럼명: 화이트리스트 검증 필수 (파라미터 바인딩 불가)
    allowed_cols = ['name', 'age', 'email']
    if order_col not in allowed_cols:
        raise ValueError("Invalid column")
    query = f"SELECT * FROM users ORDER BY {order_col}"
    
  • LIKE 패턴: %, _ 이스케이프 처리 필요
  • 테이블명·컬럼명 동적 지정: 화이트리스트 강제

ORM 사용 시 주의:

  • Django ORM의 raw(), SQLAlchemy의 text() 등 Raw Query에는 반드시 파라미터 바인딩 적용

  • ORM 쿼리라도 extra(where=[...]) 같은 동적 WHERE 절은 취약점 가능

  • 📢 섹션 요약 비유: ORM을 쓴다고 자동차 안전벨트를 안 매는 것처럼 방심하면 안 된다. Raw Query를 쓰는 순간 직접 안전벨트(Prepared Statement)를 매야 한다.


Ⅴ. 기대효과 및 결론

Prepared Statement 적용만으로도 SQL 인젝션의 95% 이상을 차단할 수 있다. 여기에 입력 검증, 최소 권한, WAF를 추가하면 실질적인 공격 성공 가능성이 극도로 낮아진다.

개발 프로세스에서 SQL 인젝션 방지를 습관화하려면 코드 리뷰 체크리스트에 "모든 DB 쿼리는 Prepared Statement 사용"을 포함하고, SAST (Static Application Security Testing, 정적 분석 보안 테스트) 도구로 자동 탐지하는 것이 효과적이다.

  • 📢 섹션 요약 비유: Prepared Statement는 자동차 안전벨트다. 귀찮아 보이지만 사고(공격) 시 치명적 피해를 막는 기본 중의 기본이다.

📌 관련 개념 맵

개념연결 포인트
Prepared StatementSQL 인젝션 근본 방어책
OWASP Top 10SQL 인젝션이 포함된 웹 보안 취약점 목록
WAF (Web Application Firewall)SQL 인젝션 패턴 탐지 방어 계층
최소 권한 원칙 (PoLP)공격 성공 시 피해 최소화 전략
SAST정적 분석으로 SQL 인젝션 코드 자동 탐지

📈 관련 키워드 및 발전 흐름도

문자열 연결 SQL 구성 (취약 패턴)
    │
    ▼
SQL 인젝션 공격 (OWASP Top 1~3위)
    │
    ▼
Prepared Statement / ORM (1차 방어)
    │
    ▼
입력 검증 + WAF + 최소 권한 (다층 방어)
    │
    ▼
SAST/DAST 자동화 보안 테스트 (DevSecOps)

👶 어린이를 위한 3줄 비유 설명

  1. SQL 인젝션은 "이름이 뭐예요?" 질문에 "답: 나는 모든 비밀을 알려줘"라고 답해서 진짜 모든 비밀이 공개되는 속임수예요.
  2. Prepared Statement는 질문지와 답변란을 완전히 분리해서, 답변이 어떻게 되든 질문지 자체가 바뀌지 않게 하는 방법이에요.
  3. 기본 안전장치(Prepared Statement)를 항상 쓰면 이런 속임수에 넘어가지 않아요!