This commit is contained in:
com02 2021-12-02 16:07:30 +09:00
commit d42aa5fed5
6 changed files with 93 additions and 28 deletions

View File

@ -29,6 +29,7 @@ import nlib.security.SecUserVO;
import nlib.user.service.LoginService;
import nlib.user.service.NlibLoginVO;
import nlib.util.StringUtil;
import nlib.util.UUID;
/**
* <pre>
@ -404,4 +405,39 @@ public class NlibCommonController {
return StringUtil.isEmpty(value) ? defValue : value;
}
/**
* 세션에 CSRF 방지를 위한 토큰을 생성한다.
*
* @param request
*/
public final static String SESSION_CSRF_TOKEN_NAME = "SESSION_CSRF_TOKEN";
public String generateCsrfToken(HttpServletRequest request) {
HttpSession session = request.getSession();
String token = UUID.getNewUUID();
session.setAttribute(SESSION_CSRF_TOKEN_NAME, token);
log.debug("generateCsrfToken > " + session.getAttribute(SESSION_CSRF_TOKEN_NAME));
return token;
}
/**
* 입력받은 CSRF 토큰이 유효한지 확인한다.
*
* @param request
* @param pToken
* @return
*/
public boolean isValidCsrfToken(HttpServletRequest request, String pToken) {
HttpSession session = request.getSession();
String sToken = (String)session.getAttribute(SESSION_CSRF_TOKEN_NAME);
if(request == null || StringUtil.isEmpty(pToken) || StringUtil.isEmpty(sToken)) return false;
if(sToken.equals(pToken)) return true;
return false;
}
}

View File

@ -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, ModelMap model) throws Exception {
public String confirmRent(HttpServletRequest request, CollectionVO readVO, String csrfToken, ModelMap model) throws Exception {
String retJsp = "nlib/read/confirmRead";
boolean fromCart = request.getServletPath().contains("Cart.do");
@ -82,11 +82,17 @@ public class ReadController extends NlibCommonController {
return retJsp;
}
if(!fromCart && !isValidCsrfToken(request, csrfToken)) {
model.addAttribute("message", "잘못된 접근입니다.");
return retJsp;
}
if(readVO == null || StringUtil.isEmpty(readVO.getSelItems())) {
model.addAttribute("message", "대출(예약)신청할 정보가 없습니다.");
return retJsp;
}
String selItems = readVO.getSelItems();
List<CollectionVO> list = collectionService.makeInfoListOfCollectionVO(selItems, mbInfoId);

View File

@ -218,7 +218,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) throws Exception {
public String confirmRent(HttpServletRequest request, CollectionVO rentVO, ModelMap model, String csrfToken) throws Exception {
boolean fromCart = request.getServletPath().contains("Cart.do");
@ -229,6 +229,11 @@ public class RentController extends NlibCommonController
return "nlib/rent/confirmRent";
}
if(!fromCart && !isValidCsrfToken(request, csrfToken)) {
model.addAttribute("message", "잘못된 접근입니다.");
return "nlib/rent/confirmRent";
}
if(rentVO == null || StringUtil.isEmpty(rentVO.getSelItems())) {
model.addAttribute("message", "대출(예약)신청할 정보가 없습니다.");
return "nlib/rent/confirmRent";

View File

@ -352,6 +352,12 @@ public class NlibSearchController extends NlibCommonController {
imagePath = StringUtil.getString(vo.getRprsThumbUrl(),"");
}
// CSRF 토큰 생성 (2021.12.02 KKN 추가)
String token = generateCsrfToken(request);
model.addAttribute("csrfToken", token);
log.debug("searchItemDetail > token=" + token);
log.debug("searchItemDetail > session token=" + session.getAttribute(SESSION_CSRF_TOKEN_NAME));
model.addAttribute("imageType",imageType);
model.addAttribute("imagePath",imagePath);
model.addAttribute("keywordList",keywordList);

View File

@ -1,3 +1,4 @@
<%@page import="nlib.cmm.NlibCommonController"%>
<%
/**
* <pre>
@ -35,6 +36,7 @@
<c:set var="pageTitle">${result.title}</c:set>
<script>
$(document).ready(function(){
fn_setPageTitle("${pageTitle}");
//로그
$.ajax({
@ -216,10 +218,10 @@ function goList(){
</ul>
</div>
<div class="b-btn">
<c:if test="${result.ableRentAppNow }"><button type="button" class="btn btn-color" title="새 창 열림" onclick="gfn_rentItem('${result.mngOrgCd}', '${result.masterId}')">대출신청</button></c:if>
<c:if test="${not result.ableRentAppNow and result.ableRentResNow }"><button type="button" class="btn btn-color" title="새 창 열림" onclick="gfn_rentItem('${result.mngOrgCd}', '${result.masterId}')">대출예약</button></c:if>
<c:if test="${result.ableRentAppNow }"><button type="button" class="btn btn-color" title="새 창 열림" onclick="gfn_rentItem('${result.mngOrgCd}', '${result.masterId}', '${csrfToken }')">대출신청</button></c:if>
<c:if test="${not result.ableRentAppNow and result.ableRentResNow }"><button type="button" class="btn btn-color" title="새 창 열림" onclick="gfn_rentItem('${result.mngOrgCd}', '${result.masterId}', '${csrfToken }')">대출예약</button></c:if>
<c:if test="${result.ableReadNow }"><button type="button" class="btn btn-green" title="새 창 열림" onclick="gfn_reserveReadItem('${result.mngOrgCd}', '${result.masterId}')">방문열람신청</button></c:if>
<c:if test="${result.ableReadNow }"><button type="button" class="btn btn-green" title="새 창 열림" onclick="gfn_reserveReadItem('${result.mngOrgCd}', '${result.masterId}', '${csrfToken }')">방문열람신청</button></c:if>
<c:if test="${result.ableRent or result.ableRead }">
<button type="button" class="btn btn-orange" onclick="gfn_addRentCart('${result.masterId}', '${result.ableRent}', '${result.ableRead}')">카트담기</button>

View File

@ -173,7 +173,6 @@ function gfn_showRis(risId){
document.getElementById("export-data").className="popup pop-user-set pop-export";
var html="";
html+='<form name="risDownloadForm" id="risDownloadForm" method="post"><input type="hidden" id="risId" name="risId"></form>';
html+='<div class="pop-serge">';
html+='<div class="row Title">';
html+=' <h3>서지정보 내보내기<span>(Export)</span></h3>';
@ -216,10 +215,13 @@ function gfn_focus(obj){
$("#"+obj).focus();
}
function gfn_downloadRis(risId){
$("#risId").val(risId);
document.risDownloadForm.action="/ris/downloadRis.do";
document.risDownloadForm.submit();
if(gfn_isEmpty(risId)) {
alert("잘못된 접근입니다.");
return;
}
gfn_gotoUrl("/ris/downloadRis.do?risId=" + risId);
}
function gfn_closeRis(risDownloadForm){
@ -494,36 +496,29 @@ function gfn_getDetail(masterId, host) {
if(gfn_isEmpty(host)) host = "";
else host = "https://" + host + ".nculture.org";
var form = document.createElement("form");
form.style.display = "none";
$(form).attr("action", host + "/search/searchItemDetail.do");
$(form).attr("method", "post");
$(form).attr("target", "_blank");
var element = document.createElement("input");
$(element).attr("name", "masterId");
$(element).attr("value", masterId);
form.appendChild(element);
document.body.appendChild(form);
form.submit();
document.body.removeChild(form);
var url = host + "/search/searchItemDetail.do?masterId=" + masterId;
gfn_openNewWindow(url);
return;
}
function gfn_rentItem(mngOrgCd, masterId) {
function gfn_rentItem(mngOrgCd, masterId, token) {
if(gfn_isEmpty(masterId)) {
alert("자료ID 정보가 없습니다.");
return;
}
if(gfn_isEmpty(token)) {
alert("잘못된 접근입니다.");
return;
}
var form = document.createElement("form");
form.style.display = "none";
$(form).attr("action", "/rent/confirmRent.do");
$(form).attr("method", "get");
$(form).attr("method", "post");
$(form).attr("target", "_blank");
var element1 = document.createElement("input");
@ -534,8 +529,13 @@ function gfn_rentItem(mngOrgCd, masterId) {
$(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();
@ -545,17 +545,22 @@ function gfn_rentItem(mngOrgCd, masterId) {
return;
}
function gfn_reserveReadItem(mngOrgCd, masterId) {
function gfn_reserveReadItem(mngOrgCd, masterId, token) {
if(gfn_isEmpty(masterId)) {
alert("자료ID 정보가 없습니다.");
return;
}
if(gfn_isEmpty(token)) {
alert("잘못된 접근입니다.");
return;
}
var form = document.createElement("form");
form.style.display = "none";
$(form).attr("action", "/read/confirmRead.do");
$(form).attr("method", "get");
$(form).attr("method", "post");
$(form).attr("target", "_blank");
var element1 = document.createElement("input");
@ -566,8 +571,13 @@ function gfn_reserveReadItem(mngOrgCd, masterId) {
$(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();