한양과학기술고등학교

에듀테크 프로젝트 대시보드

SQL 인젝션

입력창 한 줄로 로그인을 뚫는 원리

웹사이트는 우리가 입력한 아이디·비밀번호를 SQL 질의문 문자열에 그대로 끼워 넣어 데이터베이스에 물어본다. 그런데 입력값에 따옴표(')와 SQL 문법을 섞어 넣으면, 내가 쓴 글자가 데이터가 아니라 명령의 일부로 해석된다. 아래 가짜 로그인 폼에 직접 공격 문자열을 넣어 질의문이 어떻게 바뀌는지 확인해 보자. 실제 서비스에 시도하는 것은 불법이다.

1 가짜 로그인 폼 — 질의문이 실시간으로 조립된다
서버가 실제로 실행하는 질의문
 
users 테이블 (데모용)
usernamepasswordrole
admins3cr3t!관리자
minsu1234일반 사용자
jiwooqwerty일반 사용자
2 왜 뚫릴까? — 따옴표가 문법을 탈출시킨다

정상 입력 minsu 는 이렇게 들어간다:
... WHERE username='minsu' AND password='1234'

그런데 아이디 칸에 ' OR '1'='1' -- 를 넣으면:
... WHERE username='' OR '1'='1' --' AND password='x'
→ 내가 넣은 ' 가 username 문자열을 일찍 닫아버리고, OR '1'='1' 은 항상 참인 조건이 되고, -- 뒤(비밀번호 검사)는 전부 주석 처리되어 사라진다. 결국 모든 행이 조건을 통과 → 첫 번째 사용자(admin)로 로그인된다.

3 코드 한 줄 차이

취약 — 문자열을 이어 붙임

# 입력값이 곧바로 질의문 문법이 된다 q = f"SELECT * FROM users " \ f"WHERE username='{user}' " \ f"AND password='{pw}'" db.execute(q)

안전 — 값을 자리표시자로 전달

q = "SELECT * FROM users " \ "WHERE username=? AND password=?" # user, pw 는 '값'으로만 취급된다 db.execute(q, (user, pw))

Prepared Statement(준비된 질의문)는 질의문의 구조를 먼저 확정하고, 값은 나중에 별도 통로로 넣는다. 그래서 값 안에 ' OR '1'='1 이 있어도 그냥 "그런 이름의 사용자"를 찾을 뿐 문법으로 해석되지 않는다. 위 데모에서 🛡️ 버튼을 눌러 같은 공격이 막히는 걸 확인해 보자.

4 개발자의 방어법
  • Prepared Statement / 파라미터 바인딩을 항상 사용한다. (가장 확실)
  • ORM(SQLAlchemy, Django ORM 등)을 쓰면 대부분 자동으로 바인딩된다.
  • 입력값 검증·정규화 — 숫자만 받을 곳은 숫자만, 길이 제한.
  • DB 계정 권한 최소화 — 웹 계정에 DROP·관리 권한을 주지 않는다.
  • 오류 메시지에 SQL 원문을 노출하지 않기 — 공격자에게 힌트가 된다.
Q. 따옴표를 없애거나 막으면 되는 거 아닌가요?

부분적으로 도움은 되지만 불완전합니다. 숫자 컨텍스트(id = 5)는 따옴표가 필요 없어 그대로 뚫리고, 인코딩·유니코드 우회, CHAR() 함수 등 우회 기법이 많습니다. "위험한 글자를 걸러내는" 블랙리스트 방식보다, 값과 코드를 구조적으로 분리하는 Prepared Statement가 정답입니다.

Q. 인젝션으로 로그인 우회 말고 또 뭘 할 수 있나요?

UNION SELECT 로 다른 테이블(회원 전체, 카드번호 등) 내용을 화면에 끌어오거나, 조건 참/거짓에 따른 반응 차이로 데이터를 한 글자씩 알아내는 Blind SQLi, 심하면 데이터 삭제·서버 명령 실행까지 가능합니다. 2008년 이후 대형 유출 사고의 단골 원인이며, OWASP Top 10에 늘 포함됩니다.

⚠️ 이 페이지의 폼은 브라우저 안에서만 도는 가짜 시뮬레이터다. 학습 목적이며, 실제 웹사이트에 공격 문자열을 넣는 행위는 정보통신망법 위반(형사처벌)이다.