sql.Identifier와 sql.Literal 개념 정리SQL Injection은 외부 입력값이 SQL 쿼리 안에 직접 삽입되면서, 악의적인 명령이 실행되는 보안 취약점을 의미한다.
이는 데이터 유출, 삭제, 인증 우회 등 심각한 보안 사고로 이어질 수 있다.
예를 들어, 사용자가 로그인 폼에서 다음과 같은 값을 입력했다고 가정하자.
Username: admin' OR '1'='1
아래와 같은 방식으로 SQL 쿼리를 문자열로 구성하면:
username = "admin' OR '1'='1"
query = f"SELECT * FROM user WHERE username = '{username}'"
실제 실행되는 쿼리는 다음과 같다:
SELECT * FROM user WHERE username = 'admin' OR '1'='1'
이는 항상 참(OR '1'='1')이 되어 인증 없이 모든 사용자 정보를 가져올 수 있게 된다. 심한 경우, DROP TABLE 같은 파괴적인 명령도 삽입될 수 있다.
초보 개발자들은 흔히 다음과 같이 문자열 포맷팅(f-string, %s, .format())을 사용해 SQL 쿼리를 만든다:
email = input("Email: ")
query = f"SELECT * FROM user WHERE email = '{email}'"
이 방식은 SQL 명령어와 사용자 데이터 간의 경계가 없기 때문에, 사용자 입력이 쿼리 문법 자체를 바꿀 수 있다. 이로 인해 SQL Injection에 매우 취약하다.
psycopg2는 PostgreSQL에 연결하기 위한 Python 라이브러리다. 이 라이브러리는 안전한 SQL 생성을 위한 psycopg2.sql 모듈을 제공한다.
이 모듈은 SQL 쿼리의 문자열 조합 방식 대신, 구조적으로 안전하게 SQL을 작성할 수 있도록 도와준다.
중요한 도구는 다음 두 가지이다:
sql.Identifier(...)
테이블명, 컬럼명 등 식별자(identifier)를 안전하게 삽입
sql.Literal(...)
문자열, 숫자 등 값(value)을 안전하게 삽입
| 항목 | 설명 | 예시 |
|---|---|---|
sql.Identifier() | SQL 구문 내의 테이블명, 컬럼명, 스키마명 등 구조 요소 삽입 | "user", "project_id" |
sql.Literal() | SQL 조건절에서 비교에 사용되는 값 삽입 | 'Suyeon', 123, '2024-01-01' |
두 도구 모두 내부적으로 SQL 구문에 대한 이스케이프 처리를 수행하여 Injection을 원천 차단한다.
project_id = "1; DROP TABLE project;"
query = f"SELECT * FROM project WHERE id = '{project_id}'"
→ 실행될 수 있는 쿼리:
SELECT * FROM project WHERE id = '1'; DROP TABLE project;'
from psycopg2 import sql
project_id = "1; DROP TABLE project;"
query = sql.SQL("SELECT * FROM project WHERE id = {}").format(
sql.Literal(project_id)
)
→ 실제 SQL 내부적으로는 다음과 같이 이스케이프된다:
SELECT * FROM project WHERE id = '1; DROP TABLE project;'
이렇게 되면 DROP TABLE은 실행되지 않고 단순 문자열로 처리된다.
table_name = "user"
query = sql.SQL("SELECT * FROM {}").format(sql.Identifier(table_name))
→ 결과:
SELECT * FROM "user"
여기서 user는 PostgreSQL의 예약어이기 때문에, 반드시 따옴표로 감싸야 정상 동작한다.
sql.Identifier()는 이러한 처리를 자동으로 해준다.
sql.Literal()로 감쌀 것sql.Identifier()로 감쌀 것psycopg2.sql 모듈은 구조적인 SQL 쿼리 생성을 도와준다sql.SQL(...).format(...) 패턴을 중첩해서 사용해도 된다sql.Identifier, sql.Literal 조합이 가장 효과적이다이상으로 SQL Injection의 원리와 psycopg2를 이용한 안전한 SQL 쿼리 작성법에 대해 정리하였습니다.