SQLi를 예방하기 위해 prepared statement를 사용합니다.
여러 방면으로 우회 방법을 찾지만 우회된 케이스가 없습니다.
어떻게 prepared statement가 동작하며 SQLi를 예방하는지에 살펴봅니다.
위키 내용에 의하면 prepared statement는 DBMS에서 제공하는 기능으로 MySQL, Oracle, DB2, Microsoft SQL Server, PostgreSQL와 같은 메이저한 회사에 포함되어 있습니다.
단순히 SQLi 보호 목적보다도 특징 자체에 이점이 있는 기술입니다. 만약 유사한 규칙을 띄는 데이터베이스 명령이 반복 실행될 때 prepared statement 사용은 효율을 증대 시킬 수 있습니다.
prepared statement은 템플릿 형식을 기반으로 매 실행 시마다 특정한 상수 값(Constant Value)으로 치환되어 데이터베이스 문을 실행 시키도록 돕습니다.
예를 들어서 “INSERT INTO products (name, price) VALUES (?, ?)” 형식에 prepared statement가 존재하면 이는 DBMS에서 parses, optimizes and translate 과정을 거쳐 적절하게 컴파일되어 실행됩니다.
DBMS에서는 어떻게 prepared statement를 다룰까?
DBMS에서의 데이터베이스 명령어는 그림과 같이 Parser, Optimizer, Executor 순서대로 실행합니다.
Parser
가장 먼저 Parser는 SQL 명령문이 정상적인지 확인합니다. SQL 명령문이 문법적으로나 의미적으로 맞는지 확인하는 절차를 수행합니다.
parsing이 진행되는 동안 SQL 명령문은 syntax tree라고 불리는 데이터베이스 내부 표현으로 변형됩니다.
Optimizer
생성된 syntax tree에 따라 데이터를 가져오기 위한 가장 효율적인 알고리즘을 결정합니다.
가장 일반적인 의사 결정 알고리즘은 CBO (Cost-Based Optimizer)이며, Optimizer 기술에 따라 인덱싱, 테이블 검색, 조인 등의 Access Path 설정을 통해 요청한 질의에 대한 최적화된 경로로 응답 데이터를 전달 받을 수 있는 execution plan을 제작합니다.
Executor
Optimizer에서 전달된 execution plan은 Executor가 데이터를 가져오고 최종 결과를 작성하는 데 사용됩니다.
Executor는 현재의 execution plan에 따른 데이터를 로딩하기 위해 스토리지 엔진을 사용하며, 트랜잭션의 데이터 무결성 보증을 위해서 트랜잭션 엔진을 사용합니다.
이러한 엔진을 이용해서 Executor는 사용자가 요구하는 데이터를 가져오기 위한 runtime-gernerate 프로그램 처럼 그저 execution plan 대로 실행하는 역할을 수행합니다.
Prepared statements
가장 먼저 prepared statement 형식은 구문 분석을 통해 Syntax Tree로 컴파일을 진행합니다. 당연히 올바른 구문이여야만 컴파일이 완료될 수 있으며 이를 pre-comilation 단계로 봅니다.
구문 분석이 완료됐으면 이제 실행에 필요한 Execution Plan 작성을 위해 Driver에서 전달되 파라미터를 Syntax Tree에 따라 바인딩 시키고 이를 컴파일하여 Execution Plan을 생성합니다.
Executor는 이렇게 생성한 Execution Plan을 통해 결과 값을 받습니다.
SQL Injection이 발생하는 원인을 근본적으로 해결하기 위해선,
개발자가 의도한 Syntax Tree를 생성하는 것이고 이를 위한 기능이 prepared statement라고 보시면 됩니다.
정해진 규칙의 prepared statement를 준비하고,
매번 동적으로 파라미터를 바인딩 시키는 구조를 통해 근본적으로 SQLi 취약점을 예방할 수 있던 것이였습니다.
다시 생각해보면 이러한 로직인지도 모르고 SQL Injection을 시도한게 얼마나 바보스러운 일이였는지 알 수 있는 내용이였습니다.
아래는 발번역하면서 참고한 사이트입니다.
해독에 어려움이 있어서 느끼는데로 작성했으니 참고만하고 아래 자세한 설명을 추가로 보시는 걸 추천드립니다!