티스토리 뷰

반응형

👉 SQL Injection 정의

KISA 홈페이지에 가면 시큐어 코딩가이드를 제공한다.



출처: https://www.kisa.or.kr/public/laws/laws3_View.jsp?mode=view&p_No=259&b_No=259&d_No=55&ST=T&SV=

👉 SQL Injection 처리해야하는 경우

안전한 코딩기법으로 'preparedStatement 클래스를 사용할 수 없는 환경이라면, 입력값을 필터링 처리한 후 사용한다.' 라고 적혀있다.
MyBatis를 예시로 보자
- #{}는 내부적으로 PreparedStatement를 사용하기 때문에 SQLInjection 공격에 안전하다.
- mybatis에서 ${} 는 컬럼명을 쿼리에 그대로 쓸때 사용되는데 SQLInjection 공격에 취약하기 때문에 사전 입력값 검사가 필수다. 예를 들면, 게시글 조회시 등록순, 조회순 이런 기능을 구현하면서 DESC/AES 부분이나, 조회 조건에서 작성자명, 제목 이런 컬럼명을 그대로 쓸 때 사용한다. ❗이 경우가, 'preparedStatement 클래스를 사용할 수 없는 환경' 이다!

👉 SQL Injection 조치예제(feat. 로그인 모듈)

🙅🏻‍♀️ 좋은 예시는 아닙니다. 참고만 하시길 추천 드립니다.

아래와 같이 로그인 모듈을 구현했었다..
(정확히 말하면 로그인을 시도할때 아이디가 없는 아이디인지. 비밀번호만 틀린건지 이거를 구분하고 싶었었다....)
일단, jsp에서 입력받은 값을 ajax로 호출하여 전달,
그 후에 받아서 VO 통채로 말았고, 서비스 단에 전달했다(findMember).
서비스 단에서는 VO를 통채로 전달하여 mybatis SqlSession으로 select를 한다.

@RequestMapping(value = "/login_ok", method = RequestMethod.POST, consumes = "application/json", headers = "content-type=application/x-www-form-urlencoded;charset=UTF-8") @ResponseBody public String findMember(String json ,ModelMap modelMap,HttpServletRequest request) { Gson gson = new Gson(); AuthMemberVo authMemberVo = new AuthMemberVo(); authMemberVo = gson.fromJson(json, authMemberVo.getClass()); String isMember = authMemberService.isMember(authMemberVo); //...이하 생략
public String isMember(AuthMemberVo authMemberVo) { // 로그인시도한 비밀번호 암호화 authMemberVo = ... authMemberVo = replaceAuthMemberVo(authMemberVo); // 로그인한 정보 조회 AuthMemberVo existingMemberVo = authMemberDao.getMember(authMemberVo); //이하 생략 }
public AuthMemberVo getMember(AuthMemberVo authMemberVo){ return sqlSession.selectOne("user.selectMember", authMemberVo); }
<select id="selectMember" resultType="...vo.AuthMemberVo" parameterType="...vo.AuthMemberVo"> select ... from member where id=#{memId} </select>
/*Cross site scripting*/ @Override public String replacePage(String page){ String [] injectionCodes={"'", "(", ")", "/", "&", ";","<", ">", "\"" }; if(page != null){ for(int i=0;i<injectionCodes.length;i++){ if(page.contains(injectionCodes[i])){ page = page.replace(injectionCodes[i], ""); } } } return page; } /*Sql Injection 방어:문자열 대체*/ @Override public AuthMemberVo replaceAuthMemberVo(AuthMemberVo authMemberVo){ String [] injectionCodes = {"'", "--", "--,#", "/**/", "'or 1=1--", "-1 or", "-1' or", "../", "win.ini", "\""}; String [] replaceCodes = {"&#39", "&#8722&#8722", "&#8722&#8722&#8218&#35", "&#47&#42&#42&#47", "&#39or 1&#611&#8722&#8722", "&#87221 or", "&#87221&#39 or", "&#46&#46&#47", "", "&#34"}; String memId = authMemberVo.getMemId(); if(memId != null){ for (int i = 0; i < injectionCodes.length; i++) { if(memId.contains(injectionCodes[i])){ memId = memId.replaceAll(injectionCodes[i], replaceCodes[i]); } } authMemberVo.setMemId(memId); } //... 이하 생략 }

 

Replace하는 메소드를 구현해서 Service 단에서 호출하였다.

다시구현하라고하면, Service단이 아닌 서블릿필터에 구현할것같다.

 

구현했을당시, 인코딩 필터랑 CORS 처리 필터는 잘 구현했었는데, 간과한부분이다. 😑

 

NEXT🏃‍♀️ 서블릿필터 구현을 정리한 다음글 https://hyejikim.tistory.com/77

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함