2026년 10월 8일 내용 정정 IBM 통계의 금액·대상, Python ZIP 경로 처리, Django 업로드 설정과 SVG 설명을 공식 문서와 대조해 수정했습니다. 근거를 확인하지 못한 수행 건수와 무료 점검의 업로드 검증 약속도 삭제했습니다.
파일 업로드는 받은 파일의 형식뿐 아니라 저장 위치, 처리 프로그램, 다운로드 권한을 함께 검토해야 하는 기능입니다. OWASP 파일 업로드 가이드에 따라 필요한 형식만 허용하고 여러 방어 수단을 조합하세요. 확장자나 매직바이트 하나가 파일의 안전을 보증하지는 않습니다.
먼저 구분할 위험 4가지
1. 파일명과 실제 처리 방식의 불일치
서버가 파일명과 내용을 어떻게 해석하는지에 따라 실행 가능한 파일을 이미지로 오인할 수 있습니다. 이중 확장자 자체만으로 실행 가능 여부가 결정되지는 않으며, 서버의 핸들러 설정과 저장 위치를 함께 확인해야 합니다.
2. SVG·HTML 등 능동 콘텐츠의 브라우저 실행
SVG의 동작은 표시 방식에 따라 다릅니다. 이미지로 불러온 SVG에는 스크립트 실행 제한이 있지만, 직접 문서로 열거나 다른 방식으로 삽입하는 경로까지 같은 제한을 가정하면 안 됩니다. 파일 형식과 실제 제공 경로를 함께 검토하세요.
3. 압축 해제 경로와 자원 사용
압축 안의 경로를 검증 없이 파일 시스템 경로로 사용하면 지정한 디렉터리 밖에 파일을 쓸 수 있습니다. 압축 크기 외에도 해제 후 크기·파일 수·처리 시간을 제한해야 합니다. 라이브러리의 경로 처리만으로 모든 압축 파일을 안전하다고 판단하지 마세요.
4. 업로드·처리·보관 용량 초과
요청 크기, 개별 파일 크기, 사용자별 보관량은 서로 다른 제한입니다. 이미지 변환이나 압축 해제 과정에서 필요한 메모리·디스크도 고려하고, 실패 시 임시 파일 정리와 처리 시간 제한을 점검하세요.
서버 측 검증 5단계
1단계: 업무에 필요한 형식과 권한만 허용
허용 확장자를 좁히고 업로드 사용자의 권한을 확인하세요. 사용자 파일명을 저장 경로로 직접 사용하지 말고, 서버가 정한 식별자로 저장하세요. 파일명·확장자의 정규화와 길이 제한도 함께 검토합니다.
2단계: 형식 검사를 여러 층으로 적용
요청의 Content-Type은 사용자가 지정할 수 있습니다. 서버 측 형식 식별과 지원 파서의 유효성 검사를 조합하되, 매직바이트가 맞는다는 이유만으로 안전하다고 단정하지 마세요. 처리 라이브러리의 보안 업데이트와 자원 제한도 필요합니다.
3단계: 파일 크기 제한을 명시적으로 구현
Django의 FILE_UPLOAD_MAX_MEMORY_SIZE는 메모리에서 임시 파일 저장으로 전환하는 기준이며 업로드 거부 한도가 아닙니다. DATA_UPLOAD_MAX_MEMORY_SIZE의 계산에서는 파일 업로드 데이터가 제외됩니다. 이 두 값만 설정해 개별 파일 용량 제한이 적용됐다고 판단하면 안 됩니다.
프록시·웹 서버의 전체 요청 크기 제한과 애플리케이션의 파일별 용량·개수 제한을 별도로 적용하세요. 처리 전 파일 크기를 확인하고, 수신 중 자원 소모까지 제한하려면 업로드 핸들러에서 수신량을 제한하는 방식을 검토하세요.
4단계: 저장과 다운로드 경로 분리
업로드 파일을 실행 가능한 웹 경로와 분리하고, 다운로드 시 요청자의 파일 접근 권한을 검사하세요. 용도에 맞는 Content-Type, 다운로드 처리와 nosniff 설정을 검토합니다. 헤더 설정만으로 접근 통제나 파일 내용 검사를 대체할 수는 없습니다.
5단계: 형식별 처리와 수정 후 확인
이미지 재인코딩이나 메타데이터 제거만으로 악성 내용을 모두 제거했다고 판단하지 마세요. SVG가 필요하면 유지 관리되는 정화 도구와 격리된 제공 방식을 검토하고, 필요하지 않으면 허용 형식에서 제외하세요. PDF·문서도 업무에 맞는 검사·변환 정책을 별도로 정합니다.
수정 뒤에는 허용·비허용 파일, 용량 초과, 권한 없는 다운로드와 정상 사용자의 업로드를 시험 환경에서 함께 확인하세요. 운영 시스템 검증은 승인된 대상·시간·방법으로 진행합니다.
자주 묻는 질문
Python 3.12 이전 zipfile에는 경로 방어가 없었나요?
그렇게 일반화할 수 없습니다. Python 3.11 공식 문서도 extract()의 절대 경로·상위 경로 요소 처리와 extractall() 사용 시 주의를 설명합니다. open()으로 읽은 내용을 직접 경로에 쓰는 구현 등에는 같은 처리를 가정하면 안 됩니다. 사용 API와 최종 저장 경로를 검토하고, 신뢰하지 않는 압축 파일은 사전 검사하세요.
SVG에서 script 태그만 지우면 안전한가요?
아닙니다. DOMParser는 파싱 도구이지 보안 정화 도구가 아닙니다. 일부 태그·문자열 제거만으로 SVG의 모든 실행 경로를 처리했다고 볼 수 없습니다. 허용할 기능과 제공 방식을 정하고, 검증된 정화 도구를 적용한 뒤 실제 표시 경로를 확인하세요.
무료 URL 점검으로 업로드 기능 전체를 검증할 수 있나요?
아닙니다. 공개 설정 점검만으로 로그인한 사용자의 업로드·파일 처리·다운로드 권한을 검증할 수는 없습니다. 테스트 계정과 업로드 기능의 승인된 검증 범위를 별도로 정해야 합니다.
통계의 해석과 참고 자료
IBM의 2024년 발표는 조사 대상 조직의 글로벌 평균 데이터 침해 비용을 488만 달러로 설명합니다. 이전 본문의 4,880만 달러는 잘못된 표기였으며, 파일 업로드나 웹 애플리케이션 취약점 사고만의 평균 대응 비용도 아닙니다. 이 수치를 특정 서비스의 예상 피해액으로 사용할 수 없습니다.
외부에서 관찰할 수 있는 보안 설정은 CodeScan 무료 점검으로 확인할 수 있습니다. 업로드 처리와 로그인 이후 권한은 SENTRIX 전문가 진단에서 대상과 범위를 협의하세요.