
PreparedStatement : SQL ์ฟผ๋ฆฌ๋ฅผ ๋ฏธ๋ฆฌ ์ปดํ์ผํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์กํ๊ธฐ ์ ์ ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌ๋ ๊ฐ์ ์ฝ์
ํ ์ ์์ต๋๋ค.
SQL Injection ๋ฐฉ์ง
SQL Injection : ๊ณต๊ฒฉ์๊ฐ ์
์์ ์ธ SQL ์ฟผ๋ฆฌ๋ฅผ ์คํํ๋๋ก ํจ์ผ๋ก์จ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ๊ทผํ๊ณ ์กฐ์ํ๋ ๊ณต๊ฒฉ ๊ธฐ๋ฒ์
๋๋ค. ๋ง์ฝ ์ธ๋ถ์์ SELECT๋ฌธ WHERE์ ์์ 1=1(ํญ์ ์ฐธ)์ ๋ฃ์ด์ฃผ๊ฒ ๋๋ค๋ฉด ๋ชจ๋ ์ ๋ณด๊ฐ ๋
ธ์ถ๋ ์ํ์ด ์์ต๋๋ค.์ฟผ๋ฆฌ์ ์ฌ์ฌ์ฉ์ฑ
์ฑ๋ฅ ํฅ์
๐ข Statement๊ณผ PreparedStatement์ ์ฐจ์ด
Statement:
String sql = STR."SELECT * FROM Employees WHERE LastName = '\{searchName}'";PreparedStatement:
?๋ฅผ ์ฌ์ฉํด ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํฉ๋๋ค.setXXX()๋ฅผ ์ฌ์ฉํ์ฌ ? ์์น์ ๊ฐ์ ์ค์ ํ ์ ์์ต๋๋ค.String sql = "SELECT * FROM Employees WHERE LastName = ?";๐ฆ Statement ์ ์ ์ฒ๋ฆฌ
MyBean252.java
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class MyBean252 {
private Integer id;
private String name;
private String unit;
private Double price;
}
Controller25.java
@GetMapping("sub2")
public void method2(@RequestParam(value = "name", required = false) String search,
@ModelAttribute("products") ArrayList<MyBean252> list) throws SQLException {
String sql = STR."""
SELECT * FROM Products WHERE ProductName LIKE '%\{search}%'
""";
Statement statement = dataSource.getConnection().createStatement();
ResultSet resultSet = statement.executeQuery(sql);
try(resultSet; statement){
while (resultSet.next()) {
Integer id = resultSet.getInt(1);
String name = resultSet.getString(2);
String unit = resultSet.getString(5);
Double price = resultSet.getDouble(6);
MyBean252 bean252 = new MyBean252(id, name, unit, price);
list.add(bean252);
}
}
}
@RequestParam(value = "name", required = false) String search : ํด๋ผ์ด์ธํธ์์ ํด๋น ์์ฒญ์ ๋ณด๋ผ ๋, name ํ๋ผ๋ฏธํฐ๊ฐ ์์ฒญ์ ๋ฐ๋์ ํฌํจ๋์ง ์๊ธฐ ๋๋ฌธ์ URL์ name=์ด ์์ด๋ ์๋ฌ๊ฐ ๋ฐ์ํ์ง ์์ต๋๋ค. (์ ํ์ ์ ๋ฌ)nameํ๋ผ๋ฏธํฐ๋ฅผ SQL ์ฟผ๋ฆฌ์ search์ ํ ๋นํ์ฌ ์ํ์ ์กฐํํฉ๋๋ค.MyBean252 ์์ id, name, unit, price๋ฅผ ๋ฆฌ์คํธ์ ๋ฃ์ด sub2.jsp์์ ${prodcuts}๋ก ๋ฐ์ ์ํ ๋ชฉ๋ก์ ํ๋ฉด์ ์ถ๋ ฅํฉ๋๋ค.sub2.jsp
<body>
<h3>์ํ๋ช
์ผ๋ก ์ํ ์กฐํ</h3>
<form action="/main25/sub2">
์ํ๋ช
:
<input type="text" name="name" placeholder="์ํ๋ช
์ ์
๋ ฅํ์ธ์.">
<input type="submit" value="์กฐํ">
</form>
<hr>
<div>
<c:forEach items="${products}" var="product">
<h4>${product.id}๋ฒ ์ํ</h4>
<p>์ํ๋ช
:
<input type="text" value="${product.name}" readonly>
</p>
<p>๋จ์ :
<input type="text" value="${product.unit}" readonly>
</p>
<p> ๊ฐ๊ฒฉ :
<input type="text" value="${product.price}" readonly>
๋ฌ๋ฌ
</p>
</c:forEach>
</div>
</body>

๐ฆ PreparedStatement ๋์ ์ฒ๋ฆฌ
MyBean256Product.java
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class MyBean256Product {
private Integer id;
private String name;
private Integer supplierId;
private Integer categoryId;
private String unit;
private Double price;
}
Controller25.java
@Controller
@RequestMapping("main25")
public class Controller25 {
@Autowired
private DataSource dataSource;
@GetMapping("sub6")
public void mehtod6(String search, Model model) throws SQLException {
var list = new ArrayList<MyBean256Product>();
String sql = "SELECT * FROM Products WHERE ProductName LIKE ?";
String keyword = "%"+search+"%";
PreparedStatement preparedStatement = dataSource.getConnection().prepareStatement(sql);
preparedStatement.setString(1, keyword);
ResultSet resultSet = preparedStatement.executeQuery();
try(resultSet; preparedStatement){
while(resultSet.next()){
Integer id = resultSet.getInt(1);
String name = resultSet.getString(2);
Integer supplierId = resultSet.getInt(3);
Integer categoryId = resultSet.getInt(4);
String unit = resultSet.getString(5);
Double price = resultSet.getDouble(6);
MyBean256Product bean = new MyBean256Product(id, name, supplierId, categoryId, unit, price);
list.add(bean);
}
}
model.addAttribute("products", list);
model.addAttribute("prevSearch", search);
}
}
SQL Injection ๋ฐฉ์ง๋ฅผ ์ํด ๊ฒ์์ด๋ฅผ ?๋ก ์ฒ๋ฆฌํ์ฌ PreparedStatement๋ฅผ ์ฌ์ฉํจ์ผ๋ก์จ ์์ ํ๊ฒ ์ฟผ๋ฆฌ๋ฅผ ์คํํฉ๋๋ค.keyword๋ SQL์์ LIKE ์ฐ์ฐ์๋ ์์ผ๋ ์นด๋(%, _)๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ํด๋น ๊ฒ์์ด ์ ๋ค์ ์์ผ๋ ์นด๋๋ฅผ ์ถ๊ฐํด์ผ ํฉ๋๋ค.PreparedStatement ์ฌ์ฉํ์ฌ setString()์ ํตํด ์ด๋ ์์น์ ๊ฐ์ ๋ฃ์ด์ฃผ๋์ง ์ ํฉ๋๋ค. ๋ง์ฝ ?๊ฐ ์ฌ๋ฌ ๊ฐ์ผ ๊ฒฝ์ฐ ? ์ ๋งํผ setXXX() ๋ฉ์๋๋ฅผ ์์ฑํ๋ฉด ๋ฉ๋๋ค.${prevSearch}๋ Spring MVC์ Model ๊ฐ์ฒด์ addAttribute() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ์ถ๊ฐ๋ฉ๋๋ค. Controller์์ Model.addAttribute("prevSearch", search)์ ๊ฐ์ด ์ด์ ๊ฒ์์ด๋ฅผ ๋ชจ๋ธ์ ์ถ๊ฐํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ JSP ํ์ผ์์๋ ${prevSearch}๋ฅผ ์ฌ์ฉํ์ฌ ์ด์ ๊ฒ์์ด๋ฅผ ์ถ๋ ฅํฉ๋๋ค.sub6.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<html>
<head>
<title>Title</title>
<style>
table, tr, th, td {
border: 1px solid black;
border-collapse: collapse;
}
table {
width: 100%;
}
</style>
</head>
<body>
<h3>์ํ ๋ชฉ๋ก</h3>
<%--action์ ๊ฐ์ด ์๊ฑฐ๋ ์๋ต๋๋ฉด ํ์ฌ ์์ฒญ ๊ฒฝ๋ก๋ก ๋ณด๋--%>
<form>
์ํ๋ช
<input value="${prevSearch}" name="search" type="text" placeholder="์กฐํํ ์ํ๋ช
์ ์
๋ ฅํด์ฃผ์ธ์." size="30" >
<%-- form ๋ด์ button ์์๋ submit ๋ฒํผ ์ญํ ์ ํฉ๋๋ค.--%>
<button>์กฐํ</button>
<%-- <input type="submit" value="์กฐํํ๊ธฐ">--%>
</form>
<hr>
<c:if test="${empty products}" var="emptyProduct">
<p style="background-color: beige; padding: 20px 20px; width: 300px">์กฐํ๋ ์ํ์ด ์์ต๋๋ค.</p>
</c:if>
<c:if test="${not emptyProduct}">
<table>
<thead style="background-color: burlywood">
<tr>
<th>์์ด๋</th>
<th>์ํ๋ช
</th>
<th>๊ณต๊ธ์
์ฒด</th>
<th>์นดํ
๊ณ ๋ฆฌ</th>
<th>Unit</th>
<th>๊ฐ๊ฒฉ</th>
</tr>
</thead>
<tbody>
<c:forEach items="${products}" var="product">
<tr style="background-color: beige">
<td>${product.id}</td>
<td>${product.name}</td>
<td>${product.supplierId}</td>
<td>${product.categoryId}</td>
<td>${product.unit}</td>
<td>${product.price}</td>
</tr>
</c:forEach>
</tbody>
</table>
</c:if>
</body>
</html>
์ถ๋ ฅ๊ฒฐ๊ณผ
1) ์ฒซ ํ๋ฉด ๋ฐ ์กฐํ๋ ์ํ์ด ์์ ๋

2) ์ํ์ด ์์ ๋ ์ํ ๋ชฉ๋ก ํ๋ฉด

3) ์ด์ ๊ฒ์ ๊ธฐ๋ก์ด ๋จ๊ฒจ์ง ํ๋ฉด
