SameOS ~/tools/private-file-protection.md

PHP와 Nginx로 비공개 파일 직접 접근 막기

파일 업로드 기능을 만들 때 가장 흔한 실수는 저장 폴더를 그대로 공개 URL 아래에 두는 것입니다. 주소만 알면 누구나 파일을 내려받을 수 있게 되기 때문입니다. 이 글은 Nginx(웹사이트 요청을 받아 나눠 주는 프로그램)에서 직접 접근을 막고, PHP 라우터(요청을 검사한 뒤 파일을 대신 읽어 주는 중간 스크립트)가 인증을 확인한 뒤 필요한 파일만 읽어주는 구조를 설명합니다.

기본 원칙

PHP 라우터 예시

<?php
session_start();
if (empty($_SESSION["user_id"])) {
    http_response_code(404);
    exit;
}

$base = realpath(__DIR__ . "/protected_files");
$rel = ltrim($_GET["file"] ?? "", "/");
$path = realpath($base . "/" . $rel);

if (!$base || !$path || !str_starts_with($path, $base . DIRECTORY_SEPARATOR)) {
    http_response_code(404);
    exit;
}

if (!is_file($path)) {
    http_response_code(404);
    exit;
}

header("Content-Type: " . mime_content_type($path));
header("X-Robots-Tag: noindex, nofollow");
readfile($path);

Nginx 차단 예시

location ~ ^/(protected_files|logs|data)/ {
    deny all;
    return 404;
}

location = /media.php {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
}

운영 체크

설정 후에는 파일 폴더 직접 URL이 404인지, PHP 라우터가 로그인 상태에서만 응답하는지, 로그에 실제 파일 경로가 과하게 남지 않는지 확인해야 합니다.

라우터 전체 코드 받기 (GitHub) Nginx 차단 규칙 생성기 열기

파일 폴더만 robots.txt로 막으면 충분한가요?

아니요. robots.txt는 착한 크롤러에게만 안내하는 파일이라 직접 접근 차단이 아닙니다. Nginx나 웹서버 레벨에서 막아야 합니다.

403과 404 중 무엇이 좋나요?

관리 정책에 따라 다르지만, 비공개 파일 존재 여부를 숨기고 싶다면 404가 더 조용합니다.

PHP에서 경로 검사가 왜 필요한가요?

../ 같은 경로 조작으로 허용 폴더 밖 파일을 읽는 문제를 막기 위해 realpath와 루트 경로 비교가 필요합니다.