오늘 끝나면
SQL 인젝션
- ✓SQL 인젝션의 핵심 문제를 한 문장으로 설명한다
- ✓오른쪽 실습에서 SQL이 어떻게 움직이는지 관찰한다
- ✓다음 강의와 이어지는 한계를 말할 수 있다
실습 미션
입력 한 줄로 쿼리를 비트는 원리 이 문장이 실제로 무슨 뜻인지 실습에서 한 번 손으로 확인한다.
성공 조건
- □실습의 기본값을 먼저 관찰
- □입력값이나 모드를 한 번 이상 바꿔 결과 비교
- □왜 결과가 바뀌었는지 한 문장으로 설명
화이트해킹 · 05
SQL
인젝션
입력을 쿼리에 그대로 붙이면 입력이 쿼리 구조를 바꾼다.
따옴표 한 개로 조건을 참으로 만들어 로그인을 우회한다.
근본 방어는 입력을 코드와 섞지 않는 것이다.
입력이 쿼리가 된다
서버는 로그인할 때 DB에 물어본다. “이 아이디·비번 맞는 사람 있냐”고. 그 질문이 SQL 쿼리다.
많은 코드가 쿼리를 이렇게 만든다. "... pw = '" + 입력 + "'" 사용자가 친 글자를 쿼리 문자열에 그대로 이어붙인다.
문제는 여기서 시작된다. 쿼리 한 줄 안에 데이터(비번 값)와 명령(SELECT, WHERE)이 같은 문자열로 섞여 있다.
DB는 둘을 구분하지 못한다. 따옴표가 닫히는 순간 그 뒤 글자를 명령으로 읽는다.
즉 입력이 데이터에 머물지 않고 쿼리의 구조가 되어 버린다.
"... pw = '" + 입력+ "'"
WHERE id = 'admin' AND pw = '1234'
따옴표로 조건을 참으로
공격자는 비번 칸에 비번을 적지 않는다. 대신 x' OR '1'='1 같은 글자를 넣는다.
이게 쿼리에 붙으면 pw = 'x' OR '1'='1'이 된다. 앞쪽 따옴표가 비번 문자열을 일찍 닫고, 그 뒤 OR '1'='1'이 새 조건으로 끼어든다.
1=1은 언제나 참이다. 조건이 OR로 묶여서 비번이 틀려도 전체가 참이 된다.
DB는 시키는 대로 “조건 맞는 행”을 돌려주고, 비번을 몰라도 로그인이 통과된다.
입력 한 줄로 인증을 우회한 것이다. 이게 SQL 인젝션의 핵심 장면이다.
pw = 'x' OR '1'='1'
| pw = '1234' | 거짓 |
| '1' = '1' | 참 |
| 거짓 OR 참 | 참 |
전체가 참 → 비번 몰라도 통과
원인, 신뢰 못 할 입력
버그는 따옴표가 아니라 가정에 있다. 코드가 입력을 “얌전한 값”이라고 믿은 것이다.
입력은 사용자 손에서 오고, 그 손이 공격자일 수 있다. 따옴표·세미콜론·SQL 키워드를 섞어 보낼 수 있다. 통제하지 못하는 바깥에서 오는 모든 입력은 일단 의심해야 한다.
그래서 인젝션은 한 종류가 아니다. 입력을 명령에 그대로 섞는 곳마다 생긴다. SQL은 DB에서, 셸 명령은 OS에서, HTML은 브라우저(다음 강 XSS)에서 일어난다.
공통 패턴은 하나다. 신뢰하지 못할 입력이 명령으로 해석된다.
그러니 막는 법도 하나로 모인다. 입력을 명령과 섞이지 않게 떼어놓는 것이다.
따옴표·키워드를 섞어 보낼 수 있다
여기 들어오면 코드로 실행된다
경계를 넘는 입력을 검사 없이 명령에 섞으면 인젝션이 된다. SQL, 셸, HTML 다 같은 구조다.
직접 쿼리가 바뀌는 걸 본다
오른쪽에서 직접 해본다. 실제 DB는 아니고, 입력이 어떤 쿼리를 만드는지 보여주는 가상 시뮬레이션이다.
문자열 이어붙이기 모드에서 비번 칸에 x' OR '1'='1을 넣어 본다. 만들어진 쿼리에서 그 부분이 강조되고 결과가 인증 우회로 바뀐다.
이제 파라미터 바인딩 모드로 토글해 본다. 같은 입력인데 쿼리가 pw = ?로 바뀌고 입력은 그냥 값으로 들어가서 막힌다.
입력을 코드에 붙이느냐, 값으로 떼어놓느냐. 그 한 끗 차이를 손으로 느끼는 칸이다.
SELECT * FROM users WHERE id = 'admin' AND pw = 'x' OR '1'='1'
비번 칸의 따옴표가 문자열을 닫고, OR '1'='1'이 새 조건이 된다. 입력이 코드가 된 것이다.
조건이 항상 참(1=1)이라 비번을 몰라도 통과한다. 입력을 쿼리에 그대로 붙인 게 원인이다.
방어, 파라미터 바인딩
근본 방어는 단순하다. 입력을 쿼리 문자열에 붙이지 말고, 쿼리는 미리 짜두고 값만 따로 넘기는 것이다.
쿼리에 ? 자리표시자를 두고 WHERE id = ? AND pw = ?처럼 구조를 먼저 고정한다. 그 다음 입력을 자리표시자에 “값”으로 묶어 보낸다.
이걸 파라미터 바인딩(prepared statement)이라 한다.
이러면 입력에 따옴표를 백 개 넣어도 쿼리 구조는 바뀌지 않는다. DB가 그걸 명령이 아니라 비번 글자로만 본다. 인젝션이 원천 차단된다.
보조로 입력 검증, 최소권한 계정, 에러 메시지 숨기기를 겹치면 더 단단해진다. 핵심은 바인딩이다. 코드와 데이터를 섞지 않는 것이다.
Q. SQL 인젝션의 근본 방어는? (입력에서 따옴표 지우기 · 파라미터화 쿼리로 입력을 코드와 안 섞기 · 비번 길게 받기 · 관리자 페이지 숨기기)
정답은 파라미터화 쿼리로 입력을 코드와 안 섞기다.따옴표만 지우면 다른 트릭으로 우회된다. 비번 길이나 페이지 숨김은 인젝션과 무관하다.
입력을 쿼리 문자열에 붙이는 한 위험은 남는다. 자리표시자 ?로 입력을 값에 가두면 구조가 바뀌지 않는다.
한 줄로 정리하면, 코드와 데이터를 분리하면 인젝션이 사라진다.
WHERE id = ? AND pw = ?
? = "x' OR '1'='1"
따옴표째 비번 '값'으로 비교되어 맞지 않는다
입력이 쿼리 구조를 바꾸지 못한다. 코드와 데이터가 분리된다.