์๋ฌ ๋ฉ์์ง ๋ ธ์ถ ์ฐจ๋จ
๊ณต๊ฒฉ์๊ฐ ๊ฒ์์ฐฝ์ ์๋์ ์ธ DB ์๋ฌ ์ ๋ฐ ์ฟผ๋ฆฌ ์
๋ ฅ ํ, ์๋ฌ ๋ฉ์์ง๋ฅผ ํตํด DB ์ ๋ณด(MySQL, ์ปฌ๋ผ ๊ฐ์ ๋ฑ)๋ฅผ ์์๋ด๋ ค๋ ๊ณต๊ฒฉ ๋ฐฉ์ง
์ ๋ ฅ ๊ฐ ๊ฒ์ฆ
1.
์ฌ์ฉ์๊ฐ ์
๋ ฅ ๊ฐ๋ฅํ ํน์๋ฌธ์ ์ ํ
2.
ํน์๋ฌธ์ ํํฐ๋ง
โข
ex) input.replace(โ--โ, โโ);
Prepared Statement
Statement vs PreparedStatement
โข
Statement : SQL ์ฟผ๋ฆฌ์ ์ฌ์ฉํ๋ ๋ฐ์ดํฐ๋ฅผ ์ง์ ๋ฃ๊ณ DB์ ์ฟผ๋ฆฌ๋ฅผ ์ ์กํ๋ ๋ฐฉ์
String sql = "select * from member where name = " + name + ";";
Statement statement = connection.createStatement();
statement.executeQuery(sql);
Java
๋ณต์ฌ
โข
PreparedStatement : ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ธ์๊ฐ์ด ๋น์ด์๋ SQL ์ฟผ๋ฆฌ๋ฅผ ๋จผ์ ์ค๋นํ ๋ค์ ํ์ํ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ์ธ๋ฉํ๋ ๋ฐฉ์
String sql = "select * from member where name = ?;"
PreparedStatement preparedStatement = connection.preparedStatement(sql);
preparedStatement.setString(1, name);
Java
๋ณต์ฌ
JdbcTemplate, JPA
๋ด๋ถ์ ์ผ๋ก ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ ๋ฐฉ์์ผ๋ก ๋์ํ๊ธฐ ๋๋ฌธ์ ๋ณ๋ค๋ฅธ ์ค์ ์์ด SQL Injection์ ๋ฐฉ์งํ ์ ์๋ค.
PreparedStatement(ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ) ์ค์ต
SQL Injection ๋ฐ์ ํ๊ฒฝ
โข
JpaRepository ํน์ JPQL์ ์ฌ์ฉํ๋ฉด ์์์ ์ธ๊ธํ ์ด์ ๋ก ์ธํด SQL Injection ๋ฐ์ ์ํฉ์ ํ
์คํธํ ์ ์๋ค.
โข
Native ์ฟผ๋ฆฌ๋ฅผ ์ง์ ์์ฑํ๋ ์ํฉ์ด๋ผ๋ฉด SQL Injection ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์๋ค. ์ด๋ฅผ ์ด์ฉํ์ฌ SQL Injection ๋ฐ์ ํ๊ฒฝ์ ์ธํ
ํ๋ค.
1.
JPA์ Native ์ฟผ๋ฆฌ ์ต์
์ฌ์ฉ
โข
@Query ์ด๋
ธํ
์ด์
์ nativeQuery = true ์ต์
2.
JdbcTemplate(PreparedStatement ๋ฐฉ์)์ ์ฌ์ฉํ๋ฉด์ ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ์ด ์๋๋ผ, SQL ์ฟผ๋ฆฌ๋ฌธ์ ์ธ์๊ฐ์ ์ง์ ๋ฌธ์์ด concat์ผ๋ก ์ถ๊ฐํด์ ์์ฑ๋ ์ฟผ๋ฆฌ๋ฅผ DB์ ์ ์ก
โข
ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ(SQL Injection ๋ฐฉ์ง)
โฆ
"WHERE content LIKE ?โ
โข
๋ฌธ์์ด concat(SQL Injection ๋ฐฉ์ง X)
โฆ
"WHERE content LIKE '%" + keyword + "%' โ
์ค์ต ๋ด์ฉ
โข
๋ค์๊ณผ ๊ฐ์ SQL Injection ์ ๋ฐ ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ๊ณ DB์ ์ ์กํ๋ค.
create table eden (id int not null auto_increment, name varchar(255), primary key(id));
-- SQL Inejection ์ ๋ฐ ์ฟผ๋ฆฌ
insert into eden (id, name) values (1, 'morak2'); drop table test; --'';
SQL
๋ณต์ฌ
โฆ
๋ฌธ์์ด concat ๋ฐฉ์๊ณผ ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ ๋ฐฉ์์ผ๋ก ๊ฐ๊ฐ ์ฟผ๋ฆฌ๋ฅผ ์ ์กํ์ ๋, ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ด๋ค ์ฐจ์ด๋ก ์ธํด SQL Injection์ด ์ฑ๊ณต ํน์ ์คํจํ๋์ง ํ์ธํ๋ค.
1.
๋ฌธ์์ด concat ๋ฐฉ์
String sql = "insert into eden (id, name) values (1, " + name + ");";
Java
๋ณต์ฌ
2.
ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ ๋ฐฉ์
// JpaRepository
edenRepository.save(new Eden(null, "morak2'); drop table test; --'"));
Java
๋ณต์ฌ
โข
๋ฐ์ดํฐ๋ฒ ์ด์ค๋ MySQL์ ๊ธฐ์ค์ผ๋ก ํ๋ค.
์ค์ต ๊ฒฐ๊ณผ
๋ฌธ์์ด concat ๋ฐฉ์
โข
SQL SyntaxError๊ฐ ๋ฐ์ํ๋ค.
โฆ
MySQL ์๋ฒ์์ ํด๋น ์ฟผ๋ฆฌ๋ฅผ ์ง์ ์
๋ ฅํ๋ฉด ํ
์ด๋ธ์ด drop๋๋ค. โ ์ฟผ๋ฆฌ ์์ฒด์๋ ๋ฌธ์ X
โฆ
๊ทธ๋ ๋ค๋ฉด ์ดํ๋ฆฌ์ผ์ด์
๋จ์์๋ ์ SyntaxError๊ฐ ๋ฐ์ํ ๊น?
โช
์ด๋ธ์ ์ธ์ด ๊ฐ์ค - SQL ์ฟผ๋ฆฌ๊ฐ 2๊ฐ ์ด์์ด๋ฉด ๊ฒฐ๊ณผ ์ญ์ 2๊ฐ ์ด์์ด ๋๋ค. ํ๋์ JdbcTemplate ๋ฉ์๋๋ก ์ฌ๋ฌ ๊ฒฐ๊ณผ๋ฅผ ์ฒ๋ฆฌํ ์ ์์ด์ ์ด๋ฌํ ์ฟผ๋ฆฌ๋ JdbcTemplate์์ SyntaxError๋ฅผ ๋ฐ์์ํจ๋ค.
โข
๊ทธ๋ผ JdbcTemplate์ ์ฌ์ฉํ๋ฉด SQL Injection์ด ๋ฌด์กฐ๊ฑด ๋ฐฉ์ง๋๋?
โฆ
์กฐํ ์ฟผ๋ฆฌ์์ or 1=1;โ๊ณผ ๊ฐ์ ๊ฐ์ ์
๋ ฅํ๋ฉด, ์กฐํ ๊ฒฐ๊ณผ๋ ํ๋์ง๋ง ์กฐ๊ฑด์ ๊ฒฐ๊ณผ๊ฐ ๋ฌด์กฐ๊ฑด ์ฐธ์ด๋ฏ๋ก ํ
์ด๋ธ์ ๋ชจ๋ ๋ ์ฝ๋๋ฅผ ์กฐํํด์ค๊ฒ ๋๋ค. ์ฆ, SQL Injection์ด ์ฑ๊ณตํ๋ค.
ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ ๋ฐฉ์
โข
Hibernate ๋ก๊ทธ
โข
MySQL ์๋ฒ ์ฟผ๋ฆฌ ๋ก๊ทธ
2022-12-08T07:18:54.504132Z 559 Query SET autocommit=0
2022-12-08T07:18:54.536313Z 559 Query insert into eden (name) values ('morak2''); drop table test; โ''')
2022-12-08T07:18:54.551643Z 559 Query commit
2022-12-08T07:18:54.556176Z 559 Query SET autocommit=1
Shell
๋ณต์ฌ
โข
MySQL ๊ธฐ์ค, ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ํ๋ผ๋ฏธํฐ๊ฐ ๋ฐ์ธ๋ฉ ๋ ์๋ฆฌ์ ์๋ค๋ก (โ ์ โ)๋ฅผ ์ถ๊ฐํ๋ค.
โข
๋ฐ์ธ๋ฉ ๋ ํ๋ผ๋ฏธํฐ๊ฐ ์
๋ ฅ๋๋ฉด, โ(์์ ๋ฐ์ดํ)๊ฐ์ ํน์๋ฌธ์๋ ๋ฌธ์์ด(ํ๋ผ๋ฏธํฐ)๋ก์จ SQL์ ๋ฐ์ธ๋ฉ ๋ ์ ์๋๋ก MySQL์์ ํน์๋ฌธ์ ์์ ์ด์ค์ผ์ดํ ๋ฌธ์๋ฅผ ์ถ๊ฐํ๋ค.
โฆ
์ด๋ ์ถ๊ฐ๋๋ ์ด์ค์ผ์ดํ ๋ฌธ์๋ ํฐ๋ฏธ๋์์ ํ์ธํ๊ธฐ์ ์์ ๋ฐ์ดํ์ ์ฐจ์ด๊ฐ ์๋ค. ์๋ง ๋ณด๊ธฐ์๋ ์์ ๋ฐ์ดํ์ ๋๊ฐ์ง๋ง MySQL ๋ด๋ถ์ ์ผ๋ก ์ธ์ฝ๋ฉ ๋๋ฒ๊ฐ ๋ค๋ฅธ ๋ณ๋์ ์ด์ค์ผ์ดํ ๋ฌธ์์ผ ๊ฒ์ผ๋ก ์ถ์
โข
๊ฒฐ๊ณผ์ ์ผ๋ก SQL Injection์ด ๋ฐฉ์ง๋๋ค.