Post

Stored Procedure SQL Injection

Stored Procedure SQL Injection

0x1. Intro

ํ”„๋กœ์‹œ์ €(procedure)์˜ ์‚ฌ์ „์  ์˜๋ฏธ๋Š” โ€˜์–ด๋–ค ์ผ์„ ํ•˜๋Š” ๊ณต์‹์ ์ด๊ฑฐ๋‚˜ ์ธ์ •๋œ ๋ฐฉ์‹์ธ ์ผ๋ จ์˜ ํ–‰๋™โ€™ ์ด๋‹ค. ์ด ํฌ์ŠคํŒ…์—์„œ๋Š” DB์„œ๋ฒ„์— ์ €์žฅ๋œ ํ”„๋กœ์‹œ์ €์ธ Stored Procedure์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ณ  ์ด์˜ SQL Injection ๊ฐ€๋Šฅ์„ฑ์— ๋Œ€ํ•ด ์‚ดํŽด๋ณด๊ฒ ๋‹ค.


0x2. Stored Procedure๋ž€?

์—ฌ๋Ÿฌ SQL์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ์ฟผ๋ฆฌ๋“ค์˜ ์ง‘ํ•ฉ. DB๋‚ด๋ถ€์— ์ €์žฅ๋œ ์‚ฌ์šฉ์ž ์ง€์ • ํ•จ์ˆ˜์™€ ๋น„์Šทํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ํŽธํ•  ๊ฒƒ ๊ฐ™๋‹ค.

  • SQL Server์—์„œ ์ œ๊ณต๋˜๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ธฐ๋Šฅ. ์ผ๋ จ์˜ ์ฟผ๋ฆฌ๋ฅผ ํ•˜๋‚˜์˜ ๋ชจ๋“ˆํ™” ์‹œ์ผœ ์‚ฌ์šฉ
  • ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ์ฟผ๋ฆฌ๋“ค์˜ ์ง‘ํ•ฉ์„ Stroed Procedure๋กœ ์ €์žฅํ•˜์—ฌ ์žฌ์‚ฌ์šฉ
  • ํ•จ์ˆ˜์™€ ๊ฐ™์ด parameter๋“ค์„ ์ „๋‹ฌํ•˜์—ฌ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

SQL์˜ ์‚ฌ์šฉ์ž ์ง€์ • ํ•จ์ˆ˜๋Š” Stored Procedure์™€ ๋น„์Šทํ•ด๋ณด์ด์ง€๋งŒ ๋ช…ํ™•ํ•œ ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค.

ย Stored FunctionStored Procedure
Return Valuereturn๋ฌธ์œผ๋กœ ํ•˜๋‚˜์˜ ๊ฐ’ ๋ฆฌํ„ด์—ฌ๋Ÿฌ๊ฐœ์˜ OUTํŒŒ๋ผ๋ฏธํ„ฐ ์‚ฌ์šฉ
Create SyntaxCREATE FUNCTION โ€ฆ.CREATE PROCEDUREโ€ฆ
Call SyntaxSELECTCALL
Exception Handling-TRYโ€ฆCATCH
ํ˜ธ์ถœ ์œ„์น˜Function์—์„œ Stored Procedure
ํ˜ธ์ถœ ๋ถˆ๊ฐ€
Stored Procedure์—์„œ Function
ํ˜ธ์ถœ ๊ฐ€๋Šฅ
์‚ฌ์šฉ ๊ฐ€๋Šฅ ๋ช…๋ น์–ดINSERT, UPDATE, DELETE ์‚ฌ์šฉ ๋ถˆ๊ฐ€INSERT, UPDATE, DELETE ์‚ฌ์šฉ ๊ฐ€๋Šฅ

Stored Procedure๋Š” DB๊ฐ’์„ ์กฐ์ž‘ ๋ฐ ์กฐํšŒ ์ฟผ๋ฆฌ๋ฌธ๋“ค์„ ๋ฌถ์–ด ์‚ฌ์šฉํ•˜๋Š” ํ•˜๋‚˜์˜ API,
Stored Function์€ DB๋ฅผ ์กฐํšŒํ•˜๊ณ  ์ด๋ฅผ ์—ฐ์‚ฐํ•˜๋Š” ๋“ฑ ๊ฐ„๋‹จํ•œ ์ž‘์—…์„ ์œ„ํ•œ SQL ๋ฌถ์Œ์œผ๋กœ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.


Stored Procedure(SP)๋Š” ๋ถ€์กฑํ•œ ์ตœ์ ํ™”๋กœ ์ธํ•ด ์ฒ˜๋ฆฌ ์†๋„๊ฐ€ ๋А๋ฆฌ๊ณ  ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ์˜ ๋น„ํšจ์œจ์ ์ด์ง€๋งŒ, ์„œ๋ฒ„์—์„œ ํ•œ๋ฒˆ์˜ ์š”์ฒญ์œผ๋กœ ์—ฌ๋Ÿฌ SQL๋ฌธ์„ ์‹คํ–‰ ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋„คํŠธ์›Œํฌ ๋ถ€ํ•˜๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๊ณ  DB ์œ ์ € ๋Œ€์‹  ํ”„๋กœ์‹œ์ ธ์— ๊ถŒํ•œ์„ ๋ถ€์—ฌํ•  ์ˆ˜ ์žˆ์–ด ๋ณด์•ˆ์„ฑ ํ–ฅ์ƒ์„ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํ•œ๋‹ค.

SP๊ฐ€ ๋ฌด์—‡์ธ์ง€ ๊ธ€๋กœ ์•Œ์•„๋ดค์œผ๋‹ˆ ์ด์ œ๋ถ€ํ„ฐ๋Š” MySQL์„ ์ง์ ‘ ์กฐ์ž‘ํ•˜๋ฉฐ ์•Œ์•„๋ณด์ž. ๋‹ค๋ฅธ DB๋ฅผ ์‚ฌ์šฉํ•ด๋„ ๋ฌธ๋ฒ•์˜ ์ฐจ์ด๋งŒ ์กด์žฌํ•  ๋ฟ ์•„๋ž˜ ์‹ค์Šต ๋‚ด์šฉ๋“ค์˜ ๊ฒฐ๊ณผ๋Š” ํฌ๊ฒŒ ๋‹ค๋ฅด์ง€ ์•Š๋‹ค.

1
2
3
4
5
6
mysql> select @@version;
+-------------------------+
| @@version               |
+-------------------------+
| 8.0.36-0ubuntu0.22.04.1 |
+-------------------------+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CREATE DATABASE testDB;

CREATE TABLE employees(
	id int NOT NULL,
	name varchar(50),
	location varchar(50),
	age int,
	PRIMARY KEY (id)
);

INSERT INTO employees (id, name, location, age) 
VALUES
	(1, 'Alpha', 'Australia', 20),
	(2, 'Bravo', 'Brazil', 28),
	(3, 'Charlie', 'China', 19),
	(4, 'Delta', 'Denmark', 33);

0x3. Stored Procedure ํ™œ์šฉ

Stored Procedure ์ƒ์„ฑ, ์‚ญ์ œ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
USE testDB;
DROP procedure IF EXISTS genSP; -- SP ์‚ญ์ œ. `IF EXISTS` ์ƒ๋žต ๊ฐ€๋Šฅ

-- SP ์ƒ์„ฑ
DELIMITER $$
USE testDB $$
CREATE PROCEDURE genSP(IN employeeName VARCHAR(255), OUT userCnt INT, INOUT plus INT)
BEGIN
	DECLARE sum INT DEFAULT 10;
		-- sum ์ง€์—ญ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๊ณ  10์œผ๋กœ ์ดˆ๊ธฐํ™”
	SELECT * FROM testDB.employees WHERE name = employeeName;
		-- emplyees table์—์„œ name ์ปฌ๋Ÿผ์ด ์ž…๋ ฅ๋ฐ›์€ employeeName์ธ ํ–‰ ์ถœ๋ ฅ
	SELECT count(User) INTO userCnt FROM mysql.user;
		-- MySQL ์œ ์ €์˜ ์ˆ˜๋ฅผ userCnt์— ํ•ด๋‹นํ•˜๋Š” ๋ณ€์ˆ˜์— ๋ฆฌํ„ด
	SET plus = plus + sum;
		-- ์ดˆ๊ธฐํ™”๋œ ๊ฐ’ plus์— sum์˜ ๊ฐ’์„ ๋”ํ•ด plus์— ํ•ด๋‹นํ•˜๋Š” ๋ณ€์ˆ˜์— ๋ฆฌํ„ด
END $$ 
DELIMITER ;
  • DELIMITER : ํ”„๋กœ์‹œ์ € ์•ž,๋’ค์˜ ์œ„์น˜ํ•˜์—ฌ ์•ˆ์— ์žˆ๋Š” ๋ถ€๋ถ„์„ ํ•œ๋ฒˆ์— ์‹คํ–‰๋  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ์—ญํ• 
  • Stored Procedure ๋งค๊ฐœ๋ณ€์ˆ˜์˜ 3๊ฐ€์ง€ ๋ชจ๋“œ
    • IN : ํ”„๋กœ์‹œ์ € ๋‚ด๋ถ€์—์„œ ๊ฐ’์ด ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ํ”„๋กœ์‹œ์ € ๋ฐ˜ํ™˜ ํ›„ ํ˜ธ์ถœ์ž๋Š” ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€. (call-by-value ์™€ ์œ ์‚ฌ)
    • OUT : ์ดˆ๊ธฐ๊ฐ’์€ ๋‚ด๋ถ€์—์„œ NULL. ํ”„๋กœ์‹œ์ € ๋ฐ˜ํ™œ๋  ๋•Œ ๋‚ด๋ถ€ ๊ฐ’ ๋ฆฌํ„ด (call-by-reference ์™€ ์œ ์‚ฌ)
    • INOUT : ํ˜ธ์ถœ์ž์— ์˜ํ•ด ๋ณ€์ˆ˜๊ฐ€ ์ดˆ๊ธฐํ™”๋˜๊ณ  ํ”„๋กœ์‹œ์ €์— ์˜ํ•ด ์ˆ˜์ •๋œ๋‹ค. IN + OUT ์˜ ๊ธฐ๋Šฅ
  • DECLARE : ํ”„๋กœ์‹œ์ € ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์ง€์—ญ๋ณ€์ˆ˜ ์„ ์–ธ
  • BEGIN ~ END : ํ”„๋กœ์‹œ์ €์˜ ์‹ค์งˆ์ ์ธ ์ฝ”๋“œ๊ฐ€ ๋“ค์–ด์žˆ๋Š” ์˜์—ญ. UPDATE, INSERT, DELETE ๋“ฑ์˜ ์ฟผ๋ฆฌ ๋ฟ ๋งŒ ์•„๋‹ˆ๋ผ ์กฐ๊ฑด์‹, ๋ฐ˜๋ณต๋ฌธ ๋“ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž๊ฐ€ ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ง์ ‘ ์ฝ”๋”ฉ

Stored Procedure ํ˜ธ์ถœ

1
2
SET @val = 10;
CALL genSP('Bravo', @cnt, @var);

@val์„ 10์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•˜๊ณ  @cnt๋ณ€์ˆ˜์™€ ํ•จ๊นจ genSP์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌํ–ˆ๋‹ค. ์•„๋ž˜๋Š” ํ•ด๋‹น SQL๋ฌธ์˜ ์‹คํ–‰ ๊ฒฐ๊ณผ์ด๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mysql> SET @val = 10;
mysql> CALL genSP('Bravo', @cnt, @var);
+----+-------+----------+------+
| id | name  | location | age  |
+----+-------+----------+------+
|  2 | Bravo | Brazil   |   28 |
+----+-------+----------+------+

mysql> SELECT @cnt, @var;
+------+------+
| @cnt | @var |
+------+------+
|    5 |   20 |
+------+------+

ํ”„๋กœ์‹œ์ € ๋‚ด๋ถ€์˜ ์ฟผ๋ฆฌ๋ฌธ๋“ค์ด ์„ฑ๊ณต์ ์œผ๋กœ ์‹คํ–‰๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

  • SELECT * FROM testDB.employees WHERE name = 'Bravo';์˜ ๊ฒฐ๊ณผ๊ฐ’์ด ์ถœ๋ ฅ๋๋‹ค.
  • SELECT count(User) INTO userCnt FROM mysql.user;์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋ผ @cnt๋ณ€์ˆ˜์— ๋ฆฌํ„ด๊ฐ’์ด ์ €์žฅ๋๋‹ค.
  • SET plus = plus + sum;์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋ผ 10์œผ๋กœ ์ดˆ๊ธฐํ™”๋œ @var์— ์ง€์—ญ๋ณ€์ˆ˜sum์˜ ๊ฐ’ 10์ด ๋”ํ•ด์ ธ 20์˜ ๊ฐ’์ด ๋ฆฌํ„ด๋๋‹ค.

0x5. Stored Procedure SQL Injection

๊ทธ๋ ‡๋‹ค๋ฉด Stored Procedure์—์„œ SQL Injection ์ทจ์•ฝ์ ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•ด๋ณด๊ธฐ ์œ„ํ•ด ์•„๋ž˜์™€ ๊ฐ™์€ ํ…Œ์ด๋ธ”๊ณผ ํ”„๋กœ์‹œ์ €๋ฅผ ๋งŒ๋“ค์–ด ํ…Œ์ŠคํŠธํ•ด๋ณด์•˜๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
CREATE TABLE user(
	seq int NOT NULL AUTO_INCREMENT,
	uid varchar(50),
	upw varchar(50),
	PRIMARY KEY (seq)
);

INSERT INTO user (uid, upw) 
VALUES
	('guest', 'guest'),
	('admin', 'ADM1NP4SSW0RD');
1
2
3
4
5
6
7
8
9
10
USE testDB;
DROP procedure IF EXISTS testSQLI;
DELIMITER $$
USE testDB $$
CREATE PROCEDURE testSQLI(IN id VARCHAR(255))
BEGIN
	SELECT id;  -- ์ž…๋ ฅ๊ฐ’ ๋””๋ฒ„๊น…์„ ์œ„ํ•œ ์ถœ๋ ฅ
	SELECT * FROM user WHERE uid=id;
END $$ 
DELIMITER ;
1
2
3
4
5
6
mysql> call testSQLI('\' or 1=1 -- a');
+---------------+
| id            |
+---------------+
| ' or 1=1 -- a |
+---------------+

call testSQLI('\' or 1=1 -- a');์ฟผ๋ฆฌ๋ฌธ์œผ๋กœ SQLI ๋ฅผ ์‹œ๋„ํ•ด๋ณด๋ฉด SQL Injection์ด ์‹คํŒจํ•œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

SQL Injection์˜ ์›์ธ

SQL Injection์€ DB๊ฐ€ ๊ณต๊ฒฉ์ž์˜ ์ž…๋ ฅ๊ณผ ์ฟผ๋ฆฌ๋ฌธ์„ ๊ตฌ๋ถ„ํ•˜์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•œ๋‹ค.
SELECT * FROM user WHERE username='admin' OR password='foo' OR 1=1 ์œ„ ์ฟผ๋ฆฌ์—์„œ ๊ณต๊ฒฉ์ž๊ฐ€๋Š” foo' OR 1=1์ด๋ผ๋Š” payload๋ฅผ ์ž…๋ ฅํ•ด SQL Injection ๊ณต๊ฒฉ์„ ์‹คํ–‰ํ–ˆ๋‹ค. DB๋Š” ํ•ด๋‹น payload๊ฐ€ ๊ธฐ์กด์˜ ์ฟผ๋ฆฌ๋ฌธ์ธ์ง€ ์•„๋‹ˆ๋ฉด ๊ณต๊ฒฉ์ž์˜ ์ž…๋ ฅ์ธ์ง€ ์•Œ ์ˆ˜๊ฐ€ ์—†๋‹ค.

SQL Injection ๋Œ€์‘๋ฐฉ๋ฒ•

  • Prepared Statement SQL Injection์œผ๋กœ๋ถ€ํ„ฐ DB๋ฅผ ๋ณดํ˜ธํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” DB๊ฐ€ ์ฟผ๋ฆฌ์™€ ์ž…๋ ฅ ๋ฐ์ดํ„ฐ๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ํ”„๋กœ์‹œ์ €๋Š” Prepared Statement๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
    ์ผ๋ฐ˜์ ์œผ๋กœ SQL๋ฌธ์€ ๊ตฌ๋ฌธ๋ถ„์„(parsing) -> ์ตœ์ ํ™” -> ์‹คํ–‰ ๊ฐ€๋Šฅ ์ฝ”๋“œ๋กœ ํฌ๋งทํŒ… -> ์‹คํ–‰ -> ์ธ์ถœ ์ด๋ ‡๊ฒŒ 5๋‹จ๊ณ„๋ฅผ ๊ฑฐ์ณ ์‹คํ–‰๋œ๋‹ค.
    Prepared Statement๋ž€ ๋ฏธ๋ฆฌ ์ฟผ๋ฆฌ์— ๋Œ€ํ•œ ์ปดํŒŒ์ผ์„ ์‹คํ–‰ํ•˜๊ณ  ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ๊ฐ’์„ ๋‹ค์ค‘์— ์ž…๋ ฅํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. ์ผ๋ฐ˜์ ์ธ ๋ฐฉ์‹๊ณผ ๋‹ฌ๋ฆฌ ๋ถˆํ•„์š”ํ•œ ๋™์ž‘๋“ค์„ ๋งค๋ฒˆ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๊ณ  ์‹คํ–‰๊ณผ ์ธ์ถœ ์ด์ „์˜ ๋‹จ๊ณ„๋Š” ํ•œ๋ฒˆ์˜ ์ปดํŒŒ์ผ๋กœ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด ๋†“๊ณ  ๋‚˜์ค‘์—๋Š” ๋ฏธ๋ฆฌ ์ปดํŒŒ์ผ๋œ Prepared Statement๋ฅผ ๊ฐ€์ ธ๋‹ค ์“ฐ๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋ ‡๊ฒŒ ๋˜๋ฉด DB๋Š” ์ฟผ๋ฆฌ๋ฌธ๊ณผ ๊ณต๊ฒฉ์ž์˜ ์•…์˜์  ์ž…๋ ฅ์„ ์ •ํ™•ํ•˜๊ฒŒ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค. ํ•˜์ง€๋งŒ ๊ทธ๋ ‡๋‹ค๊ณ  ํ•ด์„œ Stored Procedure๊ฐ€ SQL Injection์— ๋ฌด์ ์ธ๊ฑด ์•„๋‹ˆ๋‹ค.

SQL Injection ์šฐํšŒ

  • Dynamic SQL

Dynamic SQL์€ SQL๋ฌธ์„ ๋ฌธ์ž์—ด ๋ณ€์ˆ˜์— ๋‹ด์•„ ์‹คํ–‰ํ•˜๋Š” SQL๋ฌธ์ด๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
USE testDB;
DROP procedure IF EXISTS testSQLI;
DELIMITER $$
USE testDB $$
CREATE PROCEDURE testSQLI(IN id VARCHAR(50))
BEGIN
	-- Dynamic SQL
	SET @sql = CONCAT('SELECT * FROM user WHERE uid=\'', id, '\''); 
	PREPARE s1 FROM @sql;
	EXECUTE s1;
	DEALLOCATE PREPARE s1;
END $$ 
DELIMITER ;

์ด์ „์˜ ์˜ˆ์‹œ์™€ ๊ฒฐ๊ณผ๋Š” ๊ฐ™์ง€๋งŒ ์œ„ ํ”„๋กœ์‹œ์ €๋Š” @sql๋ณ€์ˆ˜์— ์ฟผ๋ฆฌ๋ฅผ ๋‹ด์€ ํ›„ ์‹คํ–‰ํ•˜๋Š” Dynamic SQL์„ ์‚ฌ์šฉํ•œ๋‹ค. ์ด๋ฅผ ํ”„๋กœ์‹œ์ € ์•ˆ์— ์‚ฌ์šฉํ•˜๋ฉด SQL Injection์˜ ๊ทผ๋ณธ์  ๋ฐฉ์–ด๊ธฐ๋ฒ•์ธ Prepared Statement๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„ ๊ฒฐ๊ตญ SQL Injection ๊ณต๊ฒฉ์— ์ทจ์•ฝํ•ด์ง„๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mysql> call testSQLI('evil\' or 1#');
+-----+-------+---------------+
| seq | uid   | upw           |
+-----+-------+---------------+
|   1 | guest | guest         |
|   2 | admin | ADM1NP4SSW0RD |
+-----+-------+---------------+

mysql> call testSQLI('evil\' or 1 UNION SELECT 1,2,3#');
+-----+-------+---------------+
| seq | uid   | upw           |
+-----+-------+---------------+
|   1 | guest | guest         |
|   2 | admin | ADM1NP4SSW0RD |
|   1 | 2     | 3             |
+-----+-------+---------------+

์œ„์˜ ์ถœ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด SQL Injection๊ณต๊ฒฉ์ด ์‹คํ–‰๋˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.


0x4. Stored Procedure์™€ ๋ณด์•ˆ

๊ฐœ๋ฐœ ๊ณผ์ •์—์„œ Stored Procedure๋Š” ๋ณด์•ˆ์„ ์œ„ํ•ด ์ข‹์€ ์„ ํƒ์ด ๋  ์ˆ˜ ์žˆ๋‹ค.

DB์œ ์ € ๊ถŒํ•œ๊ณผ ํ”„๋กœ์‹œ์ €์˜ ๊ถŒํ•œ ๋ถ„๋ฆฌ

1
2
3
4
5
6
7
8
9
10
mysql> SELECT * FROM employees;
ERROR 1142 (42000): SELECT command denied to user 'aestera'@'localhost' for table 'employees'

mysql> SHOW GRANTS FOR 'aestera'@'localhost';
+----------------------------------------------------------------------+
| Grants for aestera@localhost                                         |
+----------------------------------------------------------------------+
| GRANT USAGE ON *.* TO `aestera`@`localhost`                          |
| GRANT EXECUTE ON PROCEDURE `testDB`.`gensp` TO `aestera`@`localhost` |
+----------------------------------------------------------------------+

๊ณ„์ • aestera๋Š” genSPํ”„๋กœ์‹œ์ €์˜ ์‹คํ–‰ ๊ถŒํ•œ์€ ์žˆ์ง€๋งŒ employees ํ…Œ์ด๋ธ”์˜ ์ ‘๊ทผ ๊ถŒํ•œ์ด ์—†๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ aestera๋Š” genSPํ”„๋กœ์‹œ์ €๋ฅผ ํ†ตํ•ด employeesํ…Œ์ด๋ธ”์— ์ œํ•œ์ ์œผ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mysql> SET @var = 10;

mysql> CALL genSP('Bravo', @cnt, @var);
+----+-------+----------+------+
| id | name  | location | age  |
+----+-------+----------+------+
|  2 | Bravo | Brazil   |   28 |
+----+-------+----------+------+

mysql> SELECT @cnt, @var;
+------+------+
| @cnt | @var |
+------+------+
|    6 |   20 |
+------+------+

์ด๋Ÿฌํ•œ ๊ถŒํ•œ์˜ ๋ถ„๋ฆฌ๊ฐ€ ๋ณด์•ˆ์ ์œผ๋กœ๋Š” ์ด์ ์ด ๋œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์•„๋ž˜ ์กฐ๊ฑด์„ ๊ฐ€์ง„ DB๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž.

  • ์œ ์ € admin์€ testํ…Œ์ด๋ธ”๊ณผ ์ค‘์š”ํ•œ ์ •๋ณด๊ฐ€ ๋‹ด๊ธด secretํ…Œ์ด๋ธ”์˜ ๊ถŒํ•œ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.
  • testํ…Œ์ด๋ธ”์„ ์‚ฌ์šฉํ•˜๋Š” ๋กœ์ง์ด SQL Injection์— ์ทจ์•ฝํ•˜๋‹ค.

์ด๋•Œ testํ…Œ์ด๋ธ”์—์„œ SQL Injection์ด ๋ฐœ์ƒํ–ˆ๋‹ค๋ฉด, ์ค‘์š” ์ •๋ณด๊ฐ€ ๋‹ด๊ธด secretํ…Œ์ด๋ธ”๋„ ๊ฐ™์ด ์ทจ์•ฝํ•ด์ง„๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์•„๋ž˜์ฒ˜๋Ÿผ ๊ถŒํ•œ์„ ๋ถ„๋ฆฌํ–ˆ์„๋•Œ๋ฅผ ์ƒ๊ฐํ•ด๋ณด์ž.

  • secretํ…Œ์ด๋ธ”์„ ๋‹ค๋ฃจ๋Š” ๋กœ์ง์„ Stored Procedure๋กœ ์ฒ˜๋ฆฌ
  • admin์˜ secretํ…Œ์ด๋ธ”์— ๋Œ€ํ•œ ๊ถŒํ•œ์„ ์ œ๊ฑฐ

์ด๋ ‡๊ฒŒ ๋˜๋ฉด testํ…Œ์ด๋ธ”์—์„œ SQL Injection์ด ๋ฐœ์ƒํ•ด๋„ secretํ…Œ์ด๋ธ”์ด ์•ˆ์ „ํ•จ๊ณผ ๋™์‹œ์— admin์€ ์ œํ•œ์ ์ด์ง€๋งŒ ์—ฌ์ „ํžˆ secretํ…Œ์ด๋ธ”์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.


0x5. Reference

1
2
3
4
5
6
7
8
- https://www.w3schools.com/sql/sql_stored_procedures.asp
- https://www.c-sharpcorner.com/UploadFile/996353/difference-between-stored-procedure-and-user-defined-functio/
- https://www.shekhali.com/difference-between-stored-procedure-and-function-in-sql-server/
- https://dev.mysql.com/doc/refman/8.0/en/faqs-stored-procs.html#faq-mysql-where-procedures-functions-docs
- https://dev.mysql.com/doc/refman/8.0/en/information-schema-routines-table.html
- https://security.stackexchange.com/questions/68701/how-does-stored-procedure-prevents-sql-injection
- https://www.slideshare.net/topcredu/11-sql
- https://nive.tistory.com/148
This post is licensed under CC BY 4.0 by the author.