이번에는 File Upload 기능을 구현해보겠습니다.
해킹에 있어 File Upload 라는 공격이 있는데, 차후에 이 공격을 기반으로 한 웹 쉘을 이용해 제가 만든
웹 서버를 탈취해볼 계획입니다.
우선, 데이터베이스에 File 컬럼을 추가해줍니다.
여태까진 터미널에서 데이터베이스에 컬럼을 추가하거나 다양한 작업을 했지만,
이번에는 phpmyadmin을 한번 사용해보겠습니다.
localhost/phpmyadmin로 들어가면 접속할 수 있습니다.
원하는 테이블로 이동합니다.
스크롤을 내리면 몇 개의 컬럼을 추가할지, 어디에 추가할지 선택할 수 있습니다.
실행 버튼을 누릅니다.
그럼 이렇게 이름과 종류를 선택할 수 있습니다.
varchar(100)으로 설정해주고 NOT NULL을 위해 NULL 체크를 풀어주는 게 중요합니다.
저장을 누르면 잘 추가된 것을 볼 수 있습니다.
write.php 부분의 form 태그 부분입니다. 이 다음에 하단처럼 enctype 속성을 추가해줍니다.
이 속성을 추가하면 기존 POST 방식에서 업로드하는 용량보다 큰 용량을 업로드할 수 있게 됩니다.
<form action="write_update.php" method="POSTE" enctype="multipart/form-data">
그 후, 파일을 선택하는 type="file"인 input 태그를 form 태그 밑에 추가해줍니다.
<input type="file" name="board_file" />
다음은 write_update.php 파일을 보겠습니다.
SQL문에 file 컬럼을 추가해줍니다.
그 후, 아래의 코드를 추가해줍니다.
php에 존재하는 초전역변수 $_FILES 를 사용할 것입니다
$_FILES['userfile']['name'] | 클라이언트 머신에 존재하는 파일의 원래 이름. |
$_FILES['userfile']['type'] | 브라우저가 이 정보를 제공할 경우에, 파일의 mime 형식. 예를 들면 "image/gif". |
$_FILES['userfile']['size'] | 업로드된 파일의 바이트로 표현한 크기. |
$_FILES['userfile']['tmp_name'] | 서버에 저장된 업로드된 파일의 임시 파일 이름. |
$_FILES['userfile']['error'] | 파일 업로드에 관련한 에러 코드. ['error']는 PHP 4.2.0에서 추가되었습니다. |
$tmpfile = $_FILES['board_file']['tmp_name'];
$origin_filename = $_FILES['board_file']['name'];
$filename = iconv("UTF-8", "EUC-KR",$_FILES['board_file']['name']);
$upload_path = "./upload/".$filename;
move_uploaded_file($tmpfile,$upload_path);
read.php 에도 추가해줍니다.
적당한 곳에 추가해주면 되겠습니다.
저는 조회수 표시 밑에 입력했습니다.
파일 : <a href="upload/<?php echo $board['file']; ?>" download><?php echo $board['file']; ?></a>
가상 머신에는 첨부할만한 마땅한 이미지가 없어서 구글을 통해
귀여운 우파루파 이미지를 한번 받아서 첨부해보겠습니다
글 작성을 누른 후 cutefish.jpeg라고 저장한 우파루파 이미지를 첨부해줍니다
글 작성이 잘 되었습니다
들어가서 읽어보니 잘 읽어집니다
그런데 클릭했을 때 아무 표시도 없는 새 탭이 떴습니다.
구글링을 통해 브라우저 마다 파일 다운로드가 안될 수도 있다고 하고 쿠키를 삭제하니 된다는 얘기가 보여
쿠키를 지워봤습니다.
기록 > 에 들어가 모든 기록 지우기를 눌렀습니다.
이렇게 해도 해결이 안되었습니다.
근본적으로 코드가 부족했다고 생각되어 코드를 수정해보겠습니다.
오류 해결
저 write_update.php 다운로드 현상은 제가 이것저것 구글링하다
header함수를 write_update.php 상단에 추가해버려서 그랬던 것 같습니다
해당 코드를 지우니 해결되더라구요
header 함수는 다운로드를 관리하는 페이지에만 사용해야겠습니다. (ex : download_proc.php)
write_update.php에 있던 파일 관련 변수들을 수정해주겠습니다
//파일 관련 변수
$tmpfile = $_FILES['board_file']['tmp_name'];
$origin_filename = $_FILES['board_file']['name'];
//mime 허락된 형식
$allowed_mime_types = ['image/jpeg','image/png','image/gif','application./zip','application/x-hwp','application/msword','application/pdf']
$filename = iconv("UTF-8", "EUC-KR",$_FILES['board_file']['name']);
$timestamp = time();
$new_filename = $timestamp.'_'.$filename;
$file_mime_type = mime_content_type($tmpfile);
$upload_path = "./upload/".$new_filename;
if(move_uploaded_file($tmpfile,$upload_path)){
$_SESSION['write_error'] = '파일 업로드 success!';
} else {
$_SESSION['write_error'] = '파일 업로드 Failㅜㅜ';
}
파일의 이름은 초기에 사용자가 올린 파일명과 timestamp함수로 찍힌 업로드 시간 문자열과 합쳐서
파일명 = 업로드시간_원래파일명.png 이런식으로 저장되게 됩니다.
게시판 내용에서 출력될 때는 timestamp 시간은 빼고 출력되는 코드가 들어있어 원래 파일명만 출력됩니다.
이 부분 코드가 미완성이지만 $allowed_mime_types로 업로드 가능한 확장자 형식을 지정할 수 있습니다.
현재는 jpeg,png,gif,zip,hwp,word,pdf 만 허락되어있습니다.
저장위치는 해당 웹 서버에 upload 폴더를 만들어 new_filename 변수 이름으로 저장됩니다.
move_uploaded_file 함수가 실행되고 정상적으로 업로드되면 성공 표시가 뜨고 실패하면 실패 표시가 뜹니다.
그리고 read.php 하단에 아래 코드를 추가해줍니다.
세션함수를 활용하여 $_SESSION['write_error'] 변수가 존재하면 echo로 해당 메시지를 출력하고,
unset으로 초기화합니다.
<?php
if(isset($_SESSION['write_error'])){
echo $_SESSION['write_error'];
unset($_SESSION['write_error']);
}
?>
이제 파일 업로드는 구현된 것 같으니 다운로드를 구현해보겠습니다.
download_proc.php를 생성해줍니다.
이제 거의 다 구현이 되었다고 생각했는데 에러 메시지로 파일 업로드가 실패했다고 뜨네요
업로드 Fail 오류 해결
알아보니 해당 디렉토리의 소유자가 관리자이기 때문에 다른 사용자가 업로드를 할 권한이 없어서라고 합니다
터미널을 열고 다음 명령어를 입력해줍니다.
sudo chown -R www-data /var/www/html/upload
Ubuntu에서 아파치 이름은 www-data 라고 적어주면 됩니다.
cd로 폴더를 이동 후 ls -al로 찍어보니 소유자가 잘 바뀐 것을 확인할 수 있습니다.
이제 소유자도 바꿨으니 업로드가 잘 되는지 살펴보겠습니다.
글 작성을 누르고 항상 업로드 하던 우파루파 사진을 올리고 제목과 내용을 작성해줍니다.
글쓰기 완료! 목록으로 돌아가볼까요
드디어 첫 파일 업로드 성공 ㅠㅠㅠㅠㅠ
파일 업로드 success 문구가 떴습니다
아주 귀여운 우파루파가 타임스탬프가 찍힌 상태로 다운로드 되었습니다~
소스 참조
https://blog.naver.com/bgpoilkj/221276053999
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=questzz&logNo=220255928163
'개발 > 웹 개발' 카테고리의 다른 글
[12주차] 게시판 구현 #8 - 게시판 날짜 지정 검색 구현 (0) | 2023.06.09 |
---|---|
PHP에서 다른 파일 포함하기 - include, require (0) | 2023.05.29 |
[8주차] 게시판 구현 #6 - 조회수 카운트 (0) | 2023.05.22 |
[8주차] 게시판 구현 #5 - 검색 기능 (제목/작성자/내용별) (0) | 2023.05.20 |
[7주차] 게시판 구현 #4 - 페이징 만들기 (0) | 2023.05.15 |