๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

์ผ/JAVA

SQL Injection ์ทจ์•ฝ์  ๊ฐœ์„ 

๐Ÿ“Œ SQL Injection ์ทจ์•ฝ์  ๊ฐœ์„  ์™ธ ์กฐ์น˜ ์ •๋ฆฌ (๋ณด์•ˆ ๊ฐœ์„  ์‚ฌ๋ก€)

1. SQL Injection ์ทจ์•ฝ์  ๊ฐœ์„ 

๐Ÿ”ด ๋ฌธ์ œ

  • MyBatis์—์„œ ${} ์‚ฌ์šฉ์œผ๋กœ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์ด SQL์— ์ง์ ‘ ์‚ฝ์ž…๋จ
AND B.MBER_NM LIKE '%${searchKeyword}%'
AND B.HNF_NO_TMP IN (${hnfNoTmp})
 

๐ŸŸข ๊ฐœ์„ 

  • #{} ๋ฐ”์ธ๋”ฉ์œผ๋กœ PreparedStatement ์ ์šฉ
  • IN ์ ˆ์€ <foreach>๋กœ ์•ˆ์ „ํ•˜๊ฒŒ ์ฒ˜๋ฆฌ
AND B.MBER_NM LIKE CONCAT('%', #{searchKeyword}, '%')
AND B.HNF_NO_TMP IN
<foreach collection="hnfNoTmpList" item="item" open="(" separator="," close=")">
	#{item}
</foreach>
 

๐Ÿ’ก ํ•ต์‹ฌ ํฌ์ธํŠธ

  • ${} → ๋ฌธ์ž์—ด ์น˜ํ™˜ (์ทจ์•ฝ)
  • #{} → ๋ฐ”์ธ๋“œ ๋ณ€์ˆ˜ (์•ˆ์ „)

2. LIKE / REGEXP ๊ฒ€์ƒ‰ ์‹œ ๋ณด์•ˆ ์ฒ˜๋ฆฌ

๐Ÿ”ด ๋ฌธ์ œ

  • ์™€์ผ๋“œ์นด๋“œ ๋ฐ ์ •๊ทœ์‹ ์‚ฌ์šฉ ์‹œ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์ด ๊ทธ๋Œ€๋กœ ๋ฐ˜์˜๋จ
LIKE '%${bizNm}%'
REGEXP '${value}'
 

๐ŸŸข ๊ฐœ์„ 

  • #{} ๋ฐ”์ธ๋”ฉ ์ ์šฉ
  • %, _ escape ์ฒ˜๋ฆฌ ๋ฐ ESCAPE ์‚ฌ์šฉ
  • ํ•„์š” ์‹œ Pattern.quote()๋กœ ์ •๊ทœ์‹ ๋ฌด๋ ฅํ™”
AND B.BIZ_NM LIKE CONCAT('%', REPLACE(REPLACE(#{bizNm}, '%', '\\%'), '_', '\\_'), '%') ESCAPE '\'
AND A.MBER_LEVEL REGEXP #{safeValue}
 

๐Ÿ’ก ํ•ต์‹ฌ ํฌ์ธํŠธ

  • LIKE → wildcard escape ํ•„์š”
  • REGEXP → ์ž…๋ ฅ๊ฐ’ ๊ฒ€์ฆ ๋˜๋Š” literal ์ฒ˜๋ฆฌ ํ•„์ˆ˜

3. ๋™์  ์ปฌ๋Ÿผ ์‚ฌ์šฉ ์‹œ SQL Injection ๋ฐฉ์ง€

๐Ÿ”ด ๋ฌธ์ œ

WHERE ${vrfcColumnNm} = #{vrfcUniqueNo}
 
  • ์ปฌ๋Ÿผ๋ช…์„ ${}๋กœ ์ง์ ‘ ์น˜ํ™˜ → ์ธ์ ์…˜ ๊ฐ€๋Šฅ

๐ŸŸข ๊ฐœ์„ 

  • ์„œ๋ฒ„์—์„œ ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ ๊ฒ€์ฆ
    ๋˜๋Š” <choose>๋กœ ๋ถ„๊ธฐ ์ฒ˜๋ฆฌ
<choose>
    <when test="column == 'ID'">
    	WHERE ID = #{vrfcUniqueNo}
    </when>
</choose>
 

๐Ÿ’ก ํ•ต์‹ฌ ํฌ์ธํŠธ

  • ์ปฌ๋Ÿผ๋ช…/ํ…Œ์ด๋ธ”๋ช…์€ ๋ฐ”์ธ๋”ฉ ๋ถˆ๊ฐ€ → ๋ฐ˜๋“œ์‹œ ๊ฒ€์ฆ ํ•„์š”

4. XSS (Cross-Site Scripting) ๋ฐฉ์ง€

๐Ÿ”ด ๋ฌธ์ œ

${item.entrpsNm}
innerHTML = data;
 

๐ŸŸข ๊ฐœ์„ 

  • JSP: fn:escapeXml() ์ ์šฉ
  • JS: innerHTML ๋Œ€์‹  textContent
  • ํ•„์š” ์‹œ DOMPurify ์ ์šฉ
<c:out value="${fn:escapeXml(item.entrpsNm)}"/>
element.textContent = value;

๐Ÿ’ก ํ•ต์‹ฌ ํฌ์ธํŠธ

  • HTML ์ถœ๋ ฅ ์‹œ escape ํ•„์ˆ˜
  • innerHTML ์‚ฌ์šฉ ์‹œ sanitizing ํ•„์š”

5. ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๋ฐ ๋กœ๊ทธ ๋ฏผ๊ฐ์ •๋ณด ์ œ๊ฑฐ

๐Ÿ”ด ๋ฌธ์ œ

 
e.printStackTrace();
LOGGER.error("ERROR", e.getMessage());
  • ์ฝ˜์†” ์ถœ๋ ฅ ๋ฐ ๋ฉ”์‹œ์ง€์— ๋ฏผ๊ฐ์ •๋ณด ํฌํ•จ ๊ฐ€๋Šฅ

๐ŸŸข ๊ฐœ์„ 

LOGGER.error("Exception occurred", e);
 

๋˜๋Š”

LOGGER.debug("IGNORED exception occurred");
 

๐Ÿ’ก ํ•ต์‹ฌ ํฌ์ธํŠธ

  • printStackTrace() ๊ธˆ์ง€
  • e.getMessage() ์ง์ ‘ ์ถœ๋ ฅ ์ง€์–‘
  • ๋กœ๊ทธ์—๋Š” ์‚ฌ์šฉ์ž ์ž…๋ ฅ ํฌํ•จ ๊ธˆ์ง€

๐Ÿ“Œ ๊ธฐ์ˆ  ์š”์•ฝ 

  • MyBatis ๊ธฐ๋ฐ˜ ์„œ๋น„์Šค์—์„œ ${} ์‚ฌ์šฉ์œผ๋กœ ๋ฐœ์ƒ ๊ฐ€๋Šฅํ•œ SQL Injection ์ทจ์•ฝ์ ์„ #{} ๋ฐ”์ธ๋”ฉ ๋ฐ <foreach> ๊ตฌ์กฐ๋กœ ๊ฐœ์„ 
  • LIKE/REGEXP ๊ฒ€์ƒ‰ ์‹œ wildcard ๋ฐ ์ •๊ทœ์‹ ์ž…๋ ฅ๊ฐ’์„ escape ๋ฐ ๊ฒ€์ฆ ์ฒ˜๋ฆฌํ•˜์—ฌ ๋ณด์•ˆ ๊ฐ•ํ™”
  • JSP/JavaScript ์˜์—ญ์—์„œ XSS ์ทจ์•ฝ์  ์ œ๊ฑฐ (escapeXml, textContent ์ ์šฉ)
  • ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๋กœ๊น… ๊ตฌ์กฐ ๊ฐœ์„ ์„ ํ†ตํ•ด ๋ฏผ๊ฐ์ •๋ณด ๋…ธ์ถœ ๋ฐฉ์ง€ ๋ฐ ์šด์˜ ๋กœ๊ทธ ๋ณด์•ˆ์„ฑ ํ–ฅ์ƒ