특정 확장자를 제외한 파일의 업로드 제한 → 첨부파일을 이용하는 웹 공격을 막기 위한 조치
파일 확장자의 경우 정규표현식을 이용하여 검사 가능하다.
ajaxUpload.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script src="https://code.jquery.com/jquery-3.6.1.min.js"
integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=" crossorigin="anonymous"></script>
</head>
<body>
<div class="uploadDiv">
<input type="file" name="uploadFiles" multiple>
</div>
<button id="uploadBtn" >Upload</button>
<script>
$(function () {
const regex = new RegExp("(.*?)\.(exe|sh|zip|alz)$");
const maxSize = 5242880 // 5MB
function checkExtentsion(fileName, fileSize){
if (fileSize >= maxSize){
alert("too large file size");
return false;
}
if (regex.test(fileName)){
alert("This extensions cannot be uploaded")
return false;
}
return true;
}
$("#uploadBtn").on("click", function (e){
let formData = new FormData()
let inputFile = $("input[name='uploadFiles']");
let files = inputFile[0].files;
console.log(files)
for (let i = 0; i < files.length; i++) {
if(!checkExtentsion(files[i].name, files[i].size)) return false;
formData.append("uploadFile", files[i]);
}
$.ajax({
url : '/ajaxUpload',
processData : false,
contentType : false,
method: 'post',
data: formData,
success : function(result) {
console.log(result);
}
}) // $.ajax
}) // .on("click")
}) // $(function(){})
</script>
</body>
</html>
const regex = new RegExp("(.*?)\.(exe|sh|zip|alz)$");
.
: 임의의 한 문자
*
: 0회 이상 반복되는 문자와 가능한 많이 일치
?
: 없거나 1회 가능한 많이 일치
→ .*
: 아무 문자나 가능한 많이 일치시킨다. ( 하나의 단어 )
→ .*?
: 하나의 단어가 없거나 1회 매칭된다.
\.
: 이스케이프 문자 + 마침표 → "." 를 의미한다.
$
: 문자열의 끝
→ (.*?)
파일명 + \.
마침표 + (exe|sh|zip|alz)
확장자
⇢ 파일명.확장자 나타내는 정규표현식
메소드 | 문법 | 설명 |
---|---|---|
exec | 정규식.exec(문자열) | 일치하는 하나의 정보(Array) 반환 |
test | 정규식.test(문자열) | 일치 여부(Boolean) 반환 |
match | 문자열.match(정규식) | 일치하는 문자열의 배열(Array) 반환 |
search | 문자열.search(정규식) | 일치하는 문자열의 인덱스(Number) 반환 |
replace | 문자열.replace(정규식,대체문자) | 일치하는 문자열을 대체하고 대체된 문자열(String) 반환 |
split | 문자열.split(정규식) | 일치하는 문자열을 분할하여 배열(Array)로 반환 |
toString | 생성자_정규식.toString() | 생성자 함수 방식의 정규식을 리터럴 방식의 문자열(String)로 반환 |
mkdir()
: 디렉터리를 생성한다. 상위 폴더가 존재하지 않을 시 상위폴더도 생성한다.UploadController
package com.ze.controller;
// ...
@Controller
@Log4j2
public class UploadController {
private String getFolder(){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = new Date();
String str = sdf.format(date); // 오늘 날짜를 년-월-일 문자열로 생성한다.
return str.replace("-", File.separator); // 생성된 년-월-일 문자열의 형태를 년/월/일 로 변경한다. 이 때 /는 폴더 경로를 나타낸다
}
@PostMapping("/ajaxUpload")
public void uploadAjax(MultipartFile[] uploadFile){
log.info("post /ajaxUpload");
String uploadPath = "/Users/jueon/Desktop/study/spring/upload/temp";
// 폴더 객체 생성
File uploadFolder = new File(uploadPath, getFolder());
// 년/월/일 폴더 생성
if (!uploadFolder.exists()) uploadFolder.mkdirs();
for (MultipartFile file : uploadFile) {
log.info("upload file name : " + file.getOriginalFilename());
log.info("upload file size : " + file.getSize());
File saveFile = new File(uploadFolder, file.getOriginalFilename());
try {
file.transferTo(saveFile);
} catch (IOException e) {
e.printStackTrace();
}
}
}
@GetMapping("/uploadForm")
public void uploadForm() {
log.info("get /uploadForm");
}
@GetMapping("/ajaxUpload")
public void ajaxUpload(){
log.info("get /ajaxUpload");
}
@PostMapping("/upload")
public void upload(MultipartFile[] uploadFile, Model model) {
String uploadPath = "/Users/jueon/Desktop/study/spring/upload/temp";
for (MultipartFile file : uploadFile) {
log.info("post /upload");
log.info("upload file name : " + file.getOriginalFilename());
log.info("upload file size : " + file.getSize());
File saveFile = new File(uploadPath, file.getOriginalFilename());
try {
file.transferTo(saveFile);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@PostMapping("/ajaxUpload")
public void uploadAjax(MultipartFile[] uploadFile){
log.info("post /ajaxUpload");
String uploadPath = "/Users/jueon/Desktop/study/spring/upload/temp";
File uploadFolder = new File(uploadPath, getFolder());
if (!uploadFolder.exists()) uploadFolder.mkdirs();
for (MultipartFile file : uploadFile) {
String fileName = file.getOriginalFilename();
UUID uuid = UUID.randomUUID();
fileName = uuid.toString() + "_" + fileName;
File saveFile = new File(uploadFolder, fileName);
try {
file.transferTo(saveFile);
} catch (IOException e) {
e.printStackTrace();
}
}
}