티스토리 뷰
👉 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 = {"'", "−−", "−−‚#", "/**/", "'or 1ɣ−−", "𕒵 or", "𕒵' or", "../", "", """}; 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
'FrameWork > Spring' 카테고리의 다른 글
ElasticSearch 대신 OpenSearch 사용기, 그리고 예제 (3) | 2021.12.17 |
---|---|
SQL Injection 서블릿 필터를 이용해 처리하기 - 2 (0) | 2021.07.13 |
스프링 DL(Dependency Lookup)/DI(Dependency Injection) (0) | 2021.06.22 |
CORS 과정과 처리 (0) | 2021.06.08 |
quartz +Spring Batch 관련 참고 블로그 모음집 (0) | 2021.06.01 |
- Total
- Today
- Yesterday
- C++
- script버전
- 퇴사
- 백준퇴사
- 백준14501
- 프론트엔드
- C# java 차이점
- 백준
- 개발중캐시삭제
- html
- 런타임에러
- c#
- 캐시삭제
- html꿀팁
- 프론트엔드개발자
- 선언적트랜잭션 #noRollbackFor #@Transactional
- boj
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |