파일 업로드·다운로드
파일 형식, 저장 경로, 실행 권한의 경계
발생 상황
프로필 이미지, 게시판 첨부파일, 문서 변환, 다운로드 기능에서 사용자가 제공한 파일명이나 MIME을 신뢰할 때 문제가 발생합니다.
주요 유형
확장자·MIME 검증 우회, 경로 순회, 덮어쓰기, 저장형 XSS, 잘못된 실행 경로가 대표적입니다. 업로드 성공과 서버 코드 실행은 별도의 조건입니다.
분석할 때 주의할 점
multipart의 파일 파트 Content-Type과 전체 요청 Content-Type을 구분하세요. 이중 확장자·대소문자·정규화 결과와 웹 서버의 핸들러 매핑이 중요합니다. jspx가 실행되는지는 서버 설정에 달려 있습니다.
대응 방안
허용 확장자와 실제 형식을 함께 검사하고 서버가 파일명을 재발급합니다. 업로드는 실행 불가능한 별도 저장소에 보관합니다. 다운로드는 객체 ID로 조회하고 소유권을 검증하며 정규화한 최종 경로가 허용 디렉터리 안인지 확인합니다.
자주 놓치는 부분과 특이사항
SVG·HTML처럼 브라우저가 해석하는 파일은 다운로드 헤더와 제공 도메인도 중요합니다. 압축 해제 기능의 경로 순회와 크기 제한, 이미지 디코더의 취약점은 단순 확장자 검사로 해결되지 않습니다.
파일 업로드와 다운로드 더 알아보기
업로드 요청의 파일명·확장자·Content-Type·실제 파일 내용은 서로 독립적인 값입니다. 클라이언트가 보내는 MIME만 신뢰하거나 jsp 하나만 금지하는 블랙리스트는 검사 누락을 만들 수 있습니다.
Burp에서 multipart의 파일 파트 헤더를 비교합니다. 다운로드의 ../는 경로 정규화와 허용 디렉터리 검증 누락을 다룹니다. 서버 저장 위치, 실행 가능 여부, 읽기 권한을 구분하고 확장자 허용목록·내용 검사·웹 루트 외부 저장을 함께 적용합니다.
요청과 구현 비교
파일 파트와 전체 요청을 구분
아래는 요청 구조 예시입니다. 파일 파트의 MIME은 클라이언트가 주장하는 값이지 검증 결과가 아닙니다. 업로드 후 서버가 재발급한 객체 ID로 조회하고, 저장 위치·실행 권한·다운로드 응답 헤더·소유권까지 확인합니다.
POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=demo
--demo
Content-Disposition: form-data; name="file"; filename="sample.txt"
Content-Type: text/plain
sample content
--demo--적용 조건과 재검증
저장소의 최종 경계
허용 경로 검사는 파일명을 붙인 뒤 정규화한 최종 경로에서 해야 합니다. 심볼릭 링크가 있는 환경에서는 실제 경로까지 확인해야 합니다. 업로드 크기와 압축 해제 후 크기도 제한하고, 정상 파일의 업로드·다운로드가 계속 되는지 재검증합니다.