Spring Mybatis SQL Injection
MyBatis 바인딩 기법
MyBatis 에서는 #{} 바인딩과 ${} 바인딩이 있다
#{} 바인딩은 바인딩 값을 "" 로 감싸주어 바인딩을 해준다
[GET] http://localhost:8080/members?name=root@gmail.com
[SQL] select * from email = "root@gmail.com"
${} 바인딩은 "" 없이 바로 바인딩을 해준다
[GET] http://localhost:8080/members?name=root@gmail.com
[SQL] select * from email = root@gmail.com
위와 같이하면 "" 로 감싸지않아 쿼리문이 날라가게 되어 오류가 발생한다
따라서 ${} 이용해서 요청하려면 아래와 같이 해야 한다
[GET] http://localhost:8080/members?name="root@gmail.com"
[SQL] select * from email = "root@gmail.com"
${} 주로 사용되는 이유는 검색 조건을 동적으로 바인딩하기 위해서 이다
select * from member ${field} = #{value}
SQL Injection
SQL 인젝션은
SQL INJECT 쿼리문
<%@ page contentType="text/html;charset=UTF-8" language="java"
pageEncoding="utf-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<section>
<h1 align="center">리스트 페이지</h1>
<table border="1" align="center" width="500">
<c:forEach items="${members}" var="member">
<tr>
<td>이메일</td>
<td>
<a href="<c:url value="/member/${member.id}" />">
${member.email}
</a>
</td>
<td>
${member.name}
</td>
</tr>
</c:forEach>
<tr>
<td colspan="3" class="text-center">
<a href="<c:url value="/member/write"/>">작성하기</a>
</td>
</tr>
</table>
</section>
</body>
</html>
실제 View 화면
보통 보안상 패스워드는 DB에 들어갈때 암호화 되어 들어가서 가져온다고 해도 사용할 수 없지만
회원의 주소라던가 주민번호 휴대폰 번호로 바꿔서 한다면 보안상 위험합니다 (물론 현대 웹에서는 개인정보를 자사 웹에서 갖고 있지 않게 끔 하는 추세입니다 외부에 API 를 이용해서 인증만 하는 방식으로 처리해나가 민감한 정보를 저장하지 않습니다)
# 전체 조회 쿼리문
select * from member;
# 개발자가 예상했던 쿼리문
select * from member where id = 1;
# SQL Inject 을 이용하여 email 과 pwd 를 뒤바꿔 DTO 에서는 pwd 를 리턴하지 않아도 email 에서 pwd 를 리턴하게 한다
select * from member where id = 1 union select id, email, pwd, name, phone, register_date from (select id, email as name, pwd as email, name as pwd, phone, register_date from member) as m ;
# listSearch?keyword="root"%20union%20select%20id,%20email,%20pwd,%20name,%20phone,%20register_date%20from%20(select%20id,%20email%20as%20name,%20pwd%20as%20email,%20name%20as%20pwd,%20phone,%20register_date%20from%20member)%20as%20m%20;
겪었던 문제
/** 회원 목록 페이지 */
@RequestMapping(value = "/member/listSearch", method = RequestMethod.GET)
public String memberListPageSearch(Model model, String keyword ) {
ArrayList<MemberDto> members = mapper(MemberDao.class).listSearch(keyword);
model.addAttribute("members", members);
return "member/list";
}
1. ${} 을 줄 경우 String 타입으로 파라미터를 못넘겨 DTO 또는 HashMap 으로 넘겨줍니다
parameterType = "String" 을 써줘도 String 으로는 바인딩이 안되었습니다
ㄴ [2021.10.20 수정] String 을 받아줄 때는 ${param1}, ${param2} 이런식으로 받아서 처리하면 됩니다
첫번째 인자를 ${param1} 로 바인딩 해줍니다
<!-- Mapper.xml -->
<select id="listSearch" resultType="kr.co.loyd.dto.MemberDto">
select * from member where name = ${param1}
</select>
/** 회원 목록 페이지 */
@RequestMapping(value = "/member/listSearch", method = RequestMethod.GET)
public String memberListPageSearch(Model model, String keyword ) {
Map<String, String> map = new HashMap();
map.put("keyword", keyword);
ArrayList<MemberDto> members = mapper(MemberDao.class).listSearch(map);
model.addAttribute("members", members);
return "member/list";
}
때문에 Map 으로 하였습니다
<!-- Mapper.xml -->
<select id="listSearch" parameterType="java.util.Map" resultType="kr.co.loyd.dto.MemberDto">
select * from member where name = ${keyword}
</select>
그 외에도 내 정보보기를 통해 나의 정보를 자세하게 보고 싶은 페이지 아래와 같이 이용하여
다른 사람의 자세한 정보도 볼 수 있다
# 의도했던 쿼리
select * from member where id = 1;
# SQL Injection 공격법으로 모든 사용자 조회
select * from member where id = 1 or '1'='1';
# SQL Injection 공격법으로 특정 사용자 조회
select * from member where id = 1 or '1'='1' limit 5,1;
url 로 id 를 넘기지 않겠지만
api 또는 hidden 컬럼의 id 에 적으면 똑같다
spring 에서 mybatis 는 selectOne 하는 경우 리스트로 반환 되면 오류나기 때문에 offset limit 를 주어 특정 번째에 유저를 상세조회하는 것이다
다른 블로그에서 정리한 내용
결론
파라미터를 바인딩 할 때에는 "" 로 감싸주는 형식으로 해야 한다 ( #{} 사용하기 )
클라이언트 - 백엔드 서버 - DB서버
DB 로도 충분히 문자열 자르기, 정렬, 원하는 정보만을 줄 수 있지만
다양한 공격법을 막기 위해 중간에서 처리해주기 위해 백엔드 서버가 존재하는 것
'∞. 기술 면접 > 4. 데이터베이스' 카테고리의 다른 글
07. 기술면접 - 데이터베이스 - Statement와 PrepareStatement (0) | 2021.10.17 |
---|---|
06. 기술면접 - 데이터베이스 - 인덱스 (Index) (0) | 2021.10.17 |
05. 기술 면접 - 데이터베이스 - SQL 인젝션 (0) | 2021.10.15 |
04. 기술 면접 - 데이터베이스 - 조인 (Join) (1) | 2021.10.15 |
03. 기술 면접 - 데이터베이스 - 트랜잭션 (Transaction) (0) | 2021.10.12 |
댓글
이 글 공유하기
다른 글
-
07. 기술면접 - 데이터베이스 - Statement와 PrepareStatement
07. 기술면접 - 데이터베이스 - Statement와 PrepareStatement
2021.10.17 -
06. 기술면접 - 데이터베이스 - 인덱스 (Index)
06. 기술면접 - 데이터베이스 - 인덱스 (Index)
2021.10.17 -
05. 기술 면접 - 데이터베이스 - SQL 인젝션
05. 기술 면접 - 데이터베이스 - SQL 인젝션
2021.10.15 -
04. 기술 면접 - 데이터베이스 - 조인 (Join)
04. 기술 면접 - 데이터베이스 - 조인 (Join)
2021.10.15