용어 사전

SQL 인젝션(SQLi)이란: 입력이 데이터베이스 명령을 바꿔 쓰게 되는 결함

SQL 인젝션(SQLi)은 사용자 입력이 데이터베이스 쿼리의 의미를 바꿔 데이터를 읽거나 변경·삭제하게 되는 취약점입니다. 작동 원리와 프리페어드 스테이트먼트 등 방어법을 설명합니다.

게시 2026-06-08 업데이트 2026-10-06 7분 읽기
이 페이지에서

SQL 인젝션은 검색창에 입력한 텍스트가 데이터베이스에 대한 "명령의 일부"가 되는 취약점입니다. 동작 원리와 확실하게 막는 방법을 설명합니다(공격 절차 없음).

왜 일어나는가 (메커니즘)

근본 원인은 문자열 이어 붙이기로 SQL을 만드는 것입니다. 입력을 문장에 곧장 섞으면 "값의 경계"를 넘어 명령으로 작동할 수 있습니다.

✗ 문자열 이어 붙이기 (위험)

입력이 문장에 이어 붙여짐 → 입력이 명령의 일부로 읽힐 수 있음

✓ 플레이스홀더 (안전)

값을 ? / $1 자리에 데이터로 넘김 → 항상 값으로 남음

입력을 이어 붙이면 값의 경계를 넘어 명령이 바뀐다. 플레이스홀더를 쓰면 값은 값으로 남는다.

피해는 "그 DB 연결이 할 수 있는 모든 것"입니다. 내부 DB에 닿을 수 있다면, RCE 와 SSRF 와 나란히 대규모 유출의 고전적 원인입니다.

방어

1

플레이스홀더 / 프리페어드 스테이트먼트 사용 (가장 중요)

이어 붙이기로 SQL을 만들지 마세요. 값을 ? / 이름 있는 파라미터로 '데이터'로 넘기세요. 이것만으로 이 부류 전체가 거의 사라집니다. 핵심은 입력에서 따옴표를 제거하는 것이 아니라, 값과 명령을 서로 다른 채널로 분리해 데이터베이스가 그 둘을 결코 헷갈리지 않게 하는 것입니다.

2

ORM / 쿼리 빌더에 기대기

대부분의 ORM은 기본으로 플레이스홀더를 씁니다. 직접 작성하는 날 SQL이 적을수록 안전합니다. 날 SQL을 꼭 써야 한다면 반드시 파라미터화하세요.

3

최소 권한 DB 사용자

앱의 DB 사용자에게 필요 없는 권한(DROP, 다른 테이블, 관리 작업)을 주지 마세요. 뚫리더라도 피해를 봉쇄합니다. 읽기만 하는 화면이라면 읽기 전용 계정으로 연결해, 만약의 경우에도 데이터가 변경·삭제되지 않게 하세요.

4

보조 수단으로서의 입력 검증

타입/길이/형식 검사는 도움이 되지만, 주된 방어로 삼지 마세요. 플레이스홀더를 보완하는 것입니다.

본 사이트의 견해: 애초에 날 SQL을 손으로 짓기를 멈춰라

SQLi는 아주 오래전부터 알려져 있었지만 여전히 일어납니다. 입력을 문장에 섞는 것이 "편하기" 때문입니다. 본 사이트의 입장은 명확합니다. 값이 SQL에 문자열로 이어 붙여지는 자리를 절대 만들지 마라. 플레이스홀더나 ORM을 기본으로 삼으면 이 취약점은 설계상 막을 수 있습니다. 수동 이스케이프에 의존하지 마세요.

주의: 플레이스홀더는 값만 나른다

플레이스홀더가 모든 것을 해결하지는 않습니다. 값만 나르며, 테이블명, 컬럼명, ORDER BY 방향(오름차순/내림차순) 같은 쿼리 구조는 나르지 않습니다.

그것들이 동적으로 필요할 때(예: 사용자가 "정렬 키"나 "필터 컬럼"을 고르게 할 때)는 입력을 SQL에 떨어뜨리지 말고, 미리 정의된 허용 목록에서 실제 이름을 고르세요. "정렬 컬럼"과 "필터 컬럼"은 사람들이 플레이스홀더가 알아서 처리해 준다고 착각하는 고전적 맹점입니다.

입력은 폼 필드만이 아니다

검색창과 로그인 폼만 조심하면 된다고 생각하면 놓치는 곳이 생깁니다. SQL에 들어갈 수 있는 값은 여러 경로로 들어옵니다.

  • HTTP 헤더(User-Agent, X-Forwarded-For 등)와 쿠키
  • API가 받은 JSON의 값, 파일에서 읽은 값
  • 한 번 데이터베이스에 저장된 뒤 다른 처리가 나중에 SQL로 조립하는 값

마지막 것은 2차(second-order) SQL 인젝션이라고 합니다. 저장할 때 플레이스홀더를 썼더라도, 다른 처리가 나중에 저장된 값을 문자열로 이어 붙이면 통합니다. "내 데이터베이스에서 왔으니 안전하다"고 여기지 말고, SQL을 조립하는 모든 곳에서 플레이스홀더를 쓰세요.

본 사이트의 X-Forwarded-For 위장 해설에서는 탐색용 문자열이 헤더로 들어왔지만, 값을 플레이스홀더로 넘겼기 때문에 SQL 인젝션이 통하지 않은 사례를 소개합니다.

비슷한 용어와의 차이

이름에 "인젝션"이 들어간 결함에는 공통점이 있습니다. 입력이 다른 언어의 명령으로 읽힌다는 것입니다. 차이는 입력이 어디로 가느냐입니다.

용어입력이 가는 곳주된 피해근본 해결책
SQL 인젝션데이터베이스에 대한 명령(SQL)데이터 읽기, 변경, 삭제플레이스홀더
XSS사용자의 브라우저에서 실행되는 HTML이나 JavaScript사용자 세션의 악용, 페이지의 가짜 콘텐츠출력 시 이스케이프와 CSP
OS 명령 인젝션서버의 셸이 실행하는 명령서버에서 임의 명령 실행(RCE)셸을 거치지 않고 인자를 따로 넘기는 API를 쓴다

SQL 인젝션과 XSS는 자주 함께 언급되지만, 피해가 생기는 곳이 다릅니다. SQL 인젝션은 서버의 데이터베이스를, XSS는 사용자의 브라우저를 노립니다.

주요 언어에서 플레이스홀더를 부르는 이름

주요 언어는 모두 값을 따로 넘기는 방법을 제공합니다. 내 스택에서 어떤 기능을 쓸지 고르는 기준으로 삼으세요.

언어 / 라이브러리쓸 기능
Java(JDBC)PreparedStatement와 setString 같은 값 설정 메서드
PHP(PDO)prepare로 문을 준비하고, 값은 execute에 넘긴다
Python(DB-API)값을 execute의 두 번째 인자로 넘긴다(SQL 문자열에 끼워 넣지 않는다)
Node.js(pg 등)$1 같은 번호 기호를 쓰고, 값은 별도 배열로 넘긴다
C#(.NET)명령의 Parameters에 값을 추가한다

어떤 언어든 템플릿 문자열이나 +로 값을 SQL에 끼워 넣는 순간 이 보호는 작동하지 않습니다.

실제 사례: 제품의 SQL 인젝션에서 시작된 대규모 유출

SQL 인젝션은 오래전부터 알려져 있었지만 지금도 큰 유출을 일으킵니다. 최근 사례는 직접 작성한 코드가 아니라 사용하던 제품에서 시작된 경우가 많습니다.

사례일어난 일
MOVEit Transfer(2023)파일 전송 제품의 SQL 인젝션(CVE-2023-34362)이 수정판이 나오기 전에 악용되어, 2,700곳 이상의 조직에서 데이터가 빠져나갔고 그중 상당수는 위탁업체를 통한 것이었다(→ MOVEit 대규모 데이터 유출)
Metabase(2026)분석 도구의 인증 없는 SQL 인젝션(CVE-2026-72898)이 수정 전에 악용되어, 여러 기업이 고객 데이터 유출을 공표했다(→ Metabase 악용과 유출(영문))
WordPress 코어(2026)다른 결함과 결합하면 인증 없는 SQL 인젝션이 RCE로 이어질 수 있었다(→ CVE-2026-63030 해설(영문))

MOVEit 이후 미국 CISA와 FBI는 2024년 3월 소프트웨어 제조사에 SQL 인젝션을 없애라고 요구하는 경보를 내고, 해결책으로 파라미터화된 쿼리(플레이스홀더)를 들었습니다. 2025년 12월 공개된 MITRE의 "CWE Top 25"에서 SQL 인젝션(CWE-89)은 2위입니다.

입장에 따라 할 일이 다르다

입장먼저 할 일
SQL을 작성하는 쪽(개발자)문자열 이어 붙이기를 멈추고 플레이스홀더나 ORM을 쓴다. 날 SQL 함수의 사용처를 점검한다
제품이나 오픈소스를 운영하는 쪽(운영자)운영 중인 제품의 CVE와 KEV 등재 여부를 확인하고 수정판으로 업데이트한다. 인터넷에서 닿는 관리 화면을 줄인다
양쪽 모두앱의 데이터베이스 사용자 권한을 필요한 테이블과 컬럼으로 좁힌다

내 환경에서 확인하는 방법

공격 문자열을 입력해 시험할 필요는 없습니다. 코드와 설정으로 필요한 것을 알 수 있습니다.

1

문자열로 만든 SQL을 찾는다

코드에서 SQL 키워드(SELECT, WHERE 등)가 문자열 연결이나 템플릿 문자열과 함께 나오는 줄을 검색합니다. 날 SQL 함수($queryRawUnsafe, whereRaw, DB::raw, raw() 등)에 입력이 이어 붙여지지 않는지도 확인하세요.

2

데이터베이스 사용자가 할 수 있는 일을 적어 본다

앱의 데이터베이스 사용자가 어떤 테이블에 접근해 무엇을 할 수 있는지 확인합니다(MySQL은 SHOW GRANTS, PostgreSQL은 information_schema.role_table_grants). 필요 없는 삭제 권한이나 다른 앱의 테이블에 대한 접근은 없애세요.

3

사용 중인 제품을 취약점 정보와 대조한다

CVE / KEV 조회로 운영 중인 제품의 알려진 취약점과 악용 여부를 확인합니다. 의존성은 osv-scanner로 한꺼번에 검사할 수 있습니다.

4

SQL 오류가 화면에 나오지 않는지 확인한다

운영 환경에서 데이터베이스 오류 메시지가 그대로 사용자에게 표시되지 않는지 확인하세요. 자세한 오류는 로그에만 남깁니다.

5

로그에서 징후를 찾는다

데이터베이스 문법 오류가 갑자기 늘지 않았는지, WAF나 액세스 로그에 같은 출처에서 SQL 같은 문자열이 들어간 요청이 연달아 기록되지 않았는지 확인하세요. 그렇다면 그 경로 뒤의 코드부터 점검합니다.

출처(1차 자료)

  • OWASP, "SQL Injection Prevention Cheat Sheet" — cheatsheetseries.owasp.org(플레이스홀더, 저장 프로시저 주의점, 허용 목록 기반 입력 검증, 최소 권한, 이스케이프에 의존하지 않기)
  • CISA·FBI, "Secure by Design Alert: Eliminating SQL Injection Vulnerabilities in Software"(2024년 3월 25일) — cisa.gov
  • MITRE, "2025 CWE Top 25 Most Dangerous Software Weaknesses"(2025년 12월) — cwe.mitre.org(CWE-89가 2위)
  • IPA, "안전한 웹사이트 만드는 법"(일본어) — ipa.go.jp(근본적 해결과 보험적 대책)

다음으로 읽기

분류 번호

CWE는 취약점의 원인이 되는 약점의 종류를, MITRE ATT&CK는 공격자의 기법을 분류한 번호 체계입니다. 둘 다 MITRE가 관리하며 취약점 정보와 탐지 규칙 분류에 널리 쓰입니다.

CWE™: Copyright © 2006–2026, The MITRE Corporation. CWE is a trademark of The MITRE Corporation. The MITRE Corporation hereby grants you a non-exclusive, royalty-free license to use CWE for research, development, and commercial purposes. Any copy you make for such purposes is authorized on the condition that you reproduce MITRE’s copyright designation and this license in any such copy. CWE Terms of Use

© 2026 The MITRE Corporation. This work is reproduced and distributed with the permission of The MITRE Corporation. MITRE ATT&CK and ATT&CK are registered trademarks of The MITRE Corporation. The MITRE Corporation (MITRE) hereby grants you a non-exclusive, royalty-free license to use ATT&CK® for research, development, and commercial purposes. Any copy you make for such purposes is authorized provided that you reproduce MITRE's copyright designation and this license in any such copy. ATT&CK Terms of Use

FAQ

QSQL 인젝션이 일어나면 무슨 일이 생기나요?
A

공격자가 데이터베이스 쿼리의 의미를 바꿔 — 숨겨야 할 데이터를 읽거나, 변경하거나, 최악의 경우 전부 지우거나 인증을 우회합니다. 대규모 데이터 유출의 고전적 원인입니다.

Q가장 확실한 방어법은 무엇인가요?
A

값을 플레이스홀더(프리페어드 스테이트먼트)로 넘기는 것입니다. 문자열 이어 붙이기로 SQL을 만들지 말고, 값을 별도 채널을 통해 '데이터'로 넘겨 입력이 명령으로 읽힐 수 없게 하세요. 대부분의 ORM이 기본으로 이렇게 합니다.

Q입력을 이스케이프하면 충분한가요?
A

수동 이스케이프는 실수하기 쉬워 권장되지 않습니다. 플레이스홀더를 쓰세요. 또한 무언가 뚫렸을 때 피해를 제한하도록 DB 사용자에게 최소 권한을 부여하세요.

QORM을 쓰면 안전한가요?
A

평범하게 쓰면 안전합니다. ORM은 기본으로 값을 플레이스홀더로 넘기기 때문입니다. 하지만 ORM이 제공하는 날 SQL 함수(Prisma의 $queryRawUnsafe, Laravel의 whereRaw와 DB::raw, Django의 raw와 extra 등)에 입력을 이어 붙이면 ORM을 써도 같은 결함이 되살아납니다. 정렬 컬럼명처럼 플레이스홀더로 나를 수 없는 부분도 주의가 필요합니다.

QWAF로 SQL 인젝션을 막을 수 있나요?
A

피해를 줄이는 데는 도움이 되지만 근본 해결책은 아닙니다. 일본 IPA의 '안전한 웹사이트 만드는 법'도 근본적 해결(플레이스홀더)과 피해를 줄일 뿐인 보험적 대책을 구분합니다. WAF는 보험적 대책이며, 탐지를 빠져나가는 입력도 있습니다. 코드를 고칠 때까지의 임시 방편으로 쓰세요.

Q사용 중인 제품에 SQL 인젝션이 있는지 어떻게 알 수 있나요?
A

제품명과 버전을 공개된 취약점(CVE)과, 악용이 확인된 취약점을 모은 CISA의 KEV 목록에 대조하세요. 이 사이트의 CVE / KEV 조회로 할 수 있습니다. MOVEit Transfer와 Metabase의 사례처럼, 사용 중인 제품의 SQL 인젝션이 대규모 유출로 이어진 일은 여러 번 있었습니다.

Q프리페어드 스테이트먼트란 무엇인가요?
A

SQL 문의 형태(값이 들어갈 자리)를 먼저 데이터베이스에 보내고, 값은 나중에 따로 보내는 방식입니다. 값이 들어갈 자리는 ?나 $1 같은 기호(플레이스홀더)로 표시합니다. 형태가 먼저 고정되므로, 나중에 보낸 값은 어떤 문자가 들어 있어도 명령으로 읽히지 않습니다.

Q블라인드 SQL 인젝션이란 무엇인가요?
A

데이터베이스의 내용이나 오류가 화면에 표시되지 않는데도, 응답의 차이나 응답 시간의 차이로 정보를 조금씩 읽어 낼 수 있는 SQL 인젝션입니다. 화면에 아무것도 나오지 않는다고 사이트가 안전한 것은 아닙니다. 원인과 해결책은 일반 SQL 인젝션과 같으며, 플레이스홀더를 쓰면 통하지 않습니다.

Q오류 메시지를 숨기면 막을 수 있나요?
A

아닙니다. 오류를 숨기면 결함을 찾기 어려워지지만, 블라인드 SQL 인젝션처럼 오류가 나오지 않아도 정보를 읽을 수 있습니다. 오류를 화면에 보여서는 안 되지만, 그와 별개로 SQL을 문자열 이어 붙이기로 만드는 곳은 모두 고쳐야 합니다.

Q저장 프로시저는 안전한가요?
A

올바르게 작성하면 플레이스홀더만큼 효과적입니다. 하지만 OWASP는 프로시저가 내부에서 입력을 이어 붙여 SQL을 만들면(동적 SQL) 같은 문제가 되살아난다고 경고합니다. 프로시저가 내부에서 무엇을 하는지 확인하세요.