Tạo và mở tệp ZIP trực tuyến: cách ZIP hoạt động và giới hạn

Cấu trúc tệp ZIP, vì sao ZIP tạo trong trình duyệt không rời thiết bị, zip slip, zip bomb và loại tệp nén mà công cụ này không mở được.

Trong bài này

Để tạo một ZIP, hãy thêm các tệp hoặc một thư mục, chọn có nén hay không, rồi tải tệp nén về; để mở một ZIP, hãy nạp nó, xem danh sách bên trong, và lấy ra từng tệp. Công cụ chạy trong trình duyệt làm cả hai việc ngay trên thiết bị của bạn: trang đọc tệp từ ổ đĩa, tệp nén được tạo hoặc đọc tại đó, và không có gì bị tải lên. Bài này giải thích tệp ZIP được bố trí ra sao qua một ví dụ thật dài 122 byte, vì sao nén đôi khi chẳng có tác dụng gì, vì sao cần cẩn trọng với tệp nén từ người lạ (zip slip và zip bomb), và loại tệp nén nào một công cụ như thế không mở được.

Bên trong một ZIP có gì

Tệp ZIP có cấu trúc đơn giản. Đó là một chuỗi các mục, mỗi tệp một mục, theo sau là một bảng mục lục ở cuối. Mỗi phần mở đầu bằng chữ ký bốn byte bắt đầu bằng PK, tên viết tắt của Phil Katz, người thiết kế định dạng này.

PhầnChữ kýChứa gì
Local file header (header cục bộ)PK 03 04Tên tệp, phương pháp nén, mã kiểm tra và kích thước, rồi đến dữ liệu của tệp
Central directory headerPK 01 02Mỗi tệp một mục: cùng các chi tiết đó cộng với vị trí header cục bộ của nó
End of central directoryPK 05 06Có bao nhiêu mục và danh mục trung tâm bắt đầu ở đâu

Đây là ví dụ thật nhỏ nhất, tạo bằng module zipfile của Python: một tệp tên hello.txt chứa chữ hello và một dấu xuống dòng, sáu byte, lưu nguyên không nén. Cả tệp nén dài 122 byte:

ByteNội dung
0 đến 38Header cục bộ, 30 byte cộng tên 9 byte hello.txt
39 đến 44Dữ liệu: hello và một dấu xuống dòng
45 đến 99Header danh mục trung tâm, 46 byte cộng tên 9 byte
100 đến 121Bản ghi kết thúc danh mục trung tâm, 22 byte

Các header lưu mã kiểm tra của tệp, một CRC-32. Với hello và một dấu xuống dòng nó là 363A3020. Bản ghi cuối nói: một mục, danh mục trung tâm dài 55 byte, bắt đầu ở vị trí 45. Một chương trình mở tệp nén sẽ đọc những byte cuối trước, tìm bản ghi đó, nhảy tới danh mục trung tâm và có ngay toàn bộ danh sách tệp mà không chạm vào dữ liệu. Vì vậy một công cụ tốt mở được ZIP lớn tức thì: nó chỉ đọc danh sách. Tệp nén do chương trình khác tạo lớn hơn một chút vì thêm các trường phụ như dấu thời gian: cùng tệp đó nén bằng lệnh zip trên macOS nặng 174 byte.

Cách bố trí này kéo theo vài hệ quả. Mỗi tệp được nén riêng, nên bạn lấy được một tệp mà không cần đọc các tệp khác; cái giá là bộ nén không tìm được sự lặp lại giữa các tệp, đó là lý do .tar.gz của nhiều tệp giống nhau thường nhỏ hơn. Tệp mới có thể được nối thêm mà không phải viết lại tệp cũ. Và danh mục trung tâm mới là thứ có giá trị: một tệp nén thậm chí có thể chứa hai mục trùng tên.

Lưu nguyên hay deflate

Mỗi mục có một số hiệu phương pháp. Stored (0) giữ nguyên các byte. Deflate (8) nén chúng bằng thuật toán trong RFC 1951, kết hợp tham chiếu ngược tới đoạn văn bản lặp với mã hóa Huffman. Văn bản, bảng tính, mã nguồn và nhật ký co lại rất tốt, thường chỉ còn một phần nhỏ kích thước.

Tệp đã được nén sẵn thì chẳng được gì thêm: ảnh JPEG và PNG, video MP4, PDF có trang đã nén và các ZIP khác. Một thử nghiệm với 5.000 byte ngẫu nhiên, vốn hành xử như một tệp đã mã hóa, cho tệp nén 5.108 byte khi lưu nguyên và 5.113 byte khi deflate, lớn hơn năm byte. Một công cụ tốt nhận ra khi nén không giúp ích và lưu nguyên tệp, nên không tệp nào bị phình ra. Công cụ này làm đúng như vậy. Nếu tệp của bạn chủ yếu là ảnh, hãy thu nhỏ chúng trước bằng bộ công cụ ảnh; bài nén ảnh mà không mất chất lượng giải thích cách làm.

Tạo ZIP

  1. Mở công cụ ZIP và ở lại thẻ Tạo ZIP. Thả tệp vào khung hoặc chọn tệp. Để giữ cấu trúc thư mục, bấm "Thêm thư mục" và chọn thư mục; các đường dẫn bên trong được giữ nguyên. Trình duyệt không đọc được một thư mục khi thả cả thư mục vào, nên mới có nút này.
  2. Chọn Nén: "Nén (nhỏ hơn)" hoặc "Không nén (nhanh nhất)". Dùng "Không nén" cho ảnh và video.
  3. Đặt tên tệp nén, xem tổng số, và bấm "Tạo và tải ZIP".

Tên tệp được ghi theo UTF-8, kèm cờ trong header báo như vậy, nên tên có dấu tiếng Việt hay dấu khác vẫn nguyên vẹn. Ngày giờ trong ZIP dùng định dạng DOS cũ, đếm theo bước hai giây và bắt đầu từ năm 1980. Công cụ không tạo tệp nén có mật khẩu.

Mở ZIP

  1. Chuyển sang Mở ZIP rồi thả hoặc chọn một tệp .zip. Ban đầu chỉ có danh sách được đọc.
  2. Mỗi dòng cho thấy tên đã lưu, kích thước sau khi giải nén và ngày. Dòng tóm tắt cho biết số mục và tổng dung lượng sau giải nén, đáng liếc qua trước khi giải nén bất cứ thứ gì.
  3. Bấm Tải xuống ở một dòng để lấy một tệp, hoặc chọn tối đa 20 tệp rồi bấm "Tải các tệp đã chọn". Trình duyệt có thể hỏi một lần xin cho phép tải nhiều tệp; hãy đồng ý.

Trước khi lưu một tệp, CRC-32 của nó được so với mã kiểm tra trong tệp nén. Nếu khác nhau, tệp đã hỏng và công cụ từ chối lưu. Mã kiểm tra bắt được sự cố ngẫu nhiên, như tải về bị ngắt. Nó không bắt được việc sửa đổi có chủ ý, vì ai sửa tệp cũng có thể lưu kèm một mã kiểm tra mới. Để biết một ZIP có đúng là bản nhà phát hành đã phát hành hay không, hãy so SHA-256 của nó như hướng dẫn trong cách kiểm tra tệp tải về.

Cẩn trọng với tệp nén từ người lạ

Mọi tên trong ZIP đều do người tạo ra nó viết, và mọi kích thước cũng vậy.

Zip slip. Một tệp nén độc hại có thể chứa mục tên ../../etc/passwd hoặc đường dẫn tuyệt đối, hy vọng trình giải nén ghép nó vào thư mục đích và ghi ra ngoài thư mục. Một trình giải nén cẩn thận sẽ cắt bỏ hoặc từ chối những tên như vậy. Ví dụ unzip của Info-ZIP đi kèm macOS in ra "skipped "../" path component(s)" và giữ tệp bên trong thư mục. Không phải chương trình nào cũng cẩn thận. Công cụ này chỉ hiển thị tên như văn bản, và tên mà trình duyệt lưu là phần cuối của đường dẫn, đã được làm sạch: ../../etc/passwd được lưu thành passwd, C:\Windows\x.dll thành x.dll, và tên dành riêng của Windows con.txt thành _con.txt.

Zip bomb. Một tệp nén nhỏ có thể được dựng để bung ra hàng gigabyte, bằng cách lặp lại một mẫu. Ngay cả một máy tính xách tay vừa phải cũng có thể hết bộ nhớ. Công cụ từ chối tệp giải nén ra hơn 500 MB, dừng ngay khi dữ liệu vượt quá kích thước tệp nén đã khai báo, và dừng dữ liệu nở ra nhiều hơn mức một luồng nén hợp lệ có thể.

Thói quen tốt:

  • Xem danh sách mục và tổng dung lượng sau giải nén trước.
  • Đừng bao giờ chạy tệp thực thi, script hay macro bật ra từ một tệp nén bạn không chờ đợi.
  • Đừng dựa vào mật khẩu: tệp nén được mã hóa vẫn có thể giấu mã độc.
  • Giải nén vào một thư mục mới, trống.

Công cụ không mở được gì, và các giới hạn

  • Mục đặt mật khẩu được liệt kê kèm ổ khóa và đánh dấu là chưa hỗ trợ. Công cụ không bao giờ hỏi mật khẩu.
  • ZIP64, tệp nén hoặc tệp trên 4 GB, chưa được hỗ trợ. Tệp nén chia thành nhiều phần cũng vậy.
  • Phương pháp nén khác stored và deflate, như BZip2, LZMA hay Zstandard, được đánh dấu là chưa hỗ trợ; phần còn lại của tệp nén vẫn dùng được.
  • Tệp 7z, RAR và tar không được đọc.
  • Tạo: tối đa 500 tệp và tổng 1 GB.
  • Mở: tệp nén đến 2 GB với tối đa 10.000 mục, và mỗi tệp tối đa 500 MB sau khi giải nén.
  • Trình duyệt cũ không nén được sẽ lưu nguyên tệp, còn trình duyệt không giải nén được thì liệt kê được các mục đã nén nhưng không bung ra được.

Mọi thứ chạy trong trình duyệt. Nếu tệp nén của bạn cần một tính năng chưa được hỗ trợ, một chương trình trên máy tính là công cụ phù hợp.

Lệnh tương đương trên dòng lệnh

zip -r photos.zip photos/       # tạo, giữ cấu trúc thư mục
unzip -l photos.zip             # liệt kê nội dung
unzip -t photos.zip             # kiểm tra mã kiểm tra
unzip photos.zip -d out         # giải nén vào thư mục "out"

Trong PowerShell, Compress-Archive -Path photos -DestinationPath photos.zip và Expand-Archive photos.zip -DestinationPath out làm việc tương tự.

Danh sách kiểm tra ngắn

Dùng "Không nén" cho ảnh và các tệp đã nén, "Nén" cho văn bản và tài liệu. Thêm thư mục bằng nút thư mục, đừng thả cả thư mục vào. Kiểm tra số mục và dung lượng sau giải nén trước khi mở tệp nén của người lạ, giải nén vào thư mục trống, và so SHA-256 khi nhà phát hành cung cấp. Nhớ rằng mã kiểm tra của ZIP bảo vệ khỏi hư hỏng, không bảo vệ khỏi sự can thiệp có chủ ý.

Công cụ được nhắc trong bài

Về trang blog