/** * ******************************************************************************** * 프로그램명 : HttpFileUploadDir.java 작 성 자 : 강원중 작 성 일 : 2003. 7.23 최신변경일 : 2013. * 1.11 ********************************************************************************** */ package kr.co.kihyun.beans.totsys.board; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.URLEncoder; import java.util.Arrays; import javax.jdo.PersistenceManager; import javax.jdo.Transaction; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import kr.co.kihyun.beans.entity.TotReport; import kr.co.kihyun.beans.entity.util.PMF; import kr.co.kihyun.beans.user.HttpSSOLogin; import kr.co.kihyun.db.CommonDBManager; import kr.co.kihyun.io.FileUtil; import kr.co.kihyun.io.MultipartRequest; import kr.co.kihyun.lang.MInteger; import kr.co.kihyun.lang.MLong; import kr.co.kihyun.lang.MString; import kr.co.kihyun.moumi.MoumiConfig; //import kr.co.kihyun.text.html.ServletUtil; import kr.co.kihyun.util.MRandom; import org.apache.commons.fileupload.FileItem; import org.apache.commons.io.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @WebServlet("/servlet/kr.co.kihyun.beans.totsys.board.HttpFileUploadDir") public class HttpFileUploadDir extends HttpServlet { /** * */ private static final long serialVersionUID = 1L; private static final Logger LOG = LoggerFactory.getLogger(HttpFileUploadDir.class); @Override public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/html;charset=UTF-8"); MultipartRequest multi = null; String svrFilename = ""; String usrFilename = ""; String boardGroupID = ""; String connURL = ""; String mode = ""; String usID = HttpSSOLogin.getLoginID(req); // String dtID = HttpSSOLogin.getDeptID(req); String dtID = ""; Long docID = null; String reportID = null; String boardID = ""; String msg = ""; String maxSize = "3"; String checkSize = ""; boolean isExtNullOk = true; //7.+++ boolean isExtFileOk = true; //7.+++ boolean isDirectoryOk = true; //3.+++ Long currentFileSize = 0L; // 업로드할 파일의 크기(byte)를 저장할 변수. 2014.09.02 by youngjun cho. Long accumulateFileSize = 0L; // 업로드된 파일들의 총 누적 크기(byte)를 저장할 변수. 2014.09.02 by youngjun cho. CommonDBManager acdbm1=new CommonDBManager(); PersistenceManager pm = PMF.get().getPersistenceManager(); Transaction tx = pm.currentTransaction(); try { maxSize = req.getParameter("maxSize"); if (maxSize == null || maxSize.equals("")) { maxSize = "10"; } int tmpSize = Integer.parseInt(maxSize) * 1024 * 1024; //사이즈를 정해준다. checkSize = String.valueOf(tmpSize); multi = new MultipartRequest(req, tmpSize); mode = MString.checkNull(multi.getParameter("mode")); boardGroupID = multi.getParameter("boardGroupID"); usrFilename = multi.getParameter("appendFile"); //20170818 파일 검사수행 이전으로 옮김 by wonseok Lee. false 리턴시 첨부파일 관련 아래의 ID들을 이전페이지로 전달키 위해서임 docID = MLong.parseLong(multi.getParameter("docID")); reportID = MString.checkNull(multi.getParameter("reportID")); boardID = MString.checkNull(multi.getParameter("boardID")); dtID = MString.checkNull(multi.getParameter("dtID")); //7.위험한 형식 파일 업로드(MultipartRequest)_CWE-434 : Add by KWON,HAN int extIndex = 0 ; extIndex = usrFilename.lastIndexOf('.'); if(extIndex < 0 ) { //LOG.debug("7.위험한 형식 파일 업로드(MultipartRequest)_CWE-434 : Not Test / usrFilename: {}", usrFilename); isExtNullOk = false; //out.print(""); return; } //v2 22.정수형 오버플로우_CWE-190 : Update by YOUNGJUN,CHO if (extIndex < Integer.MAX_VALUE) { //String file_ext = usrFilename.substring(usrFilename.lastIndexOf('.') + 1); String file_ext = usrFilename.substring(extIndex + 1); if( file_ext.equalsIgnoreCase("exe") || file_ext.equalsIgnoreCase("bat") || file_ext.equalsIgnoreCase("sh") ) { //LOG.debug("7.위험한 형식 파일 업로드(MultipartRequest)_CWE-434 : Not Test / usrFilename: {}", usrFilename); //out.print(""); isExtFileOk = false; return; } } else { //LOG.debug("v2 22.정수형 오버플로우_CWE-190 : Not Test / usrFilename: {}", usrFilename); //out.print(""); isExtFileOk = false; return; } //================================================ v2 22.정수형 오버플로우_CWE-190 : Update by YOUNGJUN,CHO //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 7.위험한 형식 파일 업로드(MultipartRequest)_CWE-434 : Add by KWON,HAN // 2014.09.02 by youngjun cho. // 업로드된 파일들의 총 누적 크기(byte)를 jsp 의 hidden value 에 저장 후 파라미터로 받아온다. //accumulateFileSize = MLong.parseLong(multi.getParameter("accumulateFileSize")); //LOG.debug("docID: {}, boardID: {}, mode: {}", new Object[] {docID, boardID, mode}); if (!MString.isNull(usrFilename)) { String[] usrFilenamePath = usrFilename.split("\\\\"); usrFilename = usrFilenamePath[usrFilenamePath.length - 1]; String imsi = ""; // String[] filter_word = {" ", "\\?", "\\/", "\\~", "\\!", "\\@", "\\#", "\\$", "\\%", "\\^", "\\&", "\\*", "\\(", "\\)", "\\+", "\\=", "\\|", "\\\\", "\\}", "\\]", "\\{", "\\[", "\\\"", "\\'", "\\:", "\\;", "\\<", "\\,", "\\>", "\\?", "\\/"}; String[] filter_word = {"\\?","\\/","\\~","\\!","\\@","\\#","\\$","\\%","\\^","\\&","\\*","\\+","\\=","\\|","\\\\","\\\"","\\'","\\:","\\;","\\,"}; for (int ii = 0; ii < filter_word.length; ii++) { imsi = usrFilename.replaceAll(filter_word[ii], "_"); usrFilename = imsi; } LOG.debug("usrFilename: {}", usrFilename); } File path; //svrFilename = FileUtil.getName(usrFilename, Integer.toString(MRandom.getInt(100))); //두자리의 랜덤 수치를 얻음 if (docID != null) { path = MoumiConfig.getFileDirectory(); LOG.debug("MoumiConfig.getFileDirectory(): " + MoumiConfig.getFileDirectory()); } else if (reportID != null) { path = MoumiConfig.getFileDirectory(); LOG.debug("MoumiConfig.getFileDirectory(): " + MoumiConfig.getFileDirectory()); // } else if (!MString.isNull(boardID)) { // path = new File(MoumiConfig.getBoardFileRoot(), boardID.toString()); // LOG.debug("MoumiConfig.getBoardFileRoot(): " + MoumiConfig.getBoardFileRoot()); } else if ("csv".equals(mode)) { path = MoumiConfig.getCsvFileRoot(); LOG.debug("MoumiConfig.getCsvFileRoot(): " + MoumiConfig.getCsvFileRoot()); } else { path = MoumiConfig.getFileDirectory(); LOG.debug("MoumiConfig.getFileDirectory(): " + MoumiConfig.getFileDirectory()); } LOG.debug("passLine: {}"); //20170809_02 by wonseok Lee. 접수자료 > 자료입력 > 파일제출시 파일 업로드 수정, 파일직접 다운로드를 위해 업로드하는 파일을 MoumiConfig.getFileDirectory()2/DOCID/REPORTID/DeptID 디렉토리에 저장한다. if(mode.equals("repoper")) { svrFilename = usrFilename; LOG.debug("Long.toString(docID): {}",Long.toString(docID)); LOG.debug("Long.toString(reportID): {}",reportID); LOG.debug("Long.toString(dtID): {}",dtID); path = new File(MoumiConfig.getFileDirectory()+"/"+Long.toString(docID)+"/"+reportID+"/"+dtID); } LOG.debug("passLine: {}"); if (!path.isDirectory()) { if (!path.mkdirs()) { throw new ServletException(path + " is not a directory."); } } accumulateFileSize = FileUtils.sizeOfDirectory(path); FileItem upFile = multi.getFileItem("appendFile"); LOG.debug("UPFILE: {}", upFile); // 업로드할 파일의 크기를 구한다. (2014.09.02 by youngjun cho.) currentFileSize = upFile.getSize(); LOG.debug("UPFILE currentFileSize : {}", currentFileSize); accumulateFileSize = accumulateFileSize + currentFileSize; LOG.debug("passLine: {}"); LOG.debug("accumulateFileSize : {}"+ accumulateFileSize); // 제한용량 이상이면 "-66" 을 리턴한다. (2014.09.02 by youngjun cho.) //if (tmpSize <= accumulateFileSize) { if (accumulateFileSize > 3096000) { //(20170817 by wonseok Lee.) maxSize를 1로하고 1MB 이상의 첨부파일을 첨부하면 다음 exception 발생함=>org.apache.commons.fileupload.FileUploadBase$FileSizeLimitExceededException: msg = "-66"; return; } //3.디렉토리 경로 조작(getParameter)_CWE-22/23/36 : Add by KWON,HAN LOG.debug("svrFilename: {}", svrFilename); if(svrFilename.contains("..") || svrFilename. contains("/")) { // 특수문자열 검증 //LOG.debug("3.디렉토리 경로 조작(getParameter)_CWE-22/23/36 : Test OK {}", svrFilename); isDirectoryOk = false; return; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //20170814 if문 추가 by wonseok Lee. 업로드 파일이 중복이면 삭제하고 write. if(mode.equals("repoper")) { File existFile = new File(path+"/"+svrFilename); if(existFile.isFile()) { existFile.delete(); } } File attachFile = new File(path, svrFilename); LOG.debug("path writed to attachFile: {}/{}", attachFile); upFile.write(attachFile); LOG.debug("UPFILE writed to svrFilename: {}/{}", path, svrFilename); // ** 첨부파일을 DB에 저장하는 기능 ** // * 파일서버 경로에 저장하도록 개선하여 사용하지 않도록 주석 처리 17.12.14 jskim // tx.begin(); // TotReport totReport = pm.getObjectById(TotReport.class, Long.parseLong(reportID)); // // FileInputStream fis1 = null; // try { // // byte[] content1 = new byte[(int)attachFile.length()]; // Byte[] contentObj1 = new Byte[content1.length]; // // fis1 = new FileInputStream(attachFile); // fis1.read(content1);//파일의 내용을 읽어온다. // // for (int i = 0; i < content1.length; i++) { // contentObj1[i] = content1[i]; // } // // totReport.addAttachment(svrFilename, Arrays.asList(contentObj1)); //파일명과 내용을 HashMap에 입력 한다. // pm.makePersistent(totReport); // content1 = null; // contentObj1 = null; // tx.commit(); // // }catch(IOException e){ // e.printStackTrace(); // }finally{ // fis1.close(); // } StringBuilder sql = new StringBuilder(250); sql.delete(0, sql.length()); sql.append("UPDATE MOUMI_TOT_REPORT SET ATTACHMENTS_PATH = ATTACHMENTS_PATH|| ? WHERE ID = ? "); acdbm1.execUpdate(sql.toString(), svrFilename+";", reportID); acdbm1.pstmt.close(); sql.delete(0, sql.length()); sql.append("UPDATE MOUMI_TOT_REPORT_VERSION SET ATTACHMENTS_PATH = ATTACHMENTS_PATH|| ? WHERE REPORT_ID = ? AND ID=(SELECT MAX(ID) FROM MOUMI_TOT_REPORT_VERSION WHERE DEL_TYPE = 'N' AND REPORT_ID = ? )"); acdbm1.execUpdate(sql.toString(), svrFilename+";", reportID, reportID); acdbm1.pstmt.close(); acdbm1.commit(); svrFilename = URLEncoder.encode(svrFilename, "UTF-8"); usrFilename = URLEncoder.encode(usrFilename, "UTF-8"); } catch (Exception ex) { ex.printStackTrace(); if (tx.isActive()) tx.rollback(); acdbm1.rollback(); msg = ex.getMessage(); if (msg.indexOf(checkSize) > 0) { msg = "-99"; } else { msg = "-88"; } } finally { pm.close(); acdbm1.execClose(); connURL = "/totsys/common/inc/board/doc/write_file_upload_dir.jsp?execMode=up&svrFilename=" + svrFilename + "&usrFilename=" + usrFilename + "&boardGroupID=" + boardGroupID + "&docID=" + docID + "&reportID=" + reportID+ "&dtID=" + dtID + "&boardID=" + boardID + "&mode=" + mode + "&MSG=" + msg + "&maxSize=" + maxSize + "¤tFileSize=" + currentFileSize; if (connURL.length() > 2047) { msg = "-77"; } if(!isExtNullOk) { msg="-33"; } //7.+++ if(!isExtFileOk) { msg="-55"; } //7.+++ if(!isDirectoryOk) { msg="-44"; } //3.+++ if (!msg.equals("")) { svrFilename = ""; usrFilename = ""; currentFileSize = 0L; // 에러인 경우 파일이 업로드되지 않으므로 파일 크기를 0으로 리턴한다. (2014.09.02 by youngjun cho.) } if (svrFilename != null || usrFilename != null) { String filtered_svrFilename = svrFilename.replaceAll("\r","").replaceAll("\n",""); String filtered_usrFilename = usrFilename.replaceAll("\r","").replaceAll("\n",""); String allowURL[] = { "/totsys/common/inc/board/doc/write_file_upload_dir.jsp" }; connURL = allowURL[0] + "?execMode=up&svrFilename=" + filtered_svrFilename + "&usrFilename=" + filtered_usrFilename + "&boardGroupID=" + boardGroupID + "&docID=" + docID + "&reportID=" + reportID+ "&dtID=" + dtID + "&boardID=" + boardID + "&mode=" + mode + "&MSG=" + msg + "&maxSize=" + maxSize + "¤tFileSize=" + currentFileSize; LOG.debug("v2 3.신뢰되지 않는 URL 주소로 자동 접속 연결_CWE-601 : HttpFileUploadDir.doPost() connURL={} : Test OK", connURL); //========================================================================= } //======================================== res.sendRedirect(connURL); } } }