파일 업/다운로드 취약점

파일 업로드 취약점은

  1. php 파일이 서버에 존재하고
  2. 웹 브라우저를 통한 접근이 가능해야 합니다

이 두가지 조건이 성립 할 때 파일 업로드 취약점을 이용하여 공격할 수 있습니다.

그럼 각 방법에 대응하도록 막으면 되겠습니다.

  1. 특정(png, jpg 등 필요에 의한) 확장자만 허용하고(이 때 중요한것은 특정 확장자를 차단하는 블랙리스트가 아닌 특정 확장자만 허용하는 화이트리스트여야 합니다.
  2. 웹 브라우저를 통한 직접적인 서버 파일에 접근을 폐쇄합니다.

1번 방법에 대응하도록 바꾸는 코드는 index.php 에 해당 코드를 추가하면 됩니다.

$filetype = strtolower(pathinfo($targetFile, PATHINFO_EXTENSION));
$allowed = ['jpg', 'jpeg', 'png', 'gif'];
if (!in_array($filetype, $allowed)) {
    echo "only jpg, jpeg, png, gif is allowed. go back.";
    $uploadOk = 0;
}

jpg, jpeg, png, gif 만 허용되도록 설정해주면 됩니다.

2번 방법에 대응하도록 바꾸는것은 서버의 코드를 수정하는것이 아닌 서버의 정책을 수정해야 합니다.

파일 다운로드 시 Path traversal, Local file injection으로 이어질 수 있습니다.

regex를 이용해 (파일명).(확장자) 를 a-z, A-Z, 0-9까지 형식으로만 허용되도록, ../ 등의 순회를 방지하도록 해보겠습니다.

if 문을 하나 추가하고 묶으면 됩니다.

<?php
$filename = $_GET['file'];

if (preg_match('/^[a-zA-Z0-9]+\\.[a-zA-Z0-9]+$/', $filename)) {
    $filePath = "upload/" . $filename;

    if (file_exists($filePath) && is_readable($filePath)) {
        header("Cache-Control: private");
        header("Content-Type: application/octet-stream");
        header("Content-Length: " . filesize($filePath));
        header("Content-Disposition: attachment; filename=" . $filename);

        readfile($filePath);
        exit;
    } else {
        echo "File not found or inaccessible";
    }
} else {
    echo "Invalid. check the file name";
}
?>