라떼군 이야기
MariaDB/MySQL에서 공백 없는 이중 대시(--)가 SQL 인젝션으로 작동하는 원리 분석
Problem
SQL 인젝션 실습 중, 일반적인 주석 기반 공격(' OR 1=1 -- ) 외에 '--'라는 특이한 입력값으로 로그인이 우회되는 현상이 발견되었습니다. MariaDB와 MySQL 문서에 따르면 이중 대시(--)가 주석으로 처리되려면 반드시 뒤에 공백이 있어야 합니다. 그러나 SELECT * FROM users WHERE ... password=''--'' 형태의 쿼리가 에러 없이 실행되고, 심지어 조건문이 True로 평가되어 인증을 통과하는 원인을 분석해야 합니다.
Background
이 문제를 이해하기 위해서는 MySQL 및 MariaDB의 두 가지 핵심 동작 방식을 알아야 합니다. 첫째, 표준 SQL과 달리 이 데이터베이스들은 -- 뒤에 공백이 없으면 이를 주석이 아닌 빼기(subtraction) 연산자의 연속으로 해석합니다. 둘째, 암시적 형변환(Implicit Type Conversion) 기능이 있어, 숫자 문맥에서 문자열이 사용될 경우 이를 자동으로 숫자로 변환하여 계산을 수행합니다.
Solution
이 현상은 연산자 해석과 자동 형변환이 결합되어 발생합니다. 단계별로 분석해 보겠습니다.
1. 이중 대시(–)의 연산자 해석
공백 없는 --는 ‘빼기’ 연산자 두 개로 파싱됩니다. 즉, A--B는 A - (-B)와 같이 ‘A에서 음수 B를 빼는’ 연산이 됩니다.
-- 문자열 '10'에서 음수 '9'를 빼는 연산으로 해석됨
SELECT '10'--'9';
-- 결과: 19 (10 - (-9) = 19)
2. 빈 문자열의 수치 변환
MySQL에서 빈 문자열 ''을 숫자 문맥에서 사용하면 0으로 변환됩니다. 따라서 입력값 '--'가 포함된 구문은 다음과 같이 계산됩니다.
-- 원본 쿼리의 일부
... password=''--''
-- 1단계: 수치 연산으로 해석 (0 - (-0))
-- 빈 문자열('')은 0으로 변환됨
SELECT ''--'';
-- 결과: 0
3. 최종 비교 구문과 참(True) 평가
이제 WHERE 절은 password = 0과 같은 형태가 됩니다. 여기서 다시 한번 암시적 형변환이 발생합니다. password 컬럼(문자열)을 숫자(0)와 비교하려 하기 때문에, DB는 password 컬럼의 값을 숫자로 변환을 시도합니다.
-- 예시 데이터: password가 'S3cur3'인 경우
-- 문자열 'S3cur3'는 숫자로 변환 시 0이 됨 (유효한 숫자로 시작하지 않으므로)
SELECT 'S3cur3' + 0;
-- 결과: 0
-- 따라서 아래 비교 구문은 참이 됨
SELECT * FROM users WHERE password = 0;
-- 결과: 모든 사용자가 조회됨 (비밀번호가 숫자로 시작하지 않는 경우)
결국 password=''--''는 password = 0으로 평가되고, 대부분의 비밀번호 문자열이 숫자로 변환될 때 0이 되므로 로그인이 우회되는 것입니다.
Deep Dive
이 취약점은 데이터베이스 엔진의 유연한 문법 처리가 보안 구멍이 될 수 있음을 보여주는 전형적인 사례입니다. 특히 숫자로 시작하는 비밀번호(예: 1234pass)를 가진 계정의 경우, 1234로 변환되어 0과 같지 않으므로 이 공격이 통하지 않을 수 있습니다. 이를 방지하기 위한 가장 확실한 방법은 **Prepared Statements(파라미터 바인딩)**를 사용하는 것입니다. 바인딩을 사용하면 입력값이 쿼리 구조가 아닌 순수 데이터로만 처리되므로, 연산자 해석이나 형변환 트릭이 근본적으로 차단됩니다.
Conclusion
'--' 인젝션은 MySQL/MariaDB가 --를 빼기 연산자로 해석하고, 문자열을 숫자로 자동 변환하는 과정에서 발생하는 논리적 허점입니다. 이는 단순한 주석 처리가 아니라 수치 연산과 비교 연산의 결과입니다. 개발자는 이러한 DB 특화 동작을 주의해야 하며, 반드시 ORM이나 Prepared Statement를 사용하여 SQL 인젝션을 예방해야 합니다.