MySQL09 SQL 삽입공격 & SQL 실행과정
비트캠프 서초본원 엄진영 강사님의 수업을 듣고 정리했습니다.
1. SQL 삽입 공격
(1) SQL 삽입 공격
- 사용자의 입력 값으로 SQL 문을 만들 때 가능한 공격 방법이다.
- 값을 입력할 때 SQL 문에 영향을 끼치는 SQL 코드를 함께 삽입하는 방법이다.
SQL 삽입 공격 예
- SQL 문:
select * from user where username='아이디' and password='암호'- 아이디:
hongkildong - 암호:
'ok' or 1=1 --
- 아이디:
- 입력 값이 포함된 최종 SQL 문
select * from user where username='hongkildong' and password='ok' or 1=1 --'1=1조건은 무조건 참이므로 username 과 password가 일치하지 않더라도 상관없이 결과는 true 이다.--은 줄 끝까지 주석으로 취급하기 때문에 SQL 문의 끝에 있던 작은 따옴표를 제거하는 효과가 있다.
해결 방법
Statement대신에PreparedStatement를 사용하면 된다.
(2) Statement vs PreparedStatement
SQL 삽입 공격
Statement: 가능PreparedStatement: 불가능
바이너리 컬럼 값 넣기
Statement: 불가능PreparedStatement: 가능
코드의 간결함
Statement: 가독성이 떨어진다. String.format()으로 개선할 수 있다.PreparedStatement: in-parameter 문법으로 SQL 문과 값을 분리하기 때문에 가독성이 좋다.
실행 속도
Statement- SQL을 실행할 때 마다 DBMS는 매번 SQL 구문 분석 → 최적화 → 실행 과정을 거친다.
PreparedStatement- 처음 SQL을 실행할 때 딱 한 번 SQL 구문 분석 → 최적화 → 실행 과정을 거친다.
- 이 이후에는 내부 SQL 공유 풀에 보관된 최적화된 실행 계획을 바로 실행한다. (hard parsing까지 되어있다.)
- 따라서 SQL을 준비한 후 반복하여 실행하는 경우에는 Statement 보다 빠르다.
표로 정리
| Statement | PreparedStatement | |
|---|---|---|
| SQL 삽입 공격 | 가능 | 불가능 |
| 바이너리 컬럼 값 넣기 | 불가능 | 가능 |
| 코드의 간결함 | 가독성이 떨어진다. | 가독성이 좋다. |
| 실행 속도 | 느리다. | 빠르다. |
2. SQL 실행 과정(오라클 DBMS의 예)
(1) SQL 구분 분석(Parsing)
문법의 유효성 검사(Syntax Check)
- 문법의 규칙을 준수하는지 검사한다.
-
예)
select * form pms_boardform은 잘못된 SQL 문법이다.
SQL 문의 의미 검사(Semantic Check)
- SQL 문에서 지정하는 컬럼이나 테이블, 뷰 등이 유효한지 검사한다.
-
예)
select * from pms_okokpms_okok테이블이 없다면, semantic 오류이다.
SQL 공유 풀 검사(Shared Pool Check)
- 공유 풀은 SQL 문에 대해 생성된 실행 계획(execution plan) 등을 보관한다.
- 먼저 SQL 문에 대해 해시(hash) 연산을 수행하여 SQL ID를 생성한다.
- 공유 풀에 저장된 값 중에서 SQL ID와 일치하는 값이 있는지 조사한다.
- 만약 있다면, 즉시 해당 값을 꺼내 실행 계획에 따라 SQL 문을 실행한다.
- 없다면, 하드 파싱(hard parsing)이라는 과정을 수행한다.
(2) 하드 파싱
SQL 최적화(Optimization)
- SQL 문을 가장 효율적으로 실행할 수 있게 재구성한다.
- 각 문장 별로 실행 계획(execution plan)이라는 명령 코드를 생성한다.
- 여러 개의 실행 계획을 검토한 후 실행 비용을 계산하여 최적의 실행 계획을 생성한다.
SQL 컴파일(Row Source Generation)
- 최적화 단계에서 생성된 실행 계획을 입력으로 받는다.
- 각 실행 단계 별로 결과 데이터(result set)를 리턴할 바이너리 명령을 생성한다.
- 이 바이너리 명령을 Row Source 라고 부른다.
- Row Source는 테이블이나 뷰, 조인 또는 그룹 연산을 가리킨다.
- Row Source Generator는 실행 순서에 따라 Row Source Tree를 생성한다.
(3) SQL 실행
- SQL 엔진은 Row Source Tree**에 따라가면서 *Row Source 바이너리 명령을 실행한다.
- 각 Row Source 바이너리 명령은 테이블이나 뷰, 조인 또는 그룹 연산 결과를 생성한다.
- 최종 실행 결과는 애플리케이션에게 리턴할 결과 데이터(Result Set)이다.
