1️⃣ UNION 연산자 기본 구조·문법
SQL에서 UNION은 두 개 이상의 SELECT 결과를 “세로로 합치는” 연산자입니다.
이렇게 하면:
-
첫 번째 SELECT 결과
-
두 번째 SELECT 결과
이 둘이 위아래로 합쳐져서 하나의 결과셋으로 반환됩니다.
✅ UNION이 성립하려면 반드시 지켜야 할 조건
-
SELECT 절의 컬럼 개수가 동일해야 합니다.
-
위·아래 SELECT 모두 컬럼 수가 같아야 합니다.
-
-
각 컬럼의 타입이 호환되어야 합니다.
-
예: 첫 번째 SELECT의 1번 컬럼이 문자열이면,
두 번째 SELECT의 1번 컬럼도 문자열 계열이어야 안전하게 나옵니다.
-
그래서 공격자들은 보통 이렇게 테스트합니다:
-
컬럼 개수만 맞으면 DB가 에러 없이 결과를 합쳐 줍니다.
-
타입 확인이 필요할 때는
"a",1,NULL등을 섞어 씁니다.
2️⃣ UNION SQL 인젝션의 구조 (어디에 끼어드는가)
취약한 코드의 전형적인 예를 보시면 구조가 더 잘 보입니다.
🔹 (1) 취약한 쿼리 예시
예를 들어 게시판 글 목록을 가져오는 코드가 있다고 하겠습니다.
정상적인 입력일 때 DB에 보내지는 쿼리:
여기서 id는 원래 숫자나 단순 문자열 데이터여야 합니다.
🔹 (2) 공격자가 UNION을 끼워 넣는 구조
공격자가 파라미터에 이런 값을 넣으면:
서버가 문자열로 쿼리를 만들면 최종 SQL은 이렇게 됩니다:
-
--뒤는 주석이라 무시됩니다. -
결과적으로 DB 입장에서는:
“board에서 (title, content) 가져온 결과 + users에서 (username, password) 가져온 결과를 합쳐서 반환하라”
라는 완전히 정상적인 SQL 문법이 됩니다.
그리고 이 결과를 웹 페이지에서 출력할 때,
title 자리에 username이, content 자리에 password가
그냥 HTML로 출력되는 상황이 발생합니다.
이게 바로 UNION 기반 SQL 인젝션의 핵심 구조입니다.
3️⃣ UNION 인젝션이 실제로 일어나는 과정 (공격 단계)
공격자는 보통 다음과 같은 순서로 UNION 인젝션을 진행합니다.
🔹 1단계: 인젝션이 되는 파라미터 찾기
예: id=1, id=2 이런 값들을 넣어보다가
id=1' 처럼 '를 붙여 에러를 유도합니다.
에러 메시지 예:
You have an error in your SQL syntax...
이런 에러가 뜨면
“아, 이 파라미터는 SQL로 바로 들어가는구나” 라고 판단합니다.
🔹 2단계: 컬럼 개수 맞추기 (ORDER BY 또는 UNION NULL 테스트)
UNION을 쓰려면 컬럼 개수를 알아야 합니다.
-
ORDER BY로 테스트:
어느 숫자에서 에러가 나는지 보면서
컬럼이 몇 개인지 유추합니다.
-
UNION SELECT NULL...테스트:
어느 개수에서 에러가 사라지는지 보고
그 수가 원래 쿼리의 컬럼 개수입니다.
🔹 3단계: 화면에 실제로 보이는 컬럼 찾기
UNION을 해도,
결국 “화면에 출력되는 컬럼”만 공격자에게 의미가 있습니다.
그래서 다음과 같이 테스트합니다:
페이지를 보면:
-
제목 부분에
2가 보인다든지 -
본문 부분에
3이 보인다든지
이런 식으로 어느 컬럼이 화면에 노출되는지를 체크합니다.
🔹 4단계: 중요한 데이터 뽑기
이제 컬럼 개수와 노출되는 컬럼을 알았으니
공격자는 DB의 메타테이블, 계정 테이블 등을 UNION으로 조회합니다.
예시 (MySQL 기준):
-
현재 DB 이름 알아내기
-
테이블 목록 조회 (information_schema.tables)
-
특정 테이블(users)의 컬럼 조회
-
실제 계정 정보 덤프
이런 식으로 원래 페이지가 보여주던 내용 대신, DB 내부 정보가 화면에 노출됩니다.
이게 UNION 기반 인젝션의 실전 공격 흐름입니다.
4️⃣ 왜 UNION SQL 인젝션이 발생하는가? (근본 원인)
결국 이유는 일반적인 SQL 인젝션과 같습니다만,
“쿼리 결과를 화면에 그대로 보여주는 구조” + “UNION 연산자” 때문에 더 위험해지는 유형입니다.
정리해보면:
✔ (1) 동적 쿼리 생성 시 문자열 결합 사용
이렇게 사용자의 입력을 그대로 문자열에 붙이는 방식 때문에
사용자 입력이 “코드”로 해석되는 것이 근본 문제입니다.
✔ (2) 입력값 검증/필터링 부족
-
',",--,#,;,UNION,SELECT등에 대한 필터링 미흡 -
숫자만 받아야 하는데 문자열도 받게 둔 경우
-
길이 제한 없음
이런 것들이 다 인젝션 가능성을 열어 줍니다.
✔ (3) 화면에서 DB 결과를 그대로 출력
UNION 인젝션은 특히,
“DB에서 가져온 결과를 필터 없이 그대로 HTML에 뿌리는 구조”
에서 더 강력합니다.
-
조회 결과가 곧바로 유저에게 보이기 때문에
-
공격자가 UNION으로 붙인 결과도 자연스럽게 노출됩니다.
✔ (4) Prepared Statement(프리페어드 스테이트먼트) 미사용
만약 아래처럼 프리페어드 쿼리를 썼다면:
-
?자리에 들어가는 값은 문자 그대로의 데이터로만 처리되고 -
UNION,--,'등을 넣어도 SQL 코드로 실행되지 않습니다.
즉, 동적 쿼리 + 문자열 결합 + 검증 부족 + 결과 직접 출력
이 네 가지가 합쳐져서 UNION 기반 SQL 인젝션이 발생합니다.
5️⃣ 한 줄 요약
UNION SQL 인젝션은
원래 쿼리 뒤에
UNION SELECT ...를 붙여다른 테이블(예: users, 계정 테이블)에서 가져온 데이터를
기존 페이지의 출력 영역에 함께 노출시키는 공격이며,
동적 쿼리 생성 시 문자열 결합과 입력 검증 부족, 프리페어드 미사용 때문에 발생합니다.