03 · Archives — ZIP · TAR · GZ · 7z · RAR
이 문서가 답하는 질문: ZIP 과 TAR 의 진짜 차이는 무엇인가? 왜
.tar.gz는 두 단계를 거치는가? 압축 해제 시 무엇이 위험한가? MIME:application/zip,application/x-tar,application/gzip,application/x-7z-compressed
한 줄 답 (Pyramid Top)
아카이브의 본질은 “컨테이너(여러 파일을 한 파일로) ↔ 압축(바이트 줄이기)” 의 분리. ZIP 은 둘을 한 번에, TAR 는 컨테이너만, GZ 는 압축만 한다. 그리고 모든 아카이브 처리기는 Zip Slip · Zip Bomb · symlink traversal 을 막아야 한다.
Why — 컨테이너와 압축은 왜 분리되었나
UNIX 의 철학 — 한 도구 한 일
tar (1979, Tape ARchive) — 본래 테이프 백업용. 여러 파일을 한 개의 연속 스트림 으로 이어붙이기만 함. 압축 X.
compress (1984) → gzip (1992) — 바이트 줄이기 하나만.
그래서 UNIX 에서는:
파일들 → tar → 한 스트림 → gzip → 압축 스트림파이프로 연결: tar cf - dir/ | gzip > dir.tar.gz.
Windows / DOS 의 철학 — 한 도구 다 하기
ZIP (1989, Phil Katz) — 컨테이너 + 압축 + 인덱스 를 한 포맷에. 각 파일을 개별로 압축. 랜덤 액세스 가 가능 (전체를 풀지 않고 한 파일만).
Windows: ZIP 더블클릭 → 내부 구조 보기 → 파일 하나만 추출
UNIX: .tar.gz 는 전부 풀어야 한 파일을 본다 (스트림이라서)이 두 철학이 지금도 살아있다.
How — 각 포맷의 내부 구조
TAR — 헤더 + 데이터의 반복
[ Header (512B) | Data (N×512B) ] [ Header | Data ] ... [ 0×1024 (END) ]각 헤더에 파일명·크기·권한·시간이 ASCII 로 적혀있고, 데이터는 그 뒤에 그대로. 압축 없음.
$ tar tvf backup.tar
-rw-r--r-- raw/staff 1234 2026-05-10 10:00 docs/a.txt
drwxr-xr-x raw/staff 0 2026-05-10 10:00 docs/img/
-rw-r--r-- raw/staff 245678 2026-05-10 10:00 docs/img/cover.png한계: 한 파일 위치를 알려면 처음부터 헤더 체인을 따라가야 함 (랜덤 액세스 X).
ZIP — 끝의 Central Directory 가 인덱스
[ Local File Header + 압축 데이터 ] × N
[ Central Directory (모든 파일의 메타) ]
[ End of Central Directory Record (EOCD) ] ← 끝PDF 의 xref 와 같은 패턴 — 인덱스가 끝에.
EOCD 의 매직 PK\x05\x06 를 끝에서 찾고, 거기서 Central Directory 위치를 안다.
$ unzip -l app.zip
Archive: app.zip
Length Date Time Name
--------- ---------- ----- ----
245678 2026-05-10 10:00 src/main.js
12345 2026-05-10 10:00 src/lib/util.js
89 2026-05-10 10:00 package.json
--------- -------
258112 3 filesunzip -l 이 빠른 이유: EOCD 만 읽으면 됨. 데이터 안 풀어도 됨.
ZIP의 압축 알고리즘
| 메소드 | 내부값 | 비고 |
|---|---|---|
| Store | 0 | 압축 없음 (이미 PNG/JPEG 인 경우) |
| Deflate | 8 | zlib, 가장 흔함 |
| Deflate64 | 9 | 사전 64KB → 호환성 떨어짐 |
| BZIP2 | 12 | 더 작지만 느림 |
| LZMA | 14 | 7z 와 같음 |
| Zstandard | 93 | 최신, 빠르고 작음 |
GZ / BZ2 / XZ / ZSTD — 단일 스트림 압축
이들은 컨테이너가 아니다. 단일 바이트 스트림을 압축. 여러 파일을 묶으려면 TAR 로 먼저 한 스트림을 만들고 그 위에 압축.
| 포맷 | 알고리즘 | 압축률 | 속도 |
|---|---|---|---|
.gz | DEFLATE (LZ77 + Huffman) | 보통 | 빠름 |
.bz2 | Burrows-Wheeler + Huffman | 좋음 | 느림 |
.xz | LZMA2 | 매우 좋음 | 매우 느림 |
.zst | Zstandard (Facebook) | 좋음 | 매우 빠름 |
.tar.gz vs .tar.zst — 2020년 이후 zstd 가 압축률·속도 둘 다 우위 → Arch Linux, Ubuntu 22.04, Fedora 가 패키지 포맷을 zstd 로 전환.
7z — Solid Compression
7z (1999, Igor Pavlov) — 여러 파일을 하나의 스트림으로 합쳐서 압축 (solid). 같은 패턴이 파일 경계를 넘어 재사용 → 압축률 +10~30%. 비용: 한 파일 추출에도 전체를 디코드.
$ 7z l archive.7z
Date Time Attr Size Compressed Name
------------------- ----- ------------ ------------ ------------------------
2026-05-10 10:00:00 ....A 1245678 docs/a.txt
2026-05-10 10:00:00 ....A 567890 docs/b.txt
2026-05-10 10:00:00 ....A 890123 234567 docs/all (solid block)RAR — 사유, but 흔함
- 매직:
52 61 72 21 1A 07 00(Rar!...) - 알고리즘 사양 비공개 (디코더만 무료, 인코더 유료)
- 리눅스 표준 도구는
unrar. RAR 5 부터 더 강한 sliding dictionary.
What — CLI / 실전
매직 / 식별
$ xxd file.zip | head -1
00000000: 504b 0304 1400 0000 0800 ... PK..............
$ xxd file.tar | head -1 # 257번째 byte 부터 'ustar'
00000000: 6d79 6669 6c65 2e74 7874 ...
$ xxd file.gz | head -1
00000000: 1f8b 0800 ... ..
$ xxd file.7z | head -1
00000000: 377a bcaf 271c ... 7z..'.
$ xxd file.xz | head -1
00000000: fd37 7a58 5a00 ... .7zXZ.
$ xxd file.zst | head -1
00000000: 28b5 2ffd ... (./자주 쓰는 명령
# 목록만
unzip -l a.zip
tar tvf a.tar.gz
7z l a.7z
# 풀기
unzip a.zip -d out/
tar xzf a.tar.gz -C out/
tar xJf a.tar.xz -C out/ # xz
tar xf a.tar.zst -C out/ # zstd (최근 tar 는 자동 감지)
7z x a.7z -oout/
# 만들기
zip -r a.zip dir/
tar czf a.tar.gz dir/
tar caf a.tar.zst dir/ # 확장자로 자동 선택
7z a -mx9 a.7z dir/ # mx9 = 최대 압축Python 으로
import zipfile, tarfile
with zipfile.ZipFile("a.zip") as z:
for info in z.infolist():
print(info.filename, info.file_size, info.compress_size)
with tarfile.open("a.tar.gz", "r:gz") as t:
t.extractall("out/") # ← 위험 (filter='data' 권장, Py3.12+)What-if — 보안 위협 백화점
1) Zip Slip — Path Traversal 의 클래식
ZIP 안에 다음과 같은 엔트리가 있다면:
../../../../etc/cron.d/evil순진한 파서는 unzip -d /tmp/upload/ 했을 때 /etc/cron.d/evil 을 만든다.
대응 (Python 예시):
import os, zipfile
def safe_extract(zf: zipfile.ZipFile, dest: str):
dest = os.path.realpath(dest)
for member in zf.infolist():
target = os.path.realpath(os.path.join(dest, member.filename))
if not target.startswith(dest + os.sep):
raise ValueError(f"Zip slip detected: {member.filename}")
zf.extract(member, dest)Python 3.12+ tarfile.extractall(filter='data') 는 자동 검증.
2) Zip Bomb — 압축률 폭탄
42.zip — 42KB 가 풀면 4.5 PB.
구조: 5중 중첩 ZIP, 각 단계마다 16개 사본, 1.3 GB 의 0 으로 채워진 파일.
더 진화한 Non-Recursive Zip Bomb (David Fifield, 2019) — 한 번 풀어서 281 TB. Central Directory 의 압축률을 인위적으로 부풀려서.
대응:
- 풀린 크기 한계 (예: 100 MB)
- 압축률 한계 (예: 100배 초과 시 거부)
- 풀면서 누적 카운트, 초과 시 abort
3) Symlink Traversal (TAR 특유)
TAR 는 symlink 를 보존 → 다음 시퀀스가 가능:
1) tar 안의 첫 엔트리: link → symlink('/tmp/extracted/innocent', '/etc')
2) tar 안의 둘째 엔트리: /tmp/extracted/innocent/cron.d/evil
↑ 풀어보면 실제 경로는 /etc/cron.d/evil대응: tarfile.extractall(filter='data') (symlink 무시), 또는 직접 검증.
4) Hard Link 같은 함정
ZIP 은 hard link 가 없지만, TAR 는 가능. ZIP 도 일부 구현은 동일 파일을 다른 이름으로 가리키는 트릭이 가능.
5) 큰 파일 (4 GB 한계) — ZIP64
옛 ZIP 은 32bit 크기 필드 → 4 GB 한계.
ZIP64 (2001) 가 64bit 확장. 옛 도구로 풀면 깨짐.
확인: unzip -v 출력 끝에 Zip64 표시.
6) 인코딩 — 파일명 깨짐
ZIP 의 파일명은 본래 CP437. 한국어 파일명을 압축하면 → 윈도우는 CP949, 맥/리눅스는 UTF-8 → 서로 깨짐.
ZIP 2003+ 는 UTF-8 플래그(bit 11) 추가. 그래도 호환성 문제 잦음.
대응: unzip -O cp949 a.zip 으로 강제 인코딩.
# Mac 에서 한국어 ZIP 깨질 때
$ unzip -O cp949 韓國.zip7) Encrypted ZIP
- Legacy ZipCrypto (1989): 알려진 평문 공격으로 깨짐. 사용 금지.
- AES-256 (WinZip 9+, 2003): 안전하지만 모든 도구가 지원하진 않음.
- 7z 의 AES-256: 헤더까지 암호화 가능 → 파일명도 가려짐.
Insight — 흥미로운 이야기
“ZIP 의 발명자 Phil Katz 와 ARC 분쟁”
1986년 SEA 사의 ARC 가 BBS 표준이었음. Phil Katz 가 더 빠른 호환 구현 PKARC 를 만들자 SEA 가 소송. Katz 는 1989년 완전히 새로운 ZIP 포맷을 발표하며 사양을 공개. 압도적 호환성으로 ARC 를 대체. 당시 PKWARE 의 광고 카피: “You will use ZIP”. Katz 본인은 알코올 중독으로 2000년에 사망 (37세).
“왜 .tar.gz 가 표준이 되었나”
1992년 GNU tar 가
-z옵션으로 gzip 을 자동 호출. 같은 시기 인터넷이 폭발 → Linux 패키지 배포 표준 →.tar.gz가 사실상 ㄹ소프트웨어 운반의 기본. 30년이 지난 지금도 거의 모든 Linux 소스 배포는.tar.gz또는.tar.xz.
“7z 는 왜 그렇게 잘 압축되는가”
두 가지 트릭:
- LZMA 의 큰 사전 — gzip 의 32KB vs LZMA 의 4GB 사전. 멀리 떨어진 반복도 잡음.
- Solid mode — 모든 파일을 한 스트림으로. 파일 간 패턴 공유. 단점: 한 파일만 꺼내려 해도 수 GB 디코드. 그래서 백업에는 좋고 라이브러리에는 나쁨.
“Zip Bomb 의 방어 전략 진화”
1990년대: 단순 크기 한계 (50MB 풀면 abort). 2000년대: 풀어보지 않고 Central Directory 의 압축률만 검사 → 우회됨. 2019: David Fifield 의 non-recursive bomb 등장 → 풀어보면서 카운트 + 압축률 둘 다 검사. 결국 stream-based decode + budget 이 정답.
요약 + Mermaid
아카이브의 본질은 컨테이너 ↔ 압축의 분리. ZIP 은 둘을 합쳤고 (랜덤 액세스 OK), TAR+GZ 는 분리했고 (스트림 친화), 7z 는 solid 로 압축률 우위. 모든 처리기는 Zip Slip · Zip Bomb · symlink traversal · 인코딩 4 가지 함정을 정적으로 막아야 한다.