1. CDATA๋?
<![CDATA[ ]]>๋ XML ํ์๊ฐ ๋ด๋ถ ๋ด์ฉ์ ํ์ฑํ์ง ์๊ณ ์์ ๋ฌธ์์ด๋ก ์ฒ๋ฆฌํ๋๋ก ๊ฐ์ธ๋ ๊ตฌ๋ฌธ์
๋๋ค.
์ ํ์ํ๊ฐ?
MyBatis XML ๋งคํผ๋ XML ํ์ผ์ด๊ธฐ ๋๋ฌธ์<, >, & ๊ฐ์ ํน์๋ฌธ์๋ XML ํ๊ทธ๋ก ์ค์ธ๋ ์ ์์ต๋๋ค.
<!-- โ CDATA ์์ด → XML ํ์ฑ ์ค๋ฅ -->
<if test="age > 10">
AND age > 10 <!-- > ๊ฐ XML ๋ซ๋ ํ๊ทธ๋ก ์ค์ธ -->
</if>
<!-- โ
CDATA ์ฌ์ฉ → ์์ ํ๊ฒ ์ฒ๋ฆฌ -->
<if test="age > 10">
<![CDATA[
AND age > 10
]]>
</if>
XML ํน์๋ฌธ์ ๋ชฉ๋ก
| ํน์๋ฌธ์ | XML ์๋ฏธ | SQL์์ ์ฌ์ฉ ์ |
|---|---|---|
< |
ํ๊ทธ ์์ | CDATA ๋๋ < |
> |
ํ๊ทธ ๋ | CDATA ๋๋ > |
& |
์ํฐํฐ ์์ | CDATA ๋๋ & |
" |
์์ฑ๊ฐ ๊ตฌ๋ถ | CDATA ๋๋ " |
' |
์์ฑ๊ฐ ๊ตฌ๋ถ | CDATA ๋๋ ' |
CDATA ์ฌ์ฉ ์์
<select id="getUserList" resultType="UserDto">
SELECT *
FROM users
<![CDATA[
WHERE age >= #{minAge}
AND salary <= #{maxSalary}
AND created_at > #{startDate}
]]>
</select>
CDATA ๋ฒ์ ์ฃผ์
CDATA ์์์๋ MyBatis ํ๊ทธ(<if>, <where> ๋ฑ)๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
ํน์๋ฌธ์๊ฐ ํฌํจ๋ SQL ๋ถ๋ถ๋ง CDATA๋ก ๊ฐ์ธ๋ ๊ฒ์ด ์ข์ต๋๋ค.
<!-- โ CDATA ์์ MyBatis ํ๊ทธ ์ฌ์ฉ ๋ถ๊ฐ -->
<![CDATA[
SELECT * FROM users
<if test="name != null"> ← ์ธ์ ์ ๋จ
WHERE name = #{name}
</if>
]]>
<!-- โ
ํน์๋ฌธ์๊ฐ ์๋ ๋ถ๋ถ๋ง CDATA๋ก ๊ฐ์ธ๊ธฐ -->
<select id="getUserList" resultType="UserDto">
SELECT * FROM users
<where>
<if test="minAge != null">
<![CDATA[ AND age >= #{minAge} ]]>
</if>
<if test="maxSalary != null">
<![CDATA[ AND salary <= #{maxSalary} ]]>
</if>
</where>
</select>
2. #{} — PreparedStatement ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ
#{}๋ JDBC์ PreparedStatement ๋ฐฉ์์ผ๋ก ๊ฐ์ ๋ฐ์ธ๋ฉํฉ๋๋ค.
๊ฐ์ ?๋ก ์นํํ ํ ์์ ํ๊ฒ ๋ฐ์ธ๋ฉํ๋ ๋ฐฉ์์
๋๋ค.
๋์ ๋ฐฉ์
SELECT * FROM users WHERE name = #{name}
MyBatis ์ฒ๋ฆฌ ๊ณผ์ :
1. SELECT * FROM users WHERE name = ? (? ๋ก ์นํ)
2. PreparedStatement.setString(1, "ํ๊ธธ๋") (๊ฐ ๋ฐ์ธ๋ฉ)
3. ์คํ
ํน์ง
- โ SQL Injection ๋ฐฉ์ด
- โ ๋ฌธ์์ด์ ์๋์ผ๋ก ๋ฐ์ดํ ์ฒ๋ฆฌ
- โ ํ์ ์ ๋ง๊ฒ ์๋ ๋ณํ
- โ ๊ฐ(VALUE) ๋ฐ์ธ๋ฉ์ ์ฌ์ฉ
์ฌ์ฉ ์์
<select id="getUser" resultType="UserDto">
SELECT *
FROM users
WHERE user_id = #{userId}
AND name = #{name}
AND status = #{status}
</select>
<insert id="insertUser">
INSERT INTO users (name, email, age)
VALUES (#{name}, #{email}, #{age})
</insert>
<update id="updateUser">
UPDATE users
SET name = #{name},
email = #{email}
WHERE user_id = #{userId}
</update>
3. ${} — ๋ฌธ์์ด ์ง์ ์นํ
${}๋ ๊ฐ์ ๋ฌธ์์ด๋ก ๊ทธ๋๋ก ์นํํฉ๋๋ค.
SQL์ ๊ฐ์ด ์ง์ ์ฝ์
๋๋ ๋ฐฉ์์
๋๋ค.
๋์ ๋ฐฉ์
SELECT * FROM users WHERE name = '${name}'
MyBatis ์ฒ๋ฆฌ ๊ณผ์ :
1. name = "ํ๊ธธ๋" ์ด ๋ค์ด์ค๋ฉด
2. SELECT * FROM users WHERE name = 'ํ๊ธธ๋' (๊ทธ๋๋ก ์ฝ์
)
3. ์คํ
ํน์ง
- โ SQL Injection ์ํ
- โ ๋ฌธ์์ด ๋ฐ์ดํ ์ง์ ์ฒ๋ฆฌ ํ์
- โ ์ปฌ๋ผ๋ช , ํ ์ด๋ธ๋ช , ์ ๋ ฌ ๋ฐฉํฅ์ ์ฌ์ฉ
- โ
#{}๋ก ๋์ฒด ๋ถ๊ฐ๋ฅํ ๊ฒฝ์ฐ์๋ง ์ฌ์ฉ
${}๋ฅผ ์จ์ผ ํ๋ ๊ฒฝ์ฐ
์ปฌ๋ผ๋ช
, ํ
์ด๋ธ๋ช
, ORDER BY ๋ฐฉํฅ์ #{} ๋ก ๋ฐ์ธ๋ฉ์ด ๋ถ๊ฐ๋ฅํฉ๋๋ค.
์ด๋ฐ ๊ฒฝ์ฐ์๋ง ${} ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
<!-- ๋์ ์ ๋ ฌ -->
<select id="getUserList" resultType="UserDto">
SELECT *
FROM users
ORDER BY ${sortColumn} ${sortDirection}
</select>
<!-- ๋์ ํ
์ด๋ธ๋ช
-->
<select id="getDataByYear" resultType="DataDto">
SELECT *
FROM ${tableName}
WHERE year = #{year}
</select>
4. #{} vs ${} ํต์ฌ ๋น๊ต
#{} |
${} |
|
|---|---|---|
| ์ฒ๋ฆฌ ๋ฐฉ์ | PreparedStatement (? ์นํ) |
๋ฌธ์์ด ์ง์ ์นํ |
| SQL Injection | โ ๋ฐฉ์ด๋จ | โ ์ํ |
| ๋ฐ์ดํ ์ฒ๋ฆฌ | โ ์๋ ์ฒ๋ฆฌ | โ ์ง์ ์ฒ๋ฆฌ ํ์ |
| ์ฌ์ฉ ๋์ | ๊ฐ (VALUE) | ์ปฌ๋ผ๋ช , ํ ์ด๋ธ๋ช , ์ ๋ ฌ ๋ฐฉํฅ |
| ์ฃผ ์ฉ๋ | ์ผ๋ฐ์ ์ธ ํ๋ผ๋ฏธํฐ ๋ฐ์ธ๋ฉ | ๋์ SQL ๊ตฌ์กฐ ๋ณ๊ฒฝ |
5. SQL Injection ์ํ์ฑ
${}์ SQL Injection ์ํ์ ์ค์ ์์๋ก ํ์ธํฉ๋๋ค.
๊ณต๊ฒฉ ์๋๋ฆฌ์ค
<!-- ${} ์ฌ์ฉ ์ -->
SELECT * FROM users WHERE name = '${name}'
๊ณต๊ฒฉ์๊ฐ name์ ์๋ ๊ฐ์ ์
๋ ฅํ๋ฉด:
' OR '1' = '1
์ฟผ๋ฆฌ๊ฐ ์ด๋ ๊ฒ ๋ณํจ:
SELECT * FROM users WHERE name = '' OR '1' = '1'
→ ์กฐ๊ฑด์ด ํญ์ TRUE → ์ ์ฒด ๋ฐ์ดํฐ ์กฐํ โ
#{} ๋ฅผ ์ฌ์ฉํ๋ฉด ์์ ํ ์ด์
<!-- #{} ์ฌ์ฉ ์ -->
SELECT * FROM users WHERE name = #{name}
๊ณต๊ฒฉ์๊ฐ name์ ์๋ ๊ฐ์ ์
๋ ฅํด๋:
' OR '1' = '1
PreparedStatement๊ฐ ๊ฐ ์์ฒด๋ก ์ฒ๋ฆฌ:
SELECT * FROM users WHERE name = ?
→ ? ์ "' OR '1' = '1" ๋ฌธ์์ด ์์ฒด๊ฐ ๋ฐ์ธ๋ฉ
→ SQL ๊ตฌ์กฐ ๋ณ๊ฒฝ ๋ถ๊ฐ โ
6. ${} ์ฌ์ฉ ์ ๋ฐ๋์ ์๋ฒ์์ ๊ฒ์ฆ
${}๋ฅผ ์ฌ์ฉํ ์๋ฐ์ ์๋ ๊ฒฝ์ฐ, ์๋ฒ์์ ํ์ฉ๋ ๊ฐ์ธ์ง ๋ฐ๋์ ๊ฒ์ฆํด์ผ ํฉ๋๋ค.
โ ๋ฐฑ์๋์์ SQL Injection์ ์ง์ ๋ฐฉ์ดํ๋ ๊ฑด ์ข์ง ์๋ค
// โ ๋ธ๋๋ฆฌ์คํธ ๋ฐฉ์ — ๊ถ์ฅํ์ง ์์
public String sanitize(String input) {
return input
.replace("'", "''")
.replace("--", "")
.replace(";", "")
.replace("/*", "")
.replace("*/", "");
// ๊ณต๊ฒฉ ํจํด์ ๋ฌด๊ถ๋ฌด์ง → ํ๋๋ผ๋ ๋์น๋ฉด ๋ซ๋ฆผ
}
SQL Injection ๊ณต๊ฒฉ ํจํด์ ๋งค์ฐ ๋ค์ํด์ ๋ชจ๋ ์ผ์ด์ค๋ฅผ ์ง์ ๋ง๋ ๊ฑด ์ฌ์ค์ ๋ถ๊ฐ๋ฅํฉ๋๋ค.
ํ๋๋ผ๋ ๋์น๋ฉด ์ทจ์ฝ์ ์ด ๋ฉ๋๋ค.
#{} ์ ${} ์ ๋ฐฉ์ด ๋ฐฉ์ ์ฐจ์ด
${} + ๋ฐฑ์๋ ์ง์ ๊ฒ์ฆ
๊ฐ๋ฐ์๊ฐ ์ง์ ๊ตฌํ → ์ค์/๋๋ฝ ๊ฐ๋ฅ์ฑ → ์ทจ์ฝ์ ๋ฐ์ ๊ฐ๋ฅ
#{}
JDBC PreparedStatement → DB ๋๋ผ์ด๋ฒ๊ฐ ์์ฒ ์ฐจ๋จ → ์์ ์์
#{} ๋ ๊ฐ์ SQL ๊ตฌ์กฐ์ ์์ ํ ๋ถ๋ฆฌํด์ ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์
์๋ฌด๋ฆฌ ์
์์ ์ธ ๊ฐ์ด ๋ค์ด์๋ SQL ๊ตฌ์กฐ ์์ฒด๊ฐ ๋ฐ๋์ง ์์ต๋๋ค.
${} ๋ฅผ ์จ์ผ ํ๋ค๋ฉด ํ์ดํธ๋ฆฌ์คํธ ๋ฐฉ์์ผ๋ก
// โ
ํ์ดํธ๋ฆฌ์คํธ ๋ฐฉ์ (๊ถ์ฅ)
public List<UserDto> getUserList(String sortColumn, String sortDirection) {
// ํ์ฉ๋ ์ปฌ๋ผ๋ช
๋ง ํ์ฉ
List<String> allowedColumns = List.of("name", "age", "created_at");
if (!allowedColumns.contains(sortColumn)) {
throw new IllegalArgumentException("ํ์ฉ๋์ง ์์ ์ ๋ ฌ ์ปฌ๋ผ์
๋๋ค.");
}
// ํ์ฉ๋ ๋ฐฉํฅ๋ง ํ์ฉ
if (!sortDirection.equalsIgnoreCase("ASC")
&& !sortDirection.equalsIgnoreCase("DESC")) {
throw new IllegalArgumentException("ํ์ฉ๋์ง ์์ ์ ๋ ฌ ๋ฐฉํฅ์
๋๋ค.");
}
return userMapper.getUserList(sortColumn, sortDirection);
}
| ๋ฐฉ์ | ์ค๋ช | ๊ถ์ฅ ์ฌ๋ถ |
|---|---|---|
#{} ์ฌ์ฉ |
DB ๋๋ผ์ด๋ฒ๊ฐ ์์ฒ ์ฐจ๋จ | โ ํญ์ ๊ถ์ฅ |
| ํ์ดํธ๋ฆฌ์คํธ ๊ฒ์ฆ | ํ์ฉ๋ ๊ฐ ๋ชฉ๋ก์ผ๋ก๋ง ํ์ฉ | โ
${} ํ์ ์ ๊ถ์ฅ |
| ๋ธ๋๋ฆฌ์คํธ ๊ฒ์ฆ | ์ํํ ๋ฌธ์์ด ์ง์ ์ ๊ฑฐ | โ ๋น๊ถ์ฅ |
7. ์ค๋ฌด ํ์ฉ ์์
CDATA + #{} + ${} ํจ๊ป ์ฌ์ฉ
<select id="getUserList" resultType="UserDto">
SELECT
user_id,
name,
email,
age,
salary
FROM users
<where>
<if test="name != null and name != ''">
AND name LIKE #{name}
</if>
<if test="minAge != null">
<![CDATA[ AND age >= #{minAge} ]]> <!-- >= ํน์๋ฌธ์ CDATA ์ฒ๋ฆฌ -->
</if>
<if test="maxSalary != null">
<![CDATA[ AND salary <= #{maxSalary} ]]> <!-- <= ํน์๋ฌธ์ CDATA ์ฒ๋ฆฌ -->
</if>
<if test="status != null">
AND status = #{status}
</if>
</where>
ORDER BY ${sortColumn} ${sortDirection} <!-- ๋์ ์ ๋ ฌ ${} -->
</select>
Oracle IN ์ ์ฒ๋ฆฌ
<select id="getUserByIds" resultType="UserDto">
SELECT *
FROM users
WHERE user_id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id} <!-- foreach ์์์๋ #{} ์ฌ์ฉ -->
</foreach>
</select>
8. ์ต์ข ์ ๋ฆฌ
| ํญ๋ชฉ | CDATA | #{} |
${} |
|---|---|---|---|
| ์ฉ๋ | XML ํน์๋ฌธ์ ์ฒ๋ฆฌ | ๊ฐ ๋ฐ์ธ๋ฉ | ๋ฌธ์์ด ์ง์ ์นํ |
| SQL Injection | ํด๋น ์์ | โ ์์ | โ ์ํ |
| ์ฌ์ฉ ๋์ | <, >, & ํฌํจ SQL |
๊ฐ(VALUE) | ์ปฌ๋ผ๋ช , ํ ์ด๋ธ๋ช |
| ์ฃผ์์ฌํญ | ๋ด๋ถ์ MyBatis ํ๊ทธ ๋ถ๊ฐ | ์์ | ๋ฐ๋์ ์๋ฒ ๊ฒ์ฆ ํ์ |
๊ฐ์ ๋ฐ์ธ๋ฉ ํ ๋๋ ํญ์ #{} ์ ์ฌ์ฉํ๊ณ ,
์ปฌ๋ผ๋ช ์ด๋ ํ ์ด๋ธ๋ช ์ฒ๋ผ ๊ตฌ์กฐ์ ์ธ ๋ณ๊ฒฝ์ด ํ์ํ ๋๋ง ${} ๋ฅผ ์ฌ์ฉํ๋, ๋ฐ๋์ ์๋ฒ์์ ๊ฒ์ฆ์ ๊ฑฐ์ณ์ผ ํ๋ค.
<, > ์ ๊ฐ์ XML ํน์๋ฌธ์๊ฐ SQL์์ ํ์ํ๋ค๋ฉด CDATA๋ก ๊ฐ์ธ์ ์ฌ์ฉํ๊ธฐ !
'๐ฅ๏ธ development' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| Oracle Synonym(์๋ ธ๋) (0) | 2026.05.25 |
|---|---|
| ๋ด์ฅ Tomcat vs ์ธ๋ถ Tomcat (0) | 2026.05.15 |
