데이터베이스 쿼리를 실행할 때 파라미터를 사용하여 동적으로 값을 전달하는 방식이다.
SQL 인젝션을 방지하고 코드 가독성 향상을 위하여 사용된다.
기존 구문을 SELECT * FROM users WHERE email = ?라고 하자.
그리고 사용자의 입력이 'user@test.com' or '1' = '1' 이라고 하자.
만약 parameterized query를 사용하지 않는다면 SELECT * FROM users WHERE email = 'user@test.com' or '1' = '1'이 되면서 '1' = '1'이 항상 참이되어 모든 사용자를 반환하게 된다.
이는 대표적인 SQL injection 기법이다.
하지만 parameterized query를 사용하면 'user@test.com' or '1' = '1'이 단순한 문자열로 취급되어 email과 비교하며 SQL injection을 방지할 수 있다.
Parameterized Query의 한 기법으로 데이터베이스 성능을 최적화하고 보안을 위해 사용한다.
일반적으로 DBMS가 쿼리를 실행하는 절차는 다음과 같다.
1. Parsing (쿼리 구문 문법 체크, 쿼리 실행계획 수립)
2. Execution (쿼리 실행)
3. Fetch (실행된 값 반환. 반환이 없는 Insert, Update, Delete는 미해당)
Prepared Statement는 미리 1번 단계를 끝낸 쿼리를 준비해두고, 파라미터를 대입하여 사용하는 기법이다.
이는 1번 절차를 진행 시간을 생략하고, 이미 쿼리 분석이 완료되었기에 모두 문자열로만 취급하여 SQL Injection을 예방하는 장점을 가지게 한다.
PREPARE get_user_by_age_and_email (int, text) AS
SELECT * FROM users WHERE age > $1 AND email = $2;
EXECUTE get_user_by_age_and_email (26, 'user@test.com');
Postgresql에서는 위와 같이 Prepared Statement를 실행할 수 있다.
대표적인 프레임워크인 Spring의 JPA는 Prepared Statement를 사용하여 SQL Injection을 막고 있고, Django는 커스텀한 Parameterized Query을 사용하여 SQL Injection을 방지하고 있다.