- 개인 블로그 운영자는 취약점 스캔, 스팸, 콘텐츠 스크래핑을 줄이기 위해 악성 봇에게 gzip 기반 Zip Bomb을 HTTP 응답으로 보냄
- 정상 브라우저와 크롤러가 쓰는 Accept-Encoding: gzip, deflate 흐름을 이용해, 의심 요청에는
200 OK와 Content-Encoding: gzip을 반환함
- 1MB gzip 파일은 압축 해제 시 약 1GB, 10MB 파일은 약 10GB로 커져 많은 봇이 메모리를 소진하거나 요청을 중단함
- 서버 미들웨어는 블랙리스트 IP와 스팸 패턴을 확인하고, 조건에 걸리면 사전 생성한 Zip Bomb 파일을 전송한 뒤 요청 처리를 끝냄
- 쉽게 탐지·우회될 수 있어 완전한 방어책은 아니지만, 무차별 크롤링으로 서버를 방해하는 단순한 봇을 막는 용도로는 충분함
봇 트래픽과 Zip Bomb 사용 배경
- 웹 트래픽의 대부분은 봇에서 오며, RSS 리더, 검색엔진 크롤러, AI 봇처럼 새 콘텐츠를 찾는 정상적인 용도도 있음
- 문제는 스패머, 콘텐츠 스크래퍼, 해커가 운영하는 악성 봇임
- 과거 직장에서 봇이 WordPress 취약점을 찾아 서버에 악성 스크립트를 삽입함
- 해당 서버는 이후 DDoS에 쓰이는 봇넷의 일부가 됨
- 초기 웹사이트 중 하나는 봇이 만든 스팸 때문에 Google 검색에서 완전히 제외됨
- 이런 경험 이후 악성 봇으로부터 서버를 보호하기 위해 Zip Bomb을 사용하기 시작함
gzip 압축을 방어 수단으로 바꾸는 방식
- Zip Bomb은 작은 압축 파일이 압축 해제 과정에서 매우 큰 파일로 확장되어 머신에 부담을 주는 파일임
- 웹 초기에 gzip 압축은 느린 인터넷 환경에서 전송량을 줄이기 위해 도입됨
- 50KB HTML 파일을 10KB로 줄이면 40KB 전송량을 아낄 수 있음
- 전화 접속 인터넷에서는 페이지 다운로드 시간이 12초에서 3초로 줄어드는 효과가 있었음
- 브라우저는 요청 시 자신이 지원하는 압축 방식을 헤더로 알림
Accept-Encoding: gzip, deflate
- 서버도 압축을 지원하면 기대한 데이터의 압축 버전을 반환함
- 웹 크롤링 봇 역시 대량 데이터를 수집하기 위해 gzip 같은 압축을 지원하며, 이 특성을 방어에 활용함
악성 요청에 보내는 응답
- 블로그에는 보안 취약점을 스캔하는 봇이 자주 나타나며, 대부분은 무시함
- 악성 입력을 주입하려 하거나 응답을 탐색하는 요청으로 판단되면
200 OK와 함께 gzip 응답을 보냄
Content-Encoding: gzip
- 전송하는 파일 크기는 상황에 따라 1MB~10MB임
- 1MB 파일은 압축 해제 시 약 1GB로 커짐
- 10MB 파일은 압축 해제 시 약 10GB로 커짐
- 봇은 헤더를 보고 압축 파일이라고 판단한 뒤 내용을 찾기 위해 압축 해제를 시도함
- 파일이 계속 확장되면서 메모리를 소진하고 서버나 스크립트가 크래시할 수 있음
- 1MB 파일로 충분하지 않은 끈질긴 스크립트에는 10MB 파일을 보내며, 이 경우 스크립트가 즉시 종료된다고 함
Zip Bomb 생성과 서버 적용 예
- Zip Bomb을 만들 때는 자신의 장치를 크래시시키거나 망가뜨릴 수 있으므로 위험 부담을 감수해야 함
- 10GB로 풀리는 gzip 파일은 다음 명령으로 생성함
dd if=/dev/zero bs=1G count=10 | gzip -c > 10GB.gz
- 명령 구성은 다음과 같음
dd: 데이터를 복사하거나 변환하는 명령
if=/dev/zero: 무한한 0 바이트 스트림을 생성하는 특수 파일을 입력으로 사용
bs=1G: 블록 크기를 1GB로 설정
count=10: 1GB 블록 10개를 처리해 10GB의 0 데이터 생성
gzip -c > 10GB.gz: 출력 데이터를 gzip으로 압축해 10GB.gz 파일로 저장
- 이 경우 결과 파일 크기는 약 10MB임
- 서버에는 현재 요청이 악성인지 확인하는 미들웨어를 추가함
- 사이트 전체를 반복적으로 스캔하는 IP의 블랙리스트를 유지함
- 스팸을 남긴 뒤 해당 스팸이 페이지에 반영됐는지 다시 확인하러 오는 패턴도 탐지에 사용함
if (ipIsBlackListed() || isMalicious()) {
header("Content-Encoding: gzip");
header("Content-Length: ". filesize(ZIP_BOMB_FILE_10G)); // 10 MB
readfile(ZIP_BOMB_FILE_10G);
exit;
}
- 비용은 특정 상황에서 서버가 10MB 파일을 전송해야 한다는 점임
- 글이 바이럴되는 상황에서는 1MB 파일로 낮추며, 이 파일도 효과가 있다고 함
한계와 사용 범위
- Zip Bomb은 완전한 방어책이 아님
- 쉽게 탐지될 수 있음
- 우회도 가능함
- 클라이언트가 내용을 부분적으로만 읽을 수도 있음
- 그래도 웹을 무작정 크롤링하며 서버를 방해하는 정교하지 않은 봇을 막는 도구로는 충분함
- 동작 예시는 서버 로그 리플레이에서 확인할 수 있음: this replay of my server logs