SQL Injection 개념 및 원리
개요
모의해킹 과정에서 배운 SQL Injection의 원리와 논리적 접근 방법을 정리한 학습자료다.
“공격구문 외우고 명령어 외우는 수업이 아니다. 원리를 이해하고 나서 AI한테 질문해서 원하는 답을 얻어내는 게 중요하다.”
“그냥
or 1=1넣는 게 무슨 의미가 있나. 왜 이렇게 되는지 원리를 이해해야 한다.”
1. 웹 아키텍처 기초
1.1 전체 흐름
사용자(브라우저) → 요청(Request) → 웹서버(Static) → WAS(로직처리) → DB
← 응답(Response) ← ← ←
구성 요소:
- 클라이언트: 브라우저 (Chrome, Firefox, Safari 등)
- 웹서버: Apache, Nginx (정적 파일 제공)
- WAS: Tomcat 등 (동적 로직 처리)
- DB: Oracle, MySQL, PostgreSQL 등
1.2 HTTP의 특징
| 특징 | 설명 |
|---|---|
| 1회성 연결 | 요청-응답 후 연결 종료 |
| 상태 저장 안 함 | 서버가 클라이언트 상태를 기억하지 않음 |
| 단방향 통신 | 서버가 일방적으로 클라이언트에 전송 불가 |
상태를 저장하지 않기 때문에 세션(Session)과 쿠키(Cookie) 개념이 등장한다.
- Session: 서버에 저장
- Cookie: 브라우저에 저장
1.3 HTTP Status Code
| 코드 | 의미 | 보안 관점 |
|---|---|---|
| 200 | OK (정상) | - |
| 302 | 주소 이동 | 리다이렉션 확인 필요 |
| 400 | Bad Request (메소드 틀림) | - |
| 404 | Not Found (경로 틀림) | - |
| 500 | Internal Server Error | 개발자가 예외처리 안 한 것 → 공격 포인트! |
500 에러는 “개발자가 예외처리를 제대로 안 해놨다”는 신호다. SQL Injection 시 이 에러가 뜨면 쿼리가 DB까지 전달되고 있다는 증거다.
2. 데이터베이스 기초
2.1 DB와 Excel 비교
| DB 용어 | Excel 대응 | 설명 |
|---|---|---|
| Database | 통합 문서 | 전체 파일 |
| Table | Sheet | 개별 시트 |
| Column | A, B, C, D | 세로 열 |
| Row | 1, 2, 3, 4 | 가로 행 |
2.2 CRUD와 SQL Injection
| 작업 | SQL | 공격 가능? |
|---|---|---|
| Create | INSERT | ❌ |
| Read | SELECT | ✅ 주요 공격 대상 |
| Update | UPDATE | ❌ |
| Delete | DELETE | ❌ |
실무 금지 사항:
INSERT, UPDATE, DELETE에서 공격하면 실제로 DB가 수정된다!
실제 사고 사례: 업데이트 쿼리 잘못 때려서 전체 회원의 비밀번호가 ‘1’로 바뀜. 암호화된 값도 아니라서 어떤 비밀번호로도 로그인 불가.
3. SELECT문의 동작 원리 (핵심!)
3.1 WHERE절의 진짜 의미
SELECT * FROM friends WHERE address = '서울';
일반적인 오해: “서울에 있는 걸 골라서 꺼내줘”
실제 동작 원리:
- 첫 번째 줄 가져옴
address컬럼 값을 조건에 대입'서울' = '서울'→ 참이면 합격, 거짓이면 불합격- 다음 줄로 넘어가서 반복
핵심 이해:
WHERE절은 검색 기능이 아니라 필터링 기능이다!
한 줄씩 가져와서 조건이 참/거짓인지 판단하고, 참인 것만 결과에 포함시킨다.
3.2 왜 이해가 중요한가?
SQL Injection은 이 참/거짓 판단 로직을 조작하는 것이다.
-- 원래 쿼리
SELECT * FROM members WHERE id='입력값' AND pw='입력값';
-- 공격 시
SELECT * FROM members WHERE id='admin' OR '1'='1' AND pw='아무거나';
조건을 항상 참으로 만들면 모든 데이터가 “합격”된다.
4. 논리 연산자 이해
4.1 AND와 OR
| 연산자 | 의미 | 결과 조건 |
|---|---|---|
| AND | ~이고 ~도 | 둘 다 참이어야 참 |
| OR | ~이거나 ~이거나 | 하나라도 참이면 참 |
4.2 연산 순서
AND가 OR보다 먼저 실행된다! (곱하기 > 더하기)
-- 예시: 집이 서울이고 취미가 축구이거나 나이가 27세 이상
WHERE age >= 27 OR (address='서울' AND hobby='축구')
복잡한 조건도 결국:
- AND 먼저 묶기
- OR로 연결
- 각 조건이 참/거짓 판단
4.3 Short-Circuit Evaluation (단락 평가)
- OR에서 하나라도 T가 나오면 → 나머지 평가 안 함 (어차피 참)
- AND에서 하나라도 F가 나오면 → 나머지 평가 안 함 (어차피 거짓)
공격 활용:
-- OR 1=1을 넣으면
WHERE 조건1 AND 조건2 OR 1=1
-- 1=1이 참인 순간, 앞의 조건들은 의미 없음!
4.4 항상 참/거짓 조건
| 용도 | OR 사용 | AND 사용 |
|---|---|---|
| 항상 참 | OR 1=1 ✅ |
AND 1=1 ❌ (있으나 마나) |
| 항상 거짓 | OR 1=2 ❌ (있으나 마나) |
AND 1=2 ✅ |
왜 AND 1=1은 의미가 없나?
-- AND 1=1은 앞 조건에 영향을 주지 않음
WHERE (조건) AND 1=1 -- 조건이 F면 결과도 F
WHERE (조건) -- 결과 동일
5. SQL Injection의 본질
5.1 정의
사용자 입력값이 쿼리문의 일부로 작동하게 만드는 공격
입력창에 입력 → 백엔드 쿼리에 삽입 → DB에서 실행
핵심: 내가 입력한 게 “데이터”가 아니라 “명령어”로 해석되게 만드는 것
5.2 쿼리문 유추의 중요성
“쿼리문 유추가 반드시 되어야 한다. 유추 없이 공격하면 그냥 치트시트 복붙하는 수준밖에 안 된다.”
유추해야 할 것들:
- 검색 방식이
=(Equal)인지LIKE인지 - 컬럼 이름과 순서
- 따옴표 위치
%사용 여부 (LIKE 패턴)
5.3 Equal vs LIKE 검색
-- Equal: 정확히 일치해야 함
WHERE name = '김철수' -- '김'만 치면 안 나옴
-- LIKE: 패턴 매칭
WHERE name LIKE '%김%' -- '김'이 포함된 모든 것
LIKE 패턴 공격 시 주의점:
-- 원래 쿼리가 이렇다면
WHERE dong LIKE '%검색어%'
-- 공격 시 뒤의 %'를 맞춰줘야 함!
삼성동%' OR 'q%'='q -- q%와 q가 매칭되어 항상 참
6. 인증 우회 공격
6.1 기본 원리
일반적인 로그인 쿼리:
SELECT * FROM members WHERE id='입력값' AND pw='입력값';
공격 목표: 특정 계정(예: admin)으로 비밀번호 없이 로그인
6.2 식별과 인증의 분리
| 개념 | 설명 | 예시 |
|---|---|---|
| 식별 | 내가 누구인지 | ID |
| 인증 | 그게 나 맞는지 | Password |
| 인가 | 권한이 뭔지 | 관리자/일반 |
보안 원칙:
실무에서는 식별과 인증을 분리해야 한다!
# 나쁜 예 (동시 처리)
result = SELECT * FROM members WHERE id=? AND pw=?
# 좋은 예 (분리 처리)
user = SELECT * FROM members WHERE id=?
if user.pw == hash(입력pw):
로그인
6.3 공격 구문 분석
목표: admin 계정으로 로그인
입력:
- ID:
admin' OR '1'='1' -- - PW:
아무거나
완성된 쿼리:
SELECT * FROM members
WHERE id='admin' OR '1'='1' --' AND pw='아무거나';
분석:
id='admin'→ admin이 있으면 참OR '1'='1'→ 무조건 참--→ 뒤의 AND pw 조건 주석 처리
6.4 OR vs AND 선택
상황: admin 계정만 딱 하나 가져오고 싶을 때
-- OR '1'='1' 사용 시 문제점
WHERE id='admin' OR '1'='1' AND pw='?'
-- 전체 다 나옴 → 누구로 로그인될지 모름!
-- 해결: 뒤를 거짓으로 만들기
WHERE id='admin' OR '1'='2' AND pw='몰라'
-- '1'='2'가 거짓이므로 뒤 조건 무시, admin만 나옴
실전 팁:
OR 1=1로 전체가 나오면 “누구를 로그인 시킬 건데?”라는 문제 발생.
특정 계정만 원하면 뒤를 거짓으로 만들어서 해당 조건만 살리기.
7. 주석 사용
7.1 DBMS별 주석
| DBMS | 한 줄 주석 | 여러 줄 주석 |
|---|---|---|
| Oracle | -- |
/* */ |
| MySQL | -- (공백 필요) 또는 # |
/* */ |
| SQLite | -- |
/* */ |
7.2 주석을 쓰지 않는 이유
“실무에서 주석을 날리면 뒤에서 무슨 일이 벌어질지 모른다.”
문제점:
- 복잡한 쿼리에서 뒤가 날아가면 에러
- 서브쿼리, 함수 안에서 주석 쓰면 깨짐
- 한 줄 주석은 줄바꿈 있으면 풀림
실력의 차이:
- 초보: 주석으로 뒤를 날림
- 고수: 문법을 깔끔하게 맞춰서 공격
8. Union SQL Injection
8.1 개념
UNION: 두 SELECT 결과를 합쳐주는 연산자
SELECT name, age FROM friends
UNION
SELECT id, pw FROM members;
-- 친구 목록 아래에 회원 정보가 붙음!
8.2 Union 제약사항 (중요!)
| 제약 | 설명 | 확인 방법 |
|---|---|---|
| 컬럼 수 일치 | 앞뒤 SELECT의 컬럼 수 동일 | ORDER BY 또는 직접 NULL 넣기 |
| 자료형 일치 | 대응하는 컬럼끼리 자료형 동일 | Oracle만 엄격, MySQL/SQLite는 유연 |
8.3 컬럼 수 찾기
방법 1: ORDER BY (주석 필요)
검색어' ORDER BY 1 -- → 정상
검색어' ORDER BY 5 -- → 정상
검색어' ORDER BY 6 -- → 에러! → 컬럼 수는 5개
방법 2: UNION SELECT NULL (주석 불필요, 권장)
검색어%' UNION SELECT null,null,null,null,null FROM dual WHERE 'q%'='q
- 에러 없이 데이터 나오면 컬럼 수 맞음
- 하나씩 늘려가며 확인
8.4 자료형 찾기
-- null은 자료형 무관
검색어%' UNION SELECT null,null,null,null,null FROM dual WHERE 'q%'='q
-- 하나씩 문자로 바꿔보기
검색어%' UNION SELECT 'a',null,null,null,null FROM dual WHERE 'q%'='q -- 첫 번째 문자형
검색어%' UNION SELECT 'a','b',null,null,null FROM dual WHERE 'q%'='q -- 두 번째도 문자형
검색어%' UNION SELECT 'a','b',1,null,null FROM dual WHERE 'q%'='q -- 세 번째 숫자형
8.5 공격 순서 (전체 흐름)
1. 쿼리문 유추
└─ 검색 방식 파악 (= vs LIKE)
└─ 입력 위치 파악
2. 공격 포인트 확인
└─ ' 입력 시 에러 발생하는지
3. Union 제약사항 확인
└─ 컬럼 수 확인
└─ 자료형 확인 (Oracle만)
4. 테이블명 탈취
└─ 시스템 테이블 조회
5. 컬럼명 탈취
└─ 컬럼 정보 테이블 조회
6. 데이터 탈취
└─ 실제 개인정보 추출
9. DBMS별 시스템 테이블
9.1 테이블 정보 조회
| DBMS | 테이블 정보 | 비고 |
|---|---|---|
| Oracle | user_tables |
현재 사용자 테이블만 |
| Oracle | all_tables |
접근 가능한 모든 테이블 |
| MySQL | information_schema.tables |
table_schema=database() 필터 권장 |
| SQLite | sqlite_master |
type='table' 필터 필요 |
9.2 컬럼 정보 조회
| DBMS | 컬럼 정보 | 비고 |
|---|---|---|
| Oracle | user_tab_columns |
table_name 조건 필요 |
| MySQL | information_schema.columns |
table_name + table_schema 조건 |
| SQLite | sqlite_master.sql |
CREATE문 파싱 필요 |
9.3 Oracle 예시
-- 테이블 목록
SELECT table_name FROM user_tables;
-- 특정 테이블의 컬럼
SELECT column_name FROM user_tab_columns WHERE table_name = 'MEMBERS';
-- 주의: Oracle은 대문자로 저장됨!
9.4 MySQL 예시
-- 현재 DB의 테이블만
SELECT table_name FROM information_schema.tables
WHERE table_schema = database();
-- 컬럼 정보
SELECT column_name FROM information_schema.columns
WHERE table_name = 'members' AND table_schema = database();
9.5 SQLite 예시
-- 테이블 목록
SELECT name FROM sqlite_master WHERE type = 'table';
-- 컬럼 정보 (CREATE문 확인)
SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'member';
-- 결과: CREATE TABLE member (id, name, password, ...)
10. Error-based SQL Injection
10.1 개념
에러 메시지 안에 공격 쿼리의 결과가 포함되도록 하는 기법
10.2 Oracle 에러 함수
-- CTXSYS.DRITHSX.SN 함수 활용
검색어%' AND CTXSYS.DRITHSX.SN(user,(공격쿼리))='
에러 메시지 예시:
ORA-20000: Oracle Text 오류:
DRG-11701: [결과값] 키워드 사전이 존재하지 않습니다
↑ 여기에 공격 쿼리 결과가 노출됨!
11. LIKE 패턴과 'q%'='q' 트릭
11.1 왜 1=1이 아니라 'q%'='q'인가?
원래 쿼리가 LIKE일 때:
WHERE dong LIKE '%삼성동%'
공격 시 뒤의 %'를 맞춰야 함:
삼성동%' OR 1=1 AND '%'='
-- 결과: WHERE dong LIKE '%삼성동%' OR 1=1 AND '%'='%'
-- '%'='%' 가 되어버림 → 의도와 다름
'q%'='q' 사용:
삼성동%' UNION SELECT ... WHERE 'q%'='q
-- 결과: WHERE dong LIKE '%삼성동%' UNION SELECT ... WHERE 'q%'='q%'
-- 'q%' LIKE 'q%' → 항상 참!
트릭의 원리:
'q%'='q'에서 뒤에 %'가 붙으면 'q%'='q%'가 된다.
LIKE 패턴에서 %는 “0개 이상의 문자”이므로 'q%'는 'q'를 포함해서 매칭된다.
12. Oracle의 특징
12.1 대소문자 처리
-- 소문자로 입력해도 대문자로 저장됨
CREATE TABLE members (...); -- 실제로는 MEMBERS로 저장
-- 조회 시 대문자 사용 필요
WHERE table_name = 'MEMBERS' -- ✅
WHERE table_name = 'members' -- ❌ 결과 없음
12.2 FROM dual 필수
-- MySQL/SQLite
SELECT 'a', 'b', 'c'; -- FROM 생략 가능
-- Oracle
SELECT 'a', 'b', 'c' FROM dual; -- FROM 필수!
12.3 자료형 엄격함
-- MySQL/SQLite: 문자↔숫자 자동 변환
SELECT 'text', 123; -- OK
-- Oracle: 자료형 일치 필수
SELECT 'text', 123; -- 컬럼끼리 자료형 안 맞으면 에러
13. 실무 조언
13.1 도구 의존성 경계
“버프 스위트 없으면 해킹 못 해요?” 이건 “디자이너한테 포토샵 없으면 그림 못 그려요?” 같은 질문이다.
버프 사용법을 아는 사용자가 되지 말고, 원리를 아는 전문가가 되어야 한다.
개발자 도구만으로도:
- Network 탭에서 요청/응답 확인
- 파라미터 구조 파악
- Ajax 요청 분석
13.2 보고서의 중요성
“남는 건 보고서밖에 없다. 아무리 뛰어난 해커여도 보고서를 못 쓰면 실력이 없다고 평가받는다.”
13.3 취약점 진단 vs 모의해킹
| 구분 | 목표 | 접근 |
|---|---|---|
| 취약점 진단 | 취약점 존재 여부 확인 | ' OR 1=1 되면 취약 판정 |
| 모의해킹 | 실제 데이터 탈취까지 | DB 끝까지 털고, 대응방안 제시 |
14. 자격증 관련
- 정보처리기사: 필수. 쌍기사(보안기사 + 정처기) 권장
- 보안기사: 어렵지만 가치 있음 (운 요소 존재)
- 기사 없으면 경력 산정 시 불리
- 회사 다니면서 공부하기 힘드니 지금 따두기
댓글 남기기