
SQL에서는 Data Definition Language (DDL), Data Manipulation Language (DML),
Data Control Language (DCL) 총 세가지의 질의 언어를 제공한다.
그 중 DML은 데이터베이스에서 데이터를 조회, 추가, 삭제, 수정을 수행하는 구문이며
우리가 이용하는 대부분의 기능은 DML로 처리한다고 볼 수 있다.
그렇다면 DML 구문을 사용하는 목적과 형태를 알고 SQL Injection 공격을 이해해보자.
SELECT는 데이터를 조회하는 구문이다.
# mysql SELECT Statement https://dev.mysql.com/doc/refman/8.0/en/select.html
SELECT select_expr [, select_expr] ...
FROM table_references
WHERE where_condition
[GROUP BY {col_name | expr | position}, ... [WITH ROLLUP]]
[ORDER BY {col_name | expr | position} [ASC | DESC], ... [WITH ROLLUP]]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
구문에서 볼 수 있듯이 특정 조건을 만족하는 데이터를 찾기위한 WHERE,
조회한 결과를 정렬하거나 특정 부분만을 확인하기 위한 ORDER BY, LIMIT 등이 있다.
| 절 | 설명 |
|---|---|
| SELECT | 해당 문자열을 시작으로, 조회하기 위한 표현식과 컬럼들에 대해 정의 |
| FROM | 데이터를 조회할 테이블의 이름 |
| WHERE | 조회할 데이터에 대한 조건 |
| ORDER BY | 조회한 결과를 원하는 컬럼 기준으로 정렬 |
| LIMIT | 조회한 결과에서 행의 갯수와 오프셋을 지정 |
💡구문 사용 예시
SELECT
uid, title, boardcontent
FROM board
WHERE boardcontent like '%abc%'
ORDER BY uid DESC
LIMIT 5
FROM 절을 사용하여 board 테이블의 uid, title, boardcontent 데이터를
검색한 후 WHERE 절을 사용하여 boardcontent 데이터에서 "abc" 문자열이
포함되어 있는지 확인한다. 이렇게 찾은 데이터를 ORDER BY 절을 통해 uid 기준으로
내림차순(DESC) 정렬한 후, 5 개의 행을 결과로 반환한다.
INSERT는 데이터를 추가하는 구문이다.
# mysql INSERT Statement https://dev.mysql.com/doc/refman/8.0/en/insert.html
INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name [, partition_name] ...)]
[(col_name [, col_name] ...)]
{ {VALUES | VALUE} (value_list) [, (value_list)] ...
|
VALUES row_constructor_list
}
INSERT 구문에서는 데이터를 추가할 테이블과 컬럼을 정의하는 INTO,
추가할 데이터를 정의하는 VALUES 등이 있다.
| 절 | 설명 |
|---|---|
| INSERT | 해당 문자열을 시작으로, 추가할 테이블과 데이터를 정의 |
| INTO | 데이터를 추가할 테이블의 이름과 컬럼을 정의 |
| VALUES | INTO 절에서 정의한 테이블의 컬럼에 명시한 데이터들을 추가 |
💡구문 사용 예시
INSERT
INTO board (title, boardcontent)
VALUES ('title 1', 'content 1'), ('title 2', 'content 2');
INTO 절을 사용하여 테이블과 컬럼을 각각 board 와 title,
boardcontent 로 명시하였고, VALUES 절을 통해 명시한 테이블의
각각의 컬럼에 데이터를 추가하였다. 위의 예시처럼 쿼리 한 줄로 두 개 이상의
데이터를 추가할 수 있다.
➕서브 쿼리 응용
INSERT
INTO board (title, boardcontent)
VALUES ('title 1', (select upw from users where uid='admin'));
서브 쿼리를 통해 다른 테이블에 존재하는 데이터를 추가할 수 있다.
INTO 절을 통해 추가할 테이블과 컬럼을 명시한 부분은 같으나, boardcontent에
SELECT 구문을 실행하여 users 테이블에 uid 값이 "admin"인 행을 찾고,
해당하는 행의 upw 데이터를 추가하였다.
UPDATE는 데이터를 수정하는 구문이다.
# mysql UPDATE https://dev.mysql.com/doc/refman/8.0/en/update.html
UPDATE [LOW_PRIORITY] [IGNORE] table_references
SET assignment_list
[WHERE where_condition]
UPDATE 구문에서 수정할 컬럼과 데이터를 정의하는 SET, 수정할 데이터의
조건을 정의하는 WHERE 등이 있다.
| 절 | 설명 |
|---|---|
| UPDATE | 해당 문자열을 시작으로, 수정할 테이블을 정의 |
| SET | 수정할 컬럼과 데이터를 정의 |
| WHERE | 수정할 행의 조건을 정의 |
💡구문 사용 예시
UPDATE board
SET boardcontent = "update content 2"
WHERE title = 'title 1';
board 테이블의 boardcontent 컬럼을 "update content 2" 문자열로 수정하고,
수정될 데이터의 title 컬럼의 값이 "title 1"인 행인 것을 WHERE로 명시하였다.
DELETE는 데이터를 삭제하는 구문이다.
# mysql DELETE https://dev.mysql.com/doc/refman/8.0/en/delete.html
DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name [[AS] tbl_alias]
[PARTITION (partition_name [, partition_name] ...)]
[WHERE where_condition]
[ORDER BY ...]
[LIMIT row_count]
DELETE 구문에서 삭제할 테이블의 정의하는 FROM, 삭제할 데이터의 조건을
정의하는 WHERE 절이 있다.
| 절 | 설명 |
|---|---|
| DELETE | 해당 문자열을 시작으로, 이후에 삭제할 테이블을 정의 |
| FROM | 삭제할 테이블을 정의 |
| WHERE | 삭제할 행의 조건을 정의 |
💡구문 사용 예시
DELETE FROM board
WHERE title = 'title 1';
board 테이블의 title 컬럼이 "title 1"인 행을 삭제하는 것을 알 수 있다.
[setup.sql]
CREATE TABLE admin (uid STRING, upw STRING);
CREATE TABLE board (name STRING, text STRING);
INSERT INTO admin (uid, upw) VALUES ('admin', [FLAG]);
Input)
Name: [userInput]
Text: [userInput]
Query)
INSERT INTO board (name, text) VALUES ("", "");
BOARD 출력)
name:
text:
위와 같은 구문에서는 사용자의 입력값을 다로 점검하지 않아 SQLI 취약점이 발생하며,
admin 테이블의 'admin' 사용자의 upw 값에 접근하여 FLAG를 획득할 수 있다.
FLAG 값을 확인하기 위해 board 테이블에 값을 넣어 출력을 해봐야하기 때문에
다음과 같은 서브 쿼리 구문을 작성하여 upw 값을 board에 INSERT 할 수 있다.
", (SELECT upw FROM admin WHERE uid="admin"))--

text 컬럼에 admin 테이블로부터 받아온 FLAG 값을 넣어 출력값을 확인한다.