diff --git a/data/fileupload/bbs/qna/.gitignore b/data/fileupload/bbs/qna/.gitignore index eedfeaba..f861d22d 100644 --- a/data/fileupload/bbs/qna/.gitignore +++ b/data/fileupload/bbs/qna/.gitignore @@ -1,4 +1,4 @@ -/F20210716045132766_5A30C3D2F8AB44A6867D76329E4502E2 -/F20210716045132766_B48A0FCFBE2D46D290B31DDECB61DA9B -/F20210716045247870_C228F5BAD6894E66A50B48F63CA8916C -/F20210716045247870_E8D7EB4610604852982585486F9BAD5A +/* +!/F20210802052436092_0A84FA72B1B1478ABEB285536B81B587 +!/F20210802052436092_F1DB407F181A4B8AAA0859E56D4EDB57 + diff --git a/data/fileupload/bbs/qna/F20210802052436092_0A84FA72B1B1478ABEB285536B81B587 b/data/fileupload/bbs/qna/F20210802052436092_0A84FA72B1B1478ABEB285536B81B587 index be14bd8a..8eed248c 100644 Binary files a/data/fileupload/bbs/qna/F20210802052436092_0A84FA72B1B1478ABEB285536B81B587 and b/data/fileupload/bbs/qna/F20210802052436092_0A84FA72B1B1478ABEB285536B81B587 differ diff --git a/data/fileupload/bbs/qna/F20210802052436092_F1DB407F181A4B8AAA0859E56D4EDB57 b/data/fileupload/bbs/qna/F20210802052436092_F1DB407F181A4B8AAA0859E56D4EDB57 index be14bd8a..d852d8f3 100644 Binary files a/data/fileupload/bbs/qna/F20210802052436092_F1DB407F181A4B8AAA0859E56D4EDB57 and b/data/fileupload/bbs/qna/F20210802052436092_F1DB407F181A4B8AAA0859E56D4EDB57 differ diff --git a/data/fileupload/bbs/qna/F20210802052436092_F1F06656D13C451BA42E21B4028F3838 b/data/fileupload/bbs/qna/F20210802052436092_F1F06656D13C451BA42E21B4028F3838 deleted file mode 100644 index be14bd8a..00000000 Binary files a/data/fileupload/bbs/qna/F20210802052436092_F1F06656D13C451BA42E21B4028F3838 and /dev/null differ diff --git a/src/main/java/nlib/cmm/fileupload/DownloadView.java b/src/main/java/nlib/cmm/fileupload/DownloadView.java index 052ba1a9..fab3f7c7 100644 --- a/src/main/java/nlib/cmm/fileupload/DownloadView.java +++ b/src/main/java/nlib/cmm/fileupload/DownloadView.java @@ -23,27 +23,28 @@ public class DownloadView extends AbstractView { File file = (File)model.get("downloadFile"); if(file != null) { String fileName =(String)model.get("fname"); + String encfileName = null; String userAgent = request.getHeader("User-Agent"); if(userAgent.indexOf("MSIE") > -1 || userAgent.indexOf("Trident") > -1){ - //fileName = URLEncoder.encode(file.getName(), "utf-8").replaceAll("\\+", "%20");; + encfileName = URLEncoder.encode(fileName, "utf-8").replaceAll("\\+", "%20");; }else if(userAgent.indexOf("Chrome") > -1) { StringBuffer sb = new StringBuffer(); - for(int i=0; i '~') { sb.append(URLEncoder.encode(""+c, "UTF-8")); }else { sb.append(c); } } - //fileName = sb.toString(); + encfileName = sb.toString(); }else { - //fileName = new String(file.getName().getBytes("utf-8")); + encfileName = new String(fileName.getBytes("utf-8")); } response.setContentType(getContentType()); response.setContentLength((int)file.length()); - response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\";"); + response.setHeader("Content-Disposition", "attachment; filename=\"" + encfileName + "\";"); response.setHeader("Content-Transfer-Encoding", "binary"); OutputStream out = response.getOutputStream(); diff --git a/src/main/java/nlib/cmm/fileupload/FileUploadController.java b/src/main/java/nlib/cmm/fileupload/FileUploadController.java index e3501e34..a4e65e58 100644 --- a/src/main/java/nlib/cmm/fileupload/FileUploadController.java +++ b/src/main/java/nlib/cmm/fileupload/FileUploadController.java @@ -76,7 +76,22 @@ public class FileUploadController { * 첨부파일 임시 저장 위치 */ private String FILEUPLOAD_TEMP_SUBPATH = nlibProperty.getProperty("fileupload.temp.subpath"); + + /** + * 경로 부적합 오류 메시지 + */ + private static final String MSG_NOT_VALID_FILE_PATH = "파일 경로가 부적합합니다. 관리자에게 문의하여 주시기 바랍니다."; + + /** + * 파일업로드(Ajax) 처리 + * - 화면 : Javascript Free Open Framework DropZone 사용 + * + * @param multiRequest + * @param subPathKey + * @param response : 파일정보를 담은 JSON String + * @return + */ @ResponseBody @RequestMapping(value="/fileupload/uploadFilesAjax.do", produces="application/json") public ResponseEntity uploadFilesAjax( @@ -84,22 +99,47 @@ public class FileUploadController { , @RequestParam("subPathKey") String subPathKey , HttpServletResponse response) { - // TODO : 권한 체크 추가할 것 + String message = null; + // TODO : 권한 체크 추가할 것 List result = new ArrayList(); try { // 최상위 위치 - if(FileUtil.isNotValid(FILEUPLOAD_BASE_PATH)) throw new Exception("첨부파일이 저장되는 최상위 위치값이 적절하지 않습니다."); + if(FileUtil.isEmpty(FILEUPLOAD_BASE_PATH)) { + message = "첨부파일이 저장되는 최상위 위치정보값이 정확하지 않습니다."; + log.error(message + " : FILEUPLOAD_BASE_PATH 값 부재"); + ErrorMessage errorMessage = new ErrorMessage("ERROR", message); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorMessage); + } // 서브 위치 - if(StringUtil.isEmpty(subPathKey)) throw new Exception("첨부파일이 저장되는 위치정보값이 정확하지 않습니다."); + if(StringUtil.isEmpty(subPathKey)) { + message = "첨부파일이 저장되는 하위 위치정보값이 정확하지 않습니다."; + log.error(message + " : 매개변수 subPathKey 값 부재"); + ErrorMessage errorMessage = new ErrorMessage("ERROR", message); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorMessage); + } String subPath = nlibProperty.getProperty(subPathKey); - if(FileUtil.isNotValid(subPath)) throw new Exception("첨부파일 서브 위치값이 적절하지 않습니다."); + if(StringUtil.isEmpty(subPath)) { + message = "첨부파일이 저장되는 하위 위치정보값을 찾을 수 없습니다."; + log.error(message + " : 매개변수 subPathKey의 속성값 부재"); + ErrorMessage errorMessage = new ErrorMessage("ERROR", message); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorMessage); + } + // 위치정보 적합 확인 + if(FileUtil.isNotValid(FILEUPLOAD_BASE_PATH + subPath)) { + message = MSG_NOT_VALID_FILE_PATH; + log.error(message + " : " + (FILEUPLOAD_BASE_PATH + subPath)); + ErrorMessage errorMessage = new ErrorMessage("ERROR", message); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorMessage); + } + + // 파일 업로드 처리 final Map files = multiRequest.getFileMap(); - log.debug("uploadFilesAjax : 진입 " + (files == null ? " files null " : files.size())); + log.debug("uploadFilesAjax : 진입 > 파일수 = " + (files == null ? " files null " : files.size())); File dir = new File(FILEUPLOAD_BASE_PATH + subPath); if(!dir.exists() || !dir.isDirectory()) dir.mkdirs(); @@ -119,37 +159,30 @@ public class FileUploadController { String orginFileName = file.getOriginalFilename(); //-------------------------------------- - // 원 파일명이 없는 경우 처리 + // 원 파일명이 없는 경우 처리 SKIP // (첨부가 되지 않은 input file type) //-------------------------------------- - if ("".equals(orginFileName)) { + if (orginFileName == null || "".equals(orginFileName)) { continue; } - ////------------------------------------ int index = orginFileName.lastIndexOf("."); - //String fileName = orginFileName.substring(0, index); - String fileExt = orginFileName.substring(index + 1); - //String newName = KeyStr + getTimeStamp() + fileKey; + String fileExt = (index < 1 ? "" : orginFileName.substring(index + 1)); String newName = UUID.getPhysicalFileName(); long size = file.getSize(); - log.debug("FILE UPLOAD : File New Name=" + newName); - if (!"".equals(orginFileName)) { filePath = FILEUPLOAD_BASE_PATH + subPath + "/" + newName; log.debug("FILE UPLOAD : filePath=" + filePath); - file.transferTo(new File(EgovWebUtil.filePathBlackList(filePath))); + file.transferTo(new File(FileUtil.filePathBlackList(filePath))); } fvo = new FileVO(); fvo.setFileExtsn(fileExt); - //fvo.setFileStreCours(storePathString); fvo.setFileMg(Long.toString(size)); fvo.setOrignlFileNm(orginFileName); fvo.setStreFileNm(newName); - //fvo.setAtchFileId(atchFileIdString); fvo.setFileSn(String.valueOf(fileKey)); result.add(fvo); @@ -172,25 +205,43 @@ public class FileUploadController { } catch (JsonProcessingException e) { json = null; e.printStackTrace(); + ErrorMessage errorMessage = new ErrorMessage("ERROR", "JSON 변환 처리에 실패하였습니다 : " + e.toString()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorMessage); } HttpHeaders responseHeaders = new HttpHeaders(); - //responseHeaders.set("Content-Type", "application/json; charset=UTF-8"); - ResponseEntity ret = ResponseEntity.ok().headers(responseHeaders).body(json); return ret; } - + + /** + * 파일 다운로드를 처리한다. + * + * @param params + * @param mv + * @return + * @throws Exception + */ @RequestMapping(value="/fileupload/downloadFiles.do") - public ModelAndView download(@RequestParam HashMap params, ModelAndView mv) { + public ModelAndView download(@RequestParam HashMap params, ModelAndView mv) throws Exception { + + // TODO 권한 설정 기능 추가 필요 + String fid = (String) params.get("fid"); String fname = (String) params.get("fname"); String subPath = nlibProperty.getProperty((String) params.get("subPathKey")); String fullPath = FILEUPLOAD_BASE_PATH + "/" + subPath + "/" + fid; - File file = new File(fullPath); + if(FileUtil.isNotValid(fullPath)) { + throw new Exception(MSG_NOT_VALID_FILE_PATH); + } - mv.setViewName("downloadView"); + File file = new File(FileUtil.filePathBlackList(fullPath)); + if(!file.isFile()) { + throw new Exception("파일 정보가 부적합합니다. 관리자에게 문의하여 주시기 바랍니다."); + } + + mv.setViewName("downloadView"); // dispatcher-servlet.xml내 BeanNameViewResolver 정의 mv.addObject("downloadFile", file); mv.addObject("fname", fname); diff --git a/src/main/java/nlib/util/FileUtil.java b/src/main/java/nlib/util/FileUtil.java index 027dcf30..571e223f 100644 --- a/src/main/java/nlib/util/FileUtil.java +++ b/src/main/java/nlib/util/FileUtil.java @@ -1,5 +1,6 @@ package nlib.util; +import egovframework.com.cmm.EgovWebUtil; import egovframework.com.utl.fcc.service.EgovStringUtil; /** @@ -50,4 +51,13 @@ public class FileUtil extends EgovStringUtil { return !isValid(pathOrFilename); } + /** + * 파일 경로 문자열에서 보안 문제가 되는 문자를 제거하여 리턴한다. + * + * @param path + * @return + */ + public static String filePathBlackList(String path) { + return EgovWebUtil.filePathBlackList(path); + } } diff --git a/src/main/webapp/WEB-INF/config/egovframework/springmvc/dispatcher-servlet.xml b/src/main/webapp/WEB-INF/config/egovframework/springmvc/dispatcher-servlet.xml index 087a7bf6..92966eb0 100644 --- a/src/main/webapp/WEB-INF/config/egovframework/springmvc/dispatcher-servlet.xml +++ b/src/main/webapp/WEB-INF/config/egovframework/springmvc/dispatcher-servlet.xml @@ -82,4 +82,12 @@ + + + + + + + + \ No newline at end of file