[Etc] ๐Ÿ’ฃ SQL Injection

์•…์˜์ ์ธ ์‚ฌ์šฉ์ž๊ฐ€ SQL ์ฟผ๋ฆฌ์— ์ฝ”๋“œ๋ฅผ ์‚ฝ์ž…ํ•ด DB์ •๋ณด๋ฅผ ํƒˆ์ทจํ•˜๊ฑฐ๋‚˜ ์กฐ์ž‘ํ•˜๋Š” ๊ฒƒ์„ ๋œปํ•˜๋Š” SQL Injection์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž.


SQL Injection์ด๋ž€?

SQL Injection์ด๋ž€, ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๊ฐ’์„ ํ†ตํ•ด ์›๋ž˜ ์˜๋„ํ•˜์ง€ ์•Š์€ SQL๋ฌธ์„ ์‹คํ–‰ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด
๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํƒˆ์ทจํ•˜๊ฑฐ๋‚˜ ์กฐ์ž‘ํ•˜๋Š” ๊ณต๊ฒฉ

๐Ÿ” ์˜ˆ์‹œ (Spring ์“ฐ๊ธฐ ์ „ ์ผ๋ฐ˜ JDBC ์ฝ”๋“œ ๊ธฐ์ค€):

String sql = "SELECT * FROM users WHERE username = '" + username + "'";

๋งŒ์•ฝ username์— ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฐ’์„ ์ž…๋ ฅํ•˜๋ฉด?

' OR '1'='1

๊ทธ๋Ÿฌ๋ฉด ์ฟผ๋ฆฌ๊ฐ€ ์ด๋ ‡๊ฒŒ ๋ฐ”๋€œ:

SELECT * FROM users WHERE username = '' OR '1'='1'

โ†’ ๋ชจ๋“  ์œ ์ € ์ •๋ณด๊ฐ€ ๋‹ค ์กฐํšŒ๋จ ๐Ÿ˜ฑ
โ†’ ๋น„๋ฐ€๋ฒˆํ˜ธ ์—†์ด ๋กœ๊ทธ์ธ๋„ ๊ฐ€๋Šฅํ•ด์ง


๐Ÿ” Spring ๊ด€์ ์—์„œ SQL Injection ๋ฐฉ์ง€๋ฒ•

โœ… 1. JDBC ์ง์ ‘ ์‚ฌ์šฉ ์‹œ: PreparedStatement ํ•„์ˆ˜!

String sql = "SELECT * FROM users WHERE username = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, username);  // ์ž๋™์œผ๋กœ ๋ฌธ์ž์—ด escape ์ฒ˜๋ฆฌ

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ' OR '1'='1 ๊ฐ™์€ ์ž…๋ ฅ๋„ ๊ทธ๋ƒฅ ๋ฌธ์ž์—ด๋กœ ์ธ์‹๋˜๋ฏ€๋กœ ์•ˆ์ „ํ•˜๋‹ค.


โœ… 2. Spring JDBC Template ์‚ฌ์šฉ ์‹œ

String sql = "SELECT * FROM users WHERE username = ?";
User user = jdbcTemplate.queryForObject(sql, new Object[]{username}, userRowMapper);

์—ฌ๊ธฐ์„œ๋„ ?๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ฐ”์ธ๋”ฉํ•˜๋ฉด PreparedStatement๊ฐ€ ์ ์šฉ๋˜๋ฏ€๋กœ ์•ˆ์ „ํ•˜๋‹ค.


โœ… 3. JPA / Spring Data JPA ์‚ฌ์šฉ ์‹œ

JPA๋Š” SQL์„ ์ง์ ‘ ์ž‘์„ฑํ•˜์ง€ ์•Š๊ณ  ์—”ํ‹ฐํ‹ฐ ์ค‘์‹ฌ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๋ณธ์ ์œผ๋กœ SQL Injection์— ๊ฐ•ํ•จ!

๐Ÿ”ธ ์˜ˆ์‹œ:

User user = userRepository.findByUsername(username);

์ด๋Ÿฐ ๋ฐฉ์‹์€ ๋‚ด๋ถ€์ ์œผ๋กœ PreparedStatement๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์•ˆ์ „ํ•จ.

๐Ÿ”ธ ์ปค์Šคํ…€ JPQL ์‚ฌ์šฉ ์‹œ์—๋„ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ ํ•„์ˆ˜!

@Query("SELECT u FROM User u WHERE u.username = :username")
User findByUsername(@Param("username") String username);

โœ… :username ํ˜•ํƒœ๋กœ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉํ•˜๋ฉด OK
โŒ ์•„๋ž˜์ฒ˜๋Ÿผ ๋ฌธ์ž์—ด ์ง์ ‘ ์—ฐ๊ฒฐํ•˜๋ฉด ์œ„ํ—˜:

@Query("SELECT u FROM User u WHERE u.username = '" + username + "'")

๐Ÿšจ Spring ๋ฐฐ์šฐ๋Š” ์ž…์žฅ์—์„œ ์กฐ์‹ฌํ•  ํฌ์ธํŠธ ์š”์•ฝ

์ƒํ™ฉ์•ˆ์ „ํ•œ ๋ฐฉ๋ฒ•์ฃผ์˜ํ•  ์ 
JDBC ์ง์ ‘ ์‚ฌ์šฉPreparedStatement๋ฌธ์ž์—ด ์ง์ ‘ ์—ฐ๊ฒฐ โŒ
JdbcTemplate? ์ž๋ฆฌ ๋ฐ”์ธ๋”ฉ ์‚ฌ์šฉ์ฟผ๋ฆฌ ์กฐํ•ฉ โŒ
JPA / Spring Data JPAํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ (:param)JPQL ๋ฌธ์ž์—ด ์ง์ ‘ ๋ถ™์ด๊ธฐ โŒ
QueryDSL์™„์ „ ์•ˆ์ „ (ํƒ€์ž… ๊ธฐ๋ฐ˜ ์ฟผ๋ฆฌ)-
์‚ฌ์šฉ์ž ์ž…๋ ฅ๊ฐ’ ์ฒ˜๋ฆฌ์ž…๋ ฅ ๊ฒ€์ฆ, ๊ธธ์ด ์ œํ•œํ•„ํ„ฐ ์—†์ด ๋ฐ”๋กœ ์‚ฌ์šฉ โŒ

๐ŸŽฏ ๋งˆ๋ฌด๋ฆฌ ์š”์•ฝ

  • SQL Injection = ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๊ฐ’์„ ํ†ตํ•ด ์•…์„ฑ SQL ์‹คํ–‰
  • Spring์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ PreparedStatement ๋ฐฉ์‹์ด๋ฏ€๋กœ ์ž˜ ์“ฐ๋ฉด ์•ˆ์ „ํ•จ
  • ํ•˜์ง€๋งŒ ์ง์ ‘ ์ฟผ๋ฆฌ ์งœ๊ฑฐ๋‚˜, ๋ฌธ์ž์—ด๋กœ SQL์„ ์กฐํ•ฉํ•˜๋Š” ๊ฒฝ์šฐ ์ฃผ์˜!
  • ORM(JPA) + ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ ๋ฐฉ์‹์œผ๋กœ ์ž‘์„ฑํ•˜๋ฉด ๊ฑฐ์˜ ๋Œ€๋ถ€๋ถ„ ์•ˆ์ „ํ•˜๊ฒŒ ๋ง‰์„ ์ˆ˜ ์žˆ์Œ