"검색창에 입력한 텍스트가 데이터베이스에 대한 '명령의 일부'가 된다" — 이것이 SQL 인젝션입니다. 동작 원리와 확실하게 막는 방법을 설명합니다(공격 절차 없음).
왜 일어나는가 (메커니즘)
근본 원인은 문자열 이어 붙이기로 SQL을 만드는 것입니다. 입력을 문장에 곧장 섞으면 "값의 경계"를 넘어 명령으로 작동할 수 있습니다.
✗ 문자열 이어 붙이기 (위험)
입력이 문장에 이어 붙여짐 → 입력이 명령의 일부로 읽힐 수 있음
✓ 플레이스홀더 (안전)
값을 ? / $1 자리에 데이터로 넘김 → 항상 값으로 남음
피해는 "그 DB 연결이 할 수 있는 모든 것"입니다. 내부 DB에 닿을 수 있다면, RCE 와 SSRF 와 나란히 대규모 유출의 고전적 입구입니다.
방어
플레이스홀더 / 프리페어드 스테이트먼트 사용 (가장 중요)
이어 붙이기로 SQL을 만들지 마세요. 값을 ? / 이름 있는 파라미터로 '데이터'로 넘기세요. 이것만으로 이 부류 전체가 거의 사라집니다. 핵심은 입력에서 따옴표를 제거하는 것이 아니라, 값과 명령을 서로 다른 채널로 분리해 데이터베이스가 그 둘을 결코 헷갈리지 않게 하는 것입니다.
ORM / 쿼리 빌더에 기대기
대부분의 ORM은 기본으로 플레이스홀더를 씁니다. 직접 작성하는 날 SQL이 적을수록 안전합니다. 날 SQL을 꼭 써야 한다면 반드시 파라미터화하세요.
최소 권한 DB 사용자
앱의 DB 사용자에게 필요 없는 권한(DROP, 다른 테이블, 관리 작업)을 주지 마세요. 뚫리더라도 피해를 봉쇄합니다. 읽기만 하는 화면이라면 읽기 전용 계정으로 연결해, 만약의 경우에도 데이터가 변경·삭제되지 않게 하세요.
보조 수단으로서의 입력 검증
타입/길이/형식 검사는 도움이 되지만, 주된 방어로 삼지 마세요 — 플레이스홀더 위에 얹는 것입니다.
본 사이트의 견해: 애초에 날 SQL을 손으로 짓기를 멈춰라
SQLi는 아주 오래전부터 존재했지만 사라지지 않습니다 — 입력을 문장에 섞는 것이 "편하기" 때문입니다. 본 사이트의 입장은 명확합니다. 값이 SQL에 문자열로 이어 붙여지는 자리를 절대 만들지 마라. 플레이스홀더나 ORM을 기본으로 삼으면 이 취약점은 설계상 사라집니다. "수동 이스케이프를 더 열심히 하자"는 길로는 가지 마세요.
맹점: 플레이스홀더는 '값'만 나른다
플레이스홀더가 만능은 아닙니다. 값만 나르며 — 테이블명, 컬럼명, ORDER BY 방향(오름차순/내림차순) 같은 쿼리 구조는 나르지 않습니다.
그것들이 동적으로 필요할 때(예: 사용자가 "정렬 키"나 "필터 컬럼"을 고르게 할 때)는 입력을 SQL에 떨어뜨리지 말고, 미리 정의된 허용 목록에서 실제 이름을 고르세요. "정렬 컬럼"과 "필터 컬럼"은 사람들이 플레이스홀더가 알아서 처리해 준다고 착각하는 고전적 맹점입니다.
다음으로 읽기
FAQ
QSQL 인젝션이 일어나면 무슨 일이 생기나요?
공격자가 데이터베이스 쿼리의 의미를 바꿔 — 숨겨야 할 데이터를 읽거나, 변경하거나, 최악의 경우 전부 지우거나 인증을 우회합니다. 대규모 데이터 유출의 고전적 원인입니다.
Q가장 확실한 방어법은 무엇인가요?
값을 플레이스홀더(프리페어드 스테이트먼트)로 넘기는 것입니다. 문자열 이어 붙이기로 SQL을 만들지 말고, 값을 별도 채널을 통해 '데이터'로 넘겨 입력이 명령으로 읽힐 수 없게 하세요. 대부분의 ORM이 기본으로 이렇게 합니다.
Q입력을 이스케이프하면 충분한가요?
수동 이스케이프는 실수하기 쉬워 권장되지 않습니다. 플레이스홀더를 쓰세요. 또한 무언가 뚫렸을 때 피해 범위를 줄이도록 DB 사용자에게 최소 권한을 부여하세요.