From 6b63b7185af4e148b613cc919fa93a573043048a Mon Sep 17 00:00:00 2001 From: KNKIM Date: Fri, 3 Dec 2021 18:01:52 +0900 Subject: [PATCH] =?UTF-8?q?CSRF=20=EC=B6=94=EA=B0=80=20=ED=99=95=EC=9E=A5?= =?UTF-8?q?=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/nlib/cmm/NlibCommonController.java | 16 +++++ .../java/nlib/col/web/CartController.java | 4 ++ .../java/nlib/col/web/ReadController.java | 43 +++++++++--- .../java/nlib/col/web/RentController.java | 42 ++++++++++-- .../java/nlib/user/web/LoginController.java | 2 +- .../WEB-INF/jsp/nlib/cart/listCartItems.jsp | 67 ++++++++----------- .../WEB-INF/jsp/nlib/read/confirmRead.jsp | 1 + .../WEB-INF/jsp/nlib/read/listReadItems.jsp | 9 +-- .../WEB-INF/jsp/nlib/rent/confirmRent.jsp | 6 +- .../WEB-INF/jsp/nlib/rent/listRentItems.jsp | 3 +- src/main/webapp/js/nlib.js | 58 ++-------------- 11 files changed, 135 insertions(+), 116 deletions(-) diff --git a/src/main/java/nlib/cmm/NlibCommonController.java b/src/main/java/nlib/cmm/NlibCommonController.java index 7c26a9c9..2bdc188c 100644 --- a/src/main/java/nlib/cmm/NlibCommonController.java +++ b/src/main/java/nlib/cmm/NlibCommonController.java @@ -333,6 +333,22 @@ public class NlibCommonController { return redirectAttrs; } + + + public String addParamsToUrl(String url, String paramName, String paramValue) { + + if(StringUtil.isEmpty(url)) return null; + if(StringUtil.isEmpty(paramName)) return url; + + String newUrl = url; + + if(url.contains("?")) newUrl += "&"; + else newUrl += "?"; + + newUrl += paramName + "=" + StringUtil.getString(paramValue, "").trim(); + + return newUrl; + } /** * paramMap에 이전 요청에서 전달할 때 추가한 POST방식의 매개변수값을 paramMap에 추가한다. diff --git a/src/main/java/nlib/col/web/CartController.java b/src/main/java/nlib/col/web/CartController.java index 70ccab41..9d561dbf 100644 --- a/src/main/java/nlib/col/web/CartController.java +++ b/src/main/java/nlib/col/web/CartController.java @@ -117,6 +117,10 @@ public class CartController extends NlibCommonController message = StringUtil.decodeUrl(message); } + // CSRF 토큰 생성 + String token = generateCsrfToken(request); + model.addAttribute("csrfToken", token); + model.addAttribute("cartTypeCd1Cnt", cartTypeCd1Cnt); model.addAttribute("cartTypeCd2Cnt", cartTypeCd2Cnt); diff --git a/src/main/java/nlib/col/web/ReadController.java b/src/main/java/nlib/col/web/ReadController.java index 2faf1001..824a809a 100644 --- a/src/main/java/nlib/col/web/ReadController.java +++ b/src/main/java/nlib/col/web/ReadController.java @@ -70,7 +70,7 @@ public class ReadController extends NlibCommonController { */ @Secured("ROLE_USER") @RequestMapping(value={"/read/confirmReadFromCart.do", "/read/confirmRead.do"}) - public String confirmRent(HttpServletRequest request, CollectionVO readVO, String csrfToken, ModelMap model) throws Exception { + public String confirmRead(HttpServletRequest request, CollectionVO readVO, String csrfToken, String fromPage, ModelMap model) throws Exception { String retJsp = "nlib/read/confirmRead"; boolean fromCart = request.getServletPath().contains("Cart.do"); @@ -82,17 +82,26 @@ public class ReadController extends NlibCommonController { return retJsp; } - if(!fromCart && !isValidCsrfToken(request, csrfToken)) { - model.addAttribute("message", "잘못된 접근입니다."); - return retJsp; + if(!isValidCsrfToken(request, csrfToken)) { + if(fromCart && StringUtil.getString(fromPage, "").equalsIgnoreCase("login")) { + // 비로그인자의 카트에서 신청을 실행하여 로그인 후 신청 진입으로 돌아온 경우 + return "redirect:/cart/listCartItems.do?cartTypeCd=2"; + } else { + model.addAttribute("message", "잘못된 접근입니다."); + return retJsp; + } } if(readVO == null || StringUtil.isEmpty(readVO.getSelItems())) { - model.addAttribute("message", "대출(예약)신청할 정보가 없습니다."); - return retJsp; + if(fromCart && StringUtil.getString(fromPage, "").equalsIgnoreCase("login")) { + // 비로그인자의 카트에서 신청을 실행하여 로그인 후 신청 진입으로 돌아온 경우 + return "redirect:/cart/listCartItems.do"; + } else { + model.addAttribute("message", "신청할 정보가 없습니다."); + return "nlib/read/confirmRead"; + } } - String selItems = readVO.getSelItems(); List list = collectionService.makeInfoListOfCollectionVO(selItems, mbInfoId); @@ -103,6 +112,10 @@ public class ReadController extends NlibCommonController { readVO.setMngOrgNm(list.get(0).getMngOrgNm()); } + // CSRF 토큰 생성 + String token = generateCsrfToken(request); + model.addAttribute("csrfToken", token); + model.addAttribute("readVO", readVO); model.addAttribute("list", list); model.addAttribute("listDates", listDates); @@ -122,7 +135,7 @@ public class ReadController extends NlibCommonController { */ @Secured("ROLE_USER") @RequestMapping(value={"/read/insertReadItemsFromCart.do", "/read/insertReadItems.do"}) - public String insertReadItems(HttpServletRequest request, CollectionVO readVO, ModelMap model) throws Exception { + public String insertReadItems(HttpServletRequest request, CollectionVO readVO, String csrfToken, ModelMap model) throws Exception { boolean fromCart = request.getServletPath().contains("Cart.do"); String retJsp = "nlib/read/insertReadItems"; @@ -133,6 +146,11 @@ public class ReadController extends NlibCommonController { return retJsp; } + if(!isValidCsrfToken(request, csrfToken)) { + model.addAttribute("message", "잘못된 접근입니다."); + return retJsp; + } + if(readVO == null || StringUtil.isEmpty(readVO.getSelItems())) { model.addAttribute("message", "대출(예약)신청할 정보가 없습니다."); return retJsp; @@ -196,6 +214,10 @@ public class ReadController extends NlibCommonController { return "nlib/read/listReadItems"; } + // CSRF 토큰 생성 + String token = generateCsrfToken(request); + model.addAttribute("csrfToken", token); + // 대출자료 문화원 목록 조회 List> readMngOrgList = readService.listReadMngOrg(mbInfoId); model.addAttribute("rentMngOrgList" , readMngOrgList); @@ -273,6 +295,7 @@ public class ReadController extends NlibCommonController { @RequestMapping(value="/read/cancelReadItemAjax.do") public ResponseEntity cancelReadItemAjax ( HttpServletRequest request, + String csrfToken, @RequestBody CollectionVO searchVO) { String resultMessage = null; @@ -284,6 +307,10 @@ public class ReadController extends NlibCommonController { resultMessage = "로그인하신 후, 이용바랍니다."; } + if(!isValidCsrfToken(request, csrfToken)) { + resultMessage = "잘못된 접근입니다."; + } + if(resultMessage != null && StringUtil.isEmpty(searchVO.getMngOrgCd())) { resultMessage = "문화원정보가 부적합합니다. 다시 요청하여 주시기 바랍니다."; } diff --git a/src/main/java/nlib/col/web/RentController.java b/src/main/java/nlib/col/web/RentController.java index c723e23c..a47f1c8f 100644 --- a/src/main/java/nlib/col/web/RentController.java +++ b/src/main/java/nlib/col/web/RentController.java @@ -98,6 +98,10 @@ public class RentController extends NlibCommonController List> rentMngOrgList = rentService.listRentMngOrg(mbInfoId); model.addAttribute("rentMngOrgList" , rentMngOrgList); + // CSRF 토큰 생성 + String token = generateCsrfToken(request); + model.addAttribute("csrfToken", token); + model.addAttribute("bookLtRvStatusCd", StringUtil.getString(searchVO.getBookLtRvStatusCd(), "A")); model.addAttribute("pageSize" , searchVO.getPageSize()); model.addAttribute("pageIndex" , searchVO.getPageIndex()); @@ -171,6 +175,7 @@ public class RentController extends NlibCommonController @RequestMapping(value="/rent/cancelRentItemAjax.do") public ResponseEntity cancelRentItemAjax( HttpServletRequest request, + String csrfToken, @RequestBody CollectionVO searchVO) { String resultMessage = null; @@ -181,6 +186,10 @@ public class RentController extends NlibCommonController if(StringUtil.isEmpty(mbInfoId)) { resultMessage = "로그인하신 후, 이용바랍니다."; } + + if(!isValidCsrfToken(request, csrfToken)) { + resultMessage = "잘못된 접근입니다."; + } if(StringUtil.isEmpty(searchVO.getMngOrgCd())) { resultMessage = "문화원정보가 부적합합니다. 다시 요청하여 주시기 바랍니다."; @@ -218,7 +227,7 @@ public class RentController extends NlibCommonController @Secured("ROLE_USER") @RequestMapping(value={"/rent/confirmRentFromCart.do", "/rent/confirmRent.do"}) - public String confirmRent(HttpServletRequest request, CollectionVO rentVO, ModelMap model, String csrfToken) throws Exception { + public String confirmRent(HttpServletRequest request, CollectionVO rentVO, ModelMap model, String csrfToken, String fromPage) throws Exception { boolean fromCart = request.getServletPath().contains("Cart.do"); @@ -229,14 +238,24 @@ public class RentController extends NlibCommonController return "nlib/rent/confirmRent"; } - if(!fromCart && !isValidCsrfToken(request, csrfToken)) { - model.addAttribute("message", "잘못된 접근입니다."); - return "nlib/rent/confirmRent"; + if(!isValidCsrfToken(request, csrfToken)) { + if(fromCart && StringUtil.getString(fromPage, "").equalsIgnoreCase("login")) { + // 비로그인자의 카트에서 신청을 실행하여 로그인 후 신청 진입으로 돌아온 경우 + return "redirect:/cart/listCartItems.do"; + } else { + model.addAttribute("message", "잘못된 접근입니다."); + return "nlib/rent/confirmRent"; + } } if(rentVO == null || StringUtil.isEmpty(rentVO.getSelItems())) { - model.addAttribute("message", "대출(예약)신청할 정보가 없습니다."); - return "nlib/rent/confirmRent"; + if(fromCart && StringUtil.getString(fromPage, "").equalsIgnoreCase("login")) { + // 비로그인자의 카트에서 신청을 실행하여 로그인 후 신청 진입으로 돌아온 경우 + return "redirect:/cart/listCartItems.do"; + } else { + model.addAttribute("message", "대출(예약)신청할 정보가 없습니다."); + return "nlib/rent/confirmRent"; + } } String selItems = rentVO.getSelItems(); @@ -248,6 +267,10 @@ public class RentController extends NlibCommonController rentVO.setMngOrgNm(list.get(0).getMngOrgNm()); } + // CSRF 토큰 생성 + String token = generateCsrfToken(request); + model.addAttribute("csrfToken", token); + model.addAttribute("rentVO", rentVO); model.addAttribute("list", list); if(fromCart) model.addAttribute("fromCart", fromCart ? "Y" : "N"); @@ -257,7 +280,7 @@ public class RentController extends NlibCommonController @Secured("ROLE_USER") @RequestMapping(value={"/rent/insertRentItemsFromCart.do", "/rent/insertRentItems.do"}) - public String insertRentItems(HttpServletRequest request, CollectionVO rentVO, ModelMap model) throws Exception { + public String insertRentItems(HttpServletRequest request, CollectionVO rentVO, String csrfToken, ModelMap model) throws Exception { boolean fromCart = request.getServletPath().contains("Cart.do"); String retJsp = "nlib/rent/insertRentItems"; @@ -268,6 +291,11 @@ public class RentController extends NlibCommonController return retJsp; } + if(!isValidCsrfToken(request, csrfToken)) { + model.addAttribute("message", "잘못된 접근입니다."); + return retJsp; + } + if(rentVO == null || StringUtil.isEmpty(rentVO.getSelItems())) { model.addAttribute("message", "대출(예약)신청할 정보가 없습니다."); return retJsp; diff --git a/src/main/java/nlib/user/web/LoginController.java b/src/main/java/nlib/user/web/LoginController.java index e15325e6..2941d8e9 100644 --- a/src/main/java/nlib/user/web/LoginController.java +++ b/src/main/java/nlib/user/web/LoginController.java @@ -535,7 +535,7 @@ public class LoginController extends NlibCommonController { cartService.mergeCart(mbInfoId, request, response); SessionConfig.removeLoginInfo(jsessionId); // 세션에 설정된 redirect 주소 확인 - return "redirect:" + councilReturnUrl; + return "redirect:" + addParamsToUrl(councilReturnUrl, "fromPage", "login"); } // 휴면계좌 diff --git a/src/main/webapp/WEB-INF/jsp/nlib/cart/listCartItems.jsp b/src/main/webapp/WEB-INF/jsp/nlib/cart/listCartItems.jsp index ceb7915e..9530cc71 100644 --- a/src/main/webapp/WEB-INF/jsp/nlib/cart/listCartItems.jsp +++ b/src/main/webapp/WEB-INF/jsp/nlib/cart/listCartItems.jsp @@ -184,52 +184,40 @@ function fn_changeCartItems(cartTypeCd, cartTypeNm) { // 대출신청으로 이동 function fn_appRent() { - - alert("먼저 로그인하신 후, 이용해 주시기 바랍니다."); - - - - if($("[id^=chk_item_]:checked").length < 1) { - alert("선택된 자료가 없습니다."); - return; - } - - if(fn_verifyCheckedCartItems("ableRentNow") > 0) { - alert("대출신청/예약불가 상태의 자료가 포함되어 있습니다.") - return; - }; - - $("#selItems").val(fn_getCheckedCartItemsValues()); - $("#frm").attr("action","${pageContext.request.contextPath}/rent/confirmRentFromCart.do"); - - $("#frm").submit(); - + if($("[id^=chk_item_]:checked").length < 1) { + alert("선택된 자료가 없습니다."); + return; + } + + if(fn_verifyCheckedCartItems("ableRentNow") > 0) { + alert("대출신청/예약불가 상태의 자료가 포함되어 있습니다.") + return; + }; + + $("#selItems").val(fn_getCheckedCartItemsValues()); + $("#frm").attr("action","${pageContext.request.contextPath}/rent/confirmRentFromCart.do"); + + $("#frm").submit(); } // 열람신청으로 이동 function fn_appRead() { - - alert("먼저 로그인하신 후, 이용해 주시기 바랍니다."); - - - - if($("[id^=chk_item_]:checked").length < 1) { - alert("방문열람할 대상을 선택해 주세요."); - return; - } + if($("[id^=chk_item_]:checked").length < 1) { + alert("방문열람할 대상을 선택해 주세요."); + return; + } - if(fn_verifyCheckedCartItems("ableReadNow") > 0) { - alert("신청불가 상태의 자료가 포함되어 있습니다.") - return; - }; - - $("#selItems").val(fn_getCheckedCartItemsValues()); - $("#frm").attr("action","${pageContext.request.contextPath}/read/confirmReadFromCart.do"); - - $("#frm").submit(); - + if(fn_verifyCheckedCartItems("ableReadNow") > 0) { + alert("신청불가 상태의 자료가 포함되어 있습니다.") + return; + }; + + $("#selItems").val(fn_getCheckedCartItemsValues()); + $("#frm").attr("action","${pageContext.request.contextPath}/read/confirmReadFromCart.do"); + + $("#frm").submit(); } @@ -262,6 +250,7 @@ $(document).ready(function() { +
diff --git a/src/main/webapp/WEB-INF/jsp/nlib/read/confirmRead.jsp b/src/main/webapp/WEB-INF/jsp/nlib/read/confirmRead.jsp index d9746d5a..894b6d5e 100644 --- a/src/main/webapp/WEB-INF/jsp/nlib/read/confirmRead.jsp +++ b/src/main/webapp/WEB-INF/jsp/nlib/read/confirmRead.jsp @@ -167,6 +167,7 @@ $(document).ready(function() { +
diff --git a/src/main/webapp/WEB-INF/jsp/nlib/read/listReadItems.jsp b/src/main/webapp/WEB-INF/jsp/nlib/read/listReadItems.jsp index b34cfad4..d342604a 100644 --- a/src/main/webapp/WEB-INF/jsp/nlib/read/listReadItems.jsp +++ b/src/main/webapp/WEB-INF/jsp/nlib/read/listReadItems.jsp @@ -184,7 +184,7 @@ function fn_search(reqStatusDivCd) { if(!confirm(title + " 방문열람을 취소하시겠습니까?")) return; - var reqUrl = "${pageContext.request.contextPath}/read/cancelReadItemAjax.do"; + var reqUrl = "${pageContext.request.contextPath}/read/cancelReadItemAjax.do?csrfToken=" + $("#csrfToken").val(); var inputData = { "mngOrgCd" : mngOrgCd @@ -245,9 +245,10 @@ function fn_search(reqStatusDivCd) {
- - - + + + +
    diff --git a/src/main/webapp/WEB-INF/jsp/nlib/rent/confirmRent.jsp b/src/main/webapp/WEB-INF/jsp/nlib/rent/confirmRent.jsp index f0cff3a1..b3ecedf5 100644 --- a/src/main/webapp/WEB-INF/jsp/nlib/rent/confirmRent.jsp +++ b/src/main/webapp/WEB-INF/jsp/nlib/rent/confirmRent.jsp @@ -148,9 +148,9 @@ $(document).ready(function() { - - - + + +
    diff --git a/src/main/webapp/WEB-INF/jsp/nlib/rent/listRentItems.jsp b/src/main/webapp/WEB-INF/jsp/nlib/rent/listRentItems.jsp index f1be9f89..10759e8b 100644 --- a/src/main/webapp/WEB-INF/jsp/nlib/rent/listRentItems.jsp +++ b/src/main/webapp/WEB-INF/jsp/nlib/rent/listRentItems.jsp @@ -165,7 +165,7 @@ function fn_search(bookLtRvStatusCd) { if(!confirm(title + " " + bookLtRvStatusNm + "을 취소하시겠습니까?")) return; - var reqUrl = "${pageContext.request.contextPath}/rent/cancelRentItemAjax.do"; + var reqUrl = "${pageContext.request.contextPath}/rent/cancelRentItemAjax.do?csrfToken=" + $("#csrfToken").val(); var inputData = { "mngOrgCd" : mngOrgCd @@ -228,6 +228,7 @@ function fn_search(bookLtRvStatusCd) { +
      diff --git a/src/main/webapp/js/nlib.js b/src/main/webapp/js/nlib.js index c3b0e922..798841b6 100644 --- a/src/main/webapp/js/nlib.js +++ b/src/main/webapp/js/nlib.js @@ -515,32 +515,8 @@ function gfn_rentItem(mngOrgCd, masterId, token) { return; } - var form = document.createElement("form"); - form.style.display = "none"; - $(form).attr("action", "/rent/confirmRent.do"); - $(form).attr("method", "post"); - $(form).attr("target", "_blank"); - - var element1 = document.createElement("input"); - $(element1).attr("name", "mngOrgCd"); - $(element1).attr("value", mngOrgCd); - - var element2 = document.createElement("input"); - $(element2).attr("name", "selItems"); - $(element2).attr("value", masterId); - - var element3 = document.createElement("input"); - $(element3).attr("name", "csrfToken"); - $(element3).attr("value", token); - - form.appendChild(element1); - form.appendChild(element2); - form.appendChild(element3); - - document.body.appendChild(form); - form.submit(); - - document.body.removeChild(form); + var url = "/rent/confirmRent.do?mngOrgCd=" + mngOrgCd + "&selItems=" + masterId + "&csrfToken=" + token; + gfn_openNewWindow(url); return; } @@ -556,33 +532,9 @@ function gfn_reserveReadItem(mngOrgCd, masterId, token) { alert("잘못된 접근입니다."); return; } - - var form = document.createElement("form"); - form.style.display = "none"; - $(form).attr("action", "/read/confirmRead.do"); - $(form).attr("method", "post"); - $(form).attr("target", "_blank"); - - var element1 = document.createElement("input"); - $(element1).attr("name", "mngOrgCd"); - $(element1).attr("value", mngOrgCd); - - var element2 = document.createElement("input"); - $(element2).attr("name", "selItems"); - $(element2).attr("value", masterId); - - var element3 = document.createElement("input"); - $(element3).attr("name", "csrfToken"); - $(element3).attr("value", token); - - form.appendChild(element1); - form.appendChild(element2); - form.appendChild(element3); - - document.body.appendChild(form); - form.submit(); - - document.body.removeChild(form); + + var url = "/read/confirmRead.do?mngOrgCd=" + mngOrgCd + "&selItems=" + masterId + "&csrfToken=" + token; + gfn_openNewWindow(url); return; }