18. Zip Slip 취약점 빠르게 정리
압축 해제기는 엔트리 이름을 파일 경로로 바꾼다. 이름에 상위 디렉터리나 절대 경로가 들어 있고 해제 대상과의 관계를 확인하지 않으면, 압축 파일이 의도한 폴더 밖에 파일을 쓸 수 있다. 업로드 기능을 점검할 때는 자기 소유의 격리된 랩에서 무해한 sentinel 파일로만 검증한다.
문제는 ../ 문자열보다 넓다
Unix의 ../, Windows의 드라이브 문자와 \\ 구분자, 절대 경로, 심볼릭 링크 엔트리, 중복 구분자와 인코딩된 이름을 각각 고려해야 한다. 라이브러리가 경로를 자동으로 정리한다는 문서가 있어도 버전과 API별 차이가 있으므로, 실제 사용 중인 추출 함수에 대한 테스트가 필요하다. 해제 전에 엔트리 이름을 출력하고, 기준 디렉터리 밖에 sentinel이 생기지 않는지 확인한다.
안전한 해제 흐름
신뢰할 수 없는 아카이브는 먼저 격리된 임시 디렉터리에 해제한다. 각 엔트리를 기준 디렉터리와 결합하고 canonical path를 계산한 뒤, 그 결과가 기준 디렉터리 내부인지 경계 포함 여부까지 검사한다. 심볼릭 링크·하드 링크·특수 파일은 허용하지 않는 편이 안전하며, 파일 수·압축 해제 크기·중첩 깊이에도 제한을 둔다.
Python에서는 zipfile의 편의 추출 함수에 방어를 맡기기보다 엔트리별 검사를 코드로 드러내는 편이 검토하기 쉽다. 검사가 통과한 뒤에도 최종 파일 생성 위치와 실행 권한을 분리한다. 웹 루트나 설정 디렉터리에 직접 해제하지 않고, 검증된 파일만 별도 복사한다.
판정과 회귀 테스트
취약성의 증거는 서버에서 셸이 실행되었다는 장면이 아니다. 악성 이름이 기준 루트 밖의 파일 생성으로 이어질 수 있었고, 실행 계정에 그 권한이 있었다는 사실이면 충분하다. 수정 후에는 경로 형태·플랫폼 구분자·링크·압축 폭탄 경계값을 포함한 테스트를 유지한다. 압축 해제는 편의 기능이 아니라 파일시스템 쓰기 작업이므로, 입력 검증과 권한 최소화가 함께 있어야 한다.