14강 / 20강
SQL 인젝션 — 검색창으로 DB를 통째로
따옴표 하나가 여는 문, 그리고 준비된 질의
13강의 원칙 — "입력을 문장으로 해석하지 마라" — 를 가장 유명하게 어긴 사례가 SQL 인젝션입니다. 검색창이나 로그인창에 넣은 값이 DB 질의(SQL)의 일부로 해석되면서, 공격자가 DB에게 직접 명령을 내리게 됩니다.
이번 강의는 실제로 우리 쇼핑몰 검색창을 뚫어 회원 정보를 빼내 본 뒤, 막습니다.
따옴표 하나로 문장을 깬다
검색창에 '(따옴표) 하나만 넣어 봅시다. 앱이 이걸 문장에 그대로 이어 붙이면
SQL 문법이 깨져 오류가 나요. 공격자에게 이 오류는 "여기 인젝션 된다"는 신호입니다.
실습실에서 준비된 질의를 끈 상태로 아래 순서를 시도해 보세요.
'— 문장이 깨져 오류 (탐색)' OR '1'='1— 조건이 항상 참 → 전체 상품이 다 나옴' UNION SELECT email, password FROM users --— 회원 표가 상품 자리에 나옴 😱
마지막 것이 실제 유출 사고의 모습입니다. 상품을 검색했는데 회원 이메일과 비밀번호 해시가 쏟아져 나오는 거죠.
공격 문자열이 만들어 내는 SQL 을 직접 봅니다.
Python
브라우저 안에서 실행 (계산용)
준비된 질의를 켰는지에 따라 결과가 갈립니다.
🥷 공격자
브라우저 안에서 실행 (계산용)
근본 해결 — 준비된 질의(placeholder)
필터링으로 위험한 글자를 막으려는 시도는 늘 뚫립니다(우회가 무한해요). 정답은 구조적으로 데이터와 명령을 분리하는 것 — 준비된 질의입니다.
위험 — 이어 붙이기
"...name = '" + 입력 + "'"
입력이 문장이 됨
안전 — placeholder
"...name = ?", (입력,)
입력은 값으로만 들어감
준비된 질의에서는 DB가 문장 구조를 먼저 정하고, 입력은 나중에 값 자리에만 채웁니다. 따옴표를 아무리 넣어도 '그런 이름의 상품 없음'이 될 뿐, 문장이 안 바뀌어요.
🤔 확인 문제
SQL 인젝션의 근본 해결책은?
해설 필터링은 우회가 끝없어 근본책이 못 됩니다. 준비된 질의는 DB가 문장 구조를 먼저 정하고 입력을 값 자리에만 채우므로, 입력이 문장이 될 수 없어요. 이것이 구조적 해결입니다.
🤔 확인 문제
웹 앱 DB 계정에서 DROP·GRANT 권한을 뺐습니다(9강). SQL 인젝션이 성공하면?
해설 최소 권한은 인젝션을 막지는 못하지만 피해를 줄입니다. 조회 유출은 될 수 있어도 DROP 권한이 없으면 표를 못 지워요. 준비된 질의(막기) + 최소 권한(피해 축소)을 함께 씁니다.