안녕하세요! 이태까지 제가 만든 웹 사이트에 보안을 좀 더 보완하겠습니다!
오늘은 파일 업로드에 보안을 좀 더 강화하겠습니다
저는 지정한 디렉터리에 저장을 하게 했는데 이는 적절한 보안 조치 없이 그냥 업로드된 파일에 대한 완전한 제어를 허용합니다! 그래서 보안에 취약하겠죠?? 더군다나 텍스트 파일, 압축파일 형식이니 악의적인 파일이 업로드될 수 있죠
그러니 저는 이걸 방지하기 위해 파일 확장자 검증 하겠습니다.
여기서 의문점이 있을 수 있습니다.
-따로 MIME 형식에서 허락된 것만 변수로 모은 게 있잖아요??
맞아요! 저희는 $allowed_mime_types에다가 형식자를 저장했죠? 근데 클라이언트는 파일 형식을. php을 바꿔서
.exe로 바꾸던가 .txt로 바꿔서 올릴 수가 있습니다! 이러면 문제점이 생기게 됩니다.
그러니깐 저는 확장자 검증을 하고 또 추가로 검증을 하는 겁니다
php에 좋은 내장 함수가 있습니다 finfo_file() 함수입니다.
finfo_file() 함수는 파일의 MIME 타입을 반환합니다. 근데 MIME 타입이 특정하지 않은 경우에는 false을 반환합니다!
즉! 클라이언트가 파일 확장자를 조작하여 업로드하더라도 finfo_file() 함수는 파일 내용을 기반으로 실제 MIME 타입을
검사하기에 더욱 정확한 검증이 가능합니다!!
그러니 저희가 파일 올릴 때 쓰이던 write_process_board.php로 가겠습니다
그리고 코드 추가 하겠습니다
//파일 업로드가 정상적으로 처리되었는지 확인
밑에 if 절에 //파일 MIME 타입 확인, 조작 됐는지 확인
한 줄에 3줄 추가하겠습니다
$file_mime_type = mime_content_type($file_tmp_name);
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$file_mime_type = finfo_file($finfo, $file_tmp_name);
finfo_close($finfo);
이렇게 변경하겠습니다!
그리고 MIME 검사를 했으니 확장자도 같이 검사하겠습니다.
굳이.. 할 필요는 없지만 제가 찾기론 모든 공격을 막을 수 없다고 합니다.
그러니 MIME랑 확장자도 같이 검사하게 코딩 추가 하겠습니다.
// 파일 업로드가 정상적으로 처리되었는지 확인
if ($file_error === UPLOAD_ERR_OK) {
// 파일 MIME 타입 확인, 조작됬는지 확인
$file_mime_type = mime_content_type($file_tmp_name);
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$file_mime_type = finfo_file($finfo, $file_tmp_name);
finfo_close($finfo);
if (in_array($file_mime_type, $allowed_mime_types)) {
//파일 확장자 확인
$file_ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
if(in_array($file_ext, $allowed_extensions)) {
// 파일 저장 경로
$upload_path = '/path/to/upload/directory/' . $new_file_name;
// 파일 이동 및 저장
if (move_uploaded_file($file_tmp_name, $upload_path)) {
$_SESSION['file_error'] = '파일 업로드 성공';
} else {
$_SESSION['file_error'] = '파일 업로드 실패';
}
} else {
$_SESSION['file_error'] = '잘못된 파일 형식입니다';
}
} else {
$_SESSION['file_error'] = '잘못된 파일 형식입니다';
}
}
strtolower는 문자열을 모두 소문자로 변환해 주는 역할을 합니다
pathinfo 함수는 파일 경로의 정보를 배열 형태로 반환해 주는 함수입니다!
이러면 파일이 조작되어도 함수 덕분에 확실히 알 수가 있겠죠 한번 실험해보겠습니다
원래 happy.txt에 php구문을 넣어서 파일이. php형식으로 되게 했습니다
그리고 txt 확장자인 채로 보내봤습니다
그러고 나면??
이렇게 막히는 것을 볼 수 있습니다!
이렇게 해서 파일 업로드 할 때 보안을 강화해봤습니다. 물론 이게 만능까지는 아닐 겁니다.
그래도 이 정도면 파일 업로드 할 때 검증은 확실한 거죠!
이제 총 코드 보여드리고 글을 마치겠습니다
-write_process_board.php
<?php
include 'DB_INFO.php'; //데이터 베이스 정보
session_start(); //세션 시작
if(!isset($_SESSION['login_id'])) {
//로그인하지 않은 사용자
header("Location: login.php"); //login 화면으로 바꾼다
exit(); //이 페이지를 바로 닫는다
}
//게시판 데이터베이스 연결
$conn = mysqli_connect($host,$username,$password, $db_board);
//데이터베이스 오류시 종료
if(mysqli_connect_errno()) {
die("데이터 베이스 오류: ". mysqli_connect_error());
}
//POST로 전달된 정보 받기
if(isset($_POST['board_id'])){
$board_id = mysqli_real_escape_string($conn,$_POST['board_id']);
} else {
$board_id = null;
}
$title = mysqli_real_escape_string($conn,$_POST['title']);
$detail = mysqli_real_escape_string($conn,$_POST['detail']);
if ($_SERVER['REQUEST_METHOD'] == 'POST' && !empty($_FILES['file'])) {
// 업로드된 파일 정보 가져오기
$file_name = $_FILES['file']['name'];
$timestamp = time(); // 현재 시간을 초로 반환
$new_file_name = $timestamp . '_' . $file_name; // 현재 시간과 원래 파일 이름을 합쳐 새로운 파일 이름 생성
$file_tmp_name = $_FILES['file']['tmp_name'];
$file_size = $_FILES['file']['size'];
$file_error = $_FILES['file']['error'];
$allowed_mime_types = ['image/jpeg', 'image/png', 'image/gif','text/plain','application/zip','application/x-hwp','application/msword','application/vnd.ms-excel','application/pdf']; //MIME 허락 된 것
//확장자 허락 된 것
$allowed_extensions = array("jpg","png","gif","txt","zip","hwp","word","xls","xlsx","pdf");
//sql공격 방지용
$new_file_name = mysqli_real_escape_string($conn,$new_file_name);
// 파일 업로드가 정상적으로 처리되었는지 확인
if ($file_error === UPLOAD_ERR_OK) {
// 파일 MIME 타입 확인, 조작됬는지 확인
$file_mime_type = mime_content_type($file_tmp_name);
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$file_mime_type = finfo_file($finfo, $file_tmp_name);
finfo_close($finfo);
if (in_array($file_mime_type, $allowed_mime_types)) {
//파일 확장자 확인
$file_ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
if(in_array($file_ext, $allowed_extensions)) {
// 파일 저장 경로
$upload_path = '/path/to/upload/directory/' . $new_file_name;
// 파일 이동 및 저장
if (move_uploaded_file($file_tmp_name, $upload_path)) {
$_SESSION['file_error'] = '파일 업로드 성공';
} else {
$_SESSION['file_error'] = '파일 업로드 실패';
}
} else {
$_SESSION['file_error'] = '잘못된 파일 형식입니다';
}
} else {
$_SESSION['file_error'] = '잘못된 파일 형식입니다';
}
}
}
//session으로 유저 이름 받기
$user_id = $_SESSION['login_id'];
echo $board_id;
if(isset($board_id)) {
//board_id가 있다는 것은 수정을 의미
$sql = "UPDATE $db_board SET title = '$title', detail='$detail', file_name='$new_file_name' WHERE board_id='$board_id' ";
}
else {
//board_id가 없으니 새로 만드는 sql문
$sql = "INSERT INTO $db_board (id, title, detail,file_name) VALUES ('$user_id', '$title', '$detail','$new_file_name')";
}
//sql문 실행
if(mysqli_query($conn,$sql)) {
//수정인 경우 바로 게시판 보이게 함
if(isset($board_id)) {
$_SESSION['write_error'] = '수정되었습니다!';
header("Location: view_board.php?index=$board_id");
}
else {
$board_id = mysqli_insert_id($conn); // 새로 생성한 게시물의 id를 가져옴
$_SESSION['write_error'] = '작성되었습니다!';
header("Location: view_board.php?index=$board_id");
}
} else {
$_SESSION['write_error'] = '작성 중 오류가 발생하였습니다.';
header("Location: view_board.php");
}
exit();
?>
감사합니다
'개발과제 > 보안추가' 카테고리의 다른 글
[노말틱 모의 해킹 취업반 추가 개발과제 ] XSS 방지 (0) | 2023.05.13 |
---|---|
[노말틱 모의 해킹 취업반 추가 개발과제 ] PreparedStatement 적용하기 -2 (0) | 2023.05.03 |
[노말틱 모의 해킹 취업반 추가 개발과제 ] PreparedStatement 적용하기 -1 (0) | 2023.05.02 |
[노말틱 모의 해킹 취업반 개발과제 (3)] 보안 관련해서 보완 하기 (0) | 2023.04.23 |
[노말틱 모의 해킹 취업반 개발과제 (1)] 보안 관련해서 보완 하기 (3) | 2023.04.05 |