** ๐SQL ๋ณด์ ๊ธฐ๋ฒ**
SQL Injection์ ์๋ฒฝํ ์ฐจ๋จํ๋ PreparedStatement ๊ธฐ๋ฒ๊ณผ
์๋ฒ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ๋ณํํ๋ ์ค๋ฌด + ๋ฉด์ ๋๋น์ฉ ๋ณด์ ์ ๋ต ์ ๋ฆฌ
๐งฉ ๋ชฉ์ฐจ
- SQL Injection์ด๋?
- ๊ณต๊ฒฉ ์์ ๋ฐ ์ํ์ฑ
- ๋ฐฉ์ง ๋ฐฉ๋ฒ: PreparedStatement
- ์ ํจ์ฑ ๊ฒ์ฌ ๋ณํ ์ฒ๋ฆฌ
- ์ค์ ์์ (์ทจ์ฝํ ์ฝ๋ โ ์์ ํ ์ฝ๋)
- ์ค๋ฌด ๋ณด์ ํ
- ๊ธฐ์ ๋ฉด์ ๋๋น ํต์ฌ ์์ฝ
- ๋ง๋ฌด๋ฆฌ ์์ฝ + Notion ์์ฑ ํ
โ
1. SQL Injection์ด๋?
ํญ๋ชฉ |
์ค๋ช
|
์ ์ |
์ฌ์ฉ์๊ฐ ์
๋ ฅ์ฐฝ์ ์
์์ ์ธ SQL์ ์
๋ ฅํด DB๋ฅผ ์กฐ์ํ๋ ๊ณต๊ฒฉ |
๊ฒฐ๊ณผ |
๋ก๊ทธ์ธ ์ฐํ, ๋ฐ์ดํฐ ์ญ์ , ๋ชจ๋ ํ
์ด๋ธ ์ด๋ ๋ฑ ์น๋ช
์ ์ธ ํผํด ๋ฐ์ ๊ฐ๋ฅ |
์ํ๋ |
๐ด ๋งค์ฐ ๋์ โ ๋ฐ๋์ ๋ฐฉ์ด ์ฝ๋ฉ ํ์ |
โ
2. ๊ณต๊ฒฉ ์์ ๋ฐ ์ํ์ฑ
-- ์ฌ์ฉ์๊ฐ ์
๋ ฅํ ID: ' OR 1=1 --
SELECT * FROM members WHERE userid='' OR 1=1 --' AND userpw='...'
๋ฌธ์ ์ |
์ค๋ช
|
' OR 1=1 -- |
ํญ์ true์ธ ์กฐ๊ฑด์ผ๋ก ๋ก๊ทธ์ธ ์ฐํ ๊ฐ๋ฅ |
-- |
๋ค์ ์กฐ๊ฑด๋ฌธ ๋ฌด์ (์ฃผ์ ์ฒ๋ฆฌ๋จ) |
๐จ ๊ฒฐ๊ณผ |
๊ด๋ฆฌ์ ๊ณ์ ์์ด ๋ก๊ทธ์ธ ์ฑ๊ณต, DB ์ ์ ์กฐํ/๋ณ์กฐ ๊ฐ๋ฅ |
โ
3. ๋ฐฉ์ง ๋ฐฉ๋ฒ: PreparedStatement ์ฌ์ฉ
๋ฐฉ๋ฒ |
์ค๋ช
|
PreparedStatement |
SQL์ ๋ณ์ ์๋ฆฌ(?)๋ฅผ ๋๊ณ , ๊ฐ์ ๋ฐ๋ก ์ ๋ฌํ๋ ๋ฐฉ์ |
์ฅ์ |
๋ด๋ถ์ ์ผ๋ก SQL๊ณผ ๊ฐ์ ๋ถ๋ฆฌ โ SQL Injection ๋ถ๊ฐ๋ฅ |
๋ฐ๋์ ์ฌ์ฉ |
๋ชจ๋ SQL ์
๋ ฅ ๊ตฌ๋ฌธ์์ ํ์๋ก ์ ์ฉํด์ผ ํจ |
๐ ์์ ํ PreparedStatement ์์
String sql = "SELECT * FROM members WHERE userid=? AND userpw=?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, userid); // ๊ฐ๋ง ๋ฐ์ธ๋ฉ
ps.setString(2, userpw); // SQL ๊ตฌ์กฐ๋ ๊ฑด๋๋ฆฌ์ง ์์
๐ด ์ ๋ ์ฌ์ฉํ๋ฉด ์ ๋๋ ๋ฐฉ์ (์ทจ์ฝ)
// ์ํ! ์ง์ ๋ฌธ์์ด ์ฐ๊ฒฐ
String sql = "SELECT * FROM members WHERE userid='" + userid + "' AND userpw='" + userpw + "'";
โ
4. ์ ํจ์ฑ ๊ฒ์ฌ ๋ณํ ์ฒ๋ฆฌ
์์น |
์์ |
์ค๋ช
|
๐ป JavaScript |
onsubmit() ์์ ๋น์นธ ํ์ธ |
๋น ๋ฅด๊ณ ์ฌ์ฉ์ ์นํ์ |
๐ฅ๏ธ Servlet |
`if(id == null |
ย |
๋ณํ ์ด์ |
JS๋ ๊บผ์ง ์ ์์ โ ์๋ฒ ์ ํจ์ฑ ๊ฒ์ฌ๋ ํ์! |
ย |
โ
5. ์ค์ ์์ (๋ก๊ทธ์ธ ์ฒ๋ฆฌ ๊ธฐ์ค)
๐ ์์ ํ LoginServlet.java
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
String userid = req.getParameter("userid");
String userpw = req.getParameter("userpw");
// ์๋ฒ ์ธก ์ ํจ์ฑ ๊ฒ์ฌ
if (userid == null || userid.trim().equals("") || userpw == null || userpw.trim().equals("")) {
PrintWriter out = resp.getWriter();
out.println("<script>alert('์์ด๋์ ๋น๋ฐ๋ฒํธ๋ฅผ ๋ชจ๋ ์
๋ ฅํ์ธ์'); history.back();</script>");
return;
}
// DB ๋ก๊ทธ์ธ ์ฒ๋ฆฌ
MemberDAO dao = new MemberDAO();
boolean isValid = dao.login(userid, userpw);
if (isValid) {
req.getSession().setAttribute("loginId", userid);
resp.sendRedirect("main.jsp");
} else {
PrintWriter out = resp.getWriter();
out.println("<script>alert('๋ก๊ทธ์ธ ์คํจ'); location.href='login.jsp';</script>");
}
}
๐ MemberDAO.java (PreparedStatement ์ ์ฉ)
public boolean login(String id, String pw) {
boolean result = false;
try {
Connection conn = DB.getConnection();
String sql = "SELECT * FROM members WHERE userid=? AND userpw=?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, id);
ps.setString(2, pw);
ResultSet rs = ps.executeQuery();
result = rs.next(); // ๊ฒฐ๊ณผ๊ฐ ์กด์ฌํ๋ฉด ๋ก๊ทธ์ธ ์ฑ๊ณต
conn.close();
} catch(Exception e) {
e.printStackTrace();
}
return result;
}
โ
6. ์ค๋ฌด ๋ณด์ ํ ๐ก๏ธ
ํญ๋ชฉ |
์ค๋ช
|
๋ชจ๋ SQL์ PreparedStatement ์ฌ์ฉ |
SELECT, INSERT, UPDATE, DELETE ์ ๋ถ |
์
๋ ฅ๊ฐ์ ํญ์ ์ ํจ์ฑ ๊ฒ์ฌ |
๊ธธ์ด ์ ํ, ๊ณต๋ฐฑ ์ ๊ฑฐ, null ์ฒดํฌ ๋ฑ |
DB ๊ณ์ ์ ์ต์ ๊ถํ์ผ๋ก ์์ฑ |
SELECT/INSERT๋ง ํ์ฉ (๊ด๋ฆฌ์ ๊ถํ X) |
์๋ฌ ๋ฉ์์ง๋ ์ฌ์ฉ์์๊ฒ ์ง์ ๋
ธ์ถ ๊ธ์ง |
e.printStackTrace()๋ ๋ก๊ทธ๋ก๋ง ๋จ๊น |
โ
7. ๊ธฐ์ ๋ฉด์ ๋๋น ํต์ฌ ์์ฝ ๐ฌ
์ง๋ฌธ |
์์ ์ ๋ฆฌ |
SQL Injection์ด๋? |
์ฌ์ฉ์๊ฐ SQL ๊ตฌ๋ฌธ์ ์กฐ์ํด์ DB๋ฅผ ๊ณต๊ฒฉํ๋ ๋ฐฉ์ |
๋ฐฉ์ง ๋ฐฉ๋ฒ์? |
PreparedStatement ์ฌ์ฉ์ผ๋ก SQL๊ณผ ๊ฐ์ ๋ถ๋ฆฌ |
Java์์ ์
๋ ฅ๊ฐ ๊ฒ์ฌ ์์๋? |
`if(id == null |
์ JavaScript๋ง์ผ๋ก๋ ์ถฉ๋ถํ์ง ์๋์? |
๊บผ์ง ์ ์์, ์๋ฒ์์๋ ๋ฐ๋์ ๋ณด์ ๊ฒ์ฌ ์ํ ํ์ |
โ
8. ๋ง๋ฌด๋ฆฌ ์์ฝ ๐ง
- ๐จ SQL Injection์ ๋ณด์ ์ฌ๊ณ 1์์ โ ๋ฐ๋์ ๋๋น ํ์
- ๐ PreparedStatement๋ ๊ฐ์ฅ ๊ธฐ๋ณธ์ด์ ๊ฐ๋ ฅํ ๋ฐฉ์ด ์๋จ
- ๐งผ ์๋ฒ ์ ํจ์ฑ ๊ฒ์ฌ๋ก ์๋ชป๋ ์
๋ ฅ ์ฐจ๋จ (JS๋ง ๋ฏฟ์ง ๋ง๊ธฐ!)
- โ
SQL + ์
๋ ฅ๊ฐ์ ์ ๋ ์ง์ ์ฐ๊ฒฐ X, ํญ์ ๋ถ๋ฆฌํด์ ์ฒ๋ฆฌํ ๊ฒ