SSD Nodes Learn Hosting plans →
Hướng dẫn Matt ConnorBởi Matt Connor · Cập nhật ngày 2026-08-25

Cách kiểm tra checksum file tải xuống trên Linux

Dùng sha256sum để tạo hash và đối chiếu file với SHA256SUMS. Sau đó đổi một byte để thấy lỗi xác minh và hiểu checksum thực sự chứng minh điều gì.

Verified Every command ran end-to-end on a fresh Ubuntu 24.04 server, August 12, 2026.

Xác minh file tải xuống bằng checksum trong hai phút

Để xác minh file tải xuống bằng checksum, hãy hash file bạn đã nhận rồi để một công cụ so sánh hash đó với hash do nhà phát hành công bố. sha256sum thực hiện cả hai phần: khi chạy độc lập, nó in ra digest; khi dùng -c, nó đọc danh sách digest và báo file nào khớp. Hướng dẫn này thực hiện toàn bộ quy trình với một file do bạn tạo, sau đó cố ý làm hỏng file đó để bạn thấy lỗi xảy ra thay vì chỉ đọc mô tả.

Trong suốt quá trình, hãy ghi nhớ một câu. Checksum cho biết các byte bạn đang có có phải là các byte đã tạo ra digest hay không, nhưng không cho biết ai đã tạo ra chúng. Câu hỏi thứ hai cần chữ ký và một key mà bạn tin cậy. Phần cuối của hướng dẫn này chỉ rõ ranh giới giữa hai việc đó.

Tạo một file để thực hành

Làm việc trong một thư mục tạm để các thao tác ở đây không ảnh hưởng đến phần còn lại của hệ thống. Mọi command bên dưới đều thuộc GNU coreutils, bộ command cơ bản có sẵn trên mọi server Ubuntu hoặc Debian, nên không cần cài thêm gì.

mkdir -p ~/checksum-demo
cd ~/checksum-demo
printf 'the payload of a totally ordinary download\n' > payload.txt
sha256sum payload.txt

Bạn nhận được một dòng gồm 64 ký tự hexadecimal, hai dấu cách, rồi đến tên file. 64 ký tự đó là digest của file. Chạy lại command này sẽ cho ra đúng dòng đó, vì hashing có tính xác định: cùng một input luôn cho cùng một output. Thay đổi một ký tự trong file rồi chạy lại, digest sẽ không chỉ thay đổi một chút. Nó sẽ trông hoàn toàn khác, vì đảo một bit của input sẽ đảo khoảng một nửa số bit của output. Tính chất này khiến một chuỗi 64 ký tự có thể dùng làm đại diện cho một image 4 GB.

Lưu file SHA256SUMS rồi kiểm tra

Digest hiển thị trên màn hình sẽ không còn hữu ích vào ngày hôm sau. Hãy ghi digest vào một file theo đúng định dạng mà sha256sum tạo ra, để công cụ có thể đọc lại sau này.

sha256sum payload.txt > SHA256SUMS
cat SHA256SUMS
sha256sum -c SHA256SUMS

sha256sum -c đọc từng dòng trong danh sách, băm file được nêu trên dòng đó rồi so sánh hai digest. Lần chạy hợp lệ sẽ in một dòng cho mỗi file:

payload.txt: OK

Đồng thời kiểm tra exit status, vì script đọc giá trị đó chứ không đọc nội dung văn bản. echo $? in 0 sau một lần chạy thành công. Tên SHA256SUMS là quy ước chứ không phải yêu cầu bắt buộc, nhưng các distribution và hầu hết trang release đều dùng tên này. Bạn cũng nên dùng nó để người tiếp theo biết file chứa gì mà không cần mở file.

Đổi một byte và theo dõi kiểm tra thất bại

Bây giờ cố ý làm hỏng file. Lệnh này ghi một byte duy nhất tại offset 5 và giữ nguyên mọi thứ khác, nên file vẫn giữ nguyên độ dài và tên.

printf 'X' | dd of=payload.txt bs=1 seek=5 conv=notrunc status=none
cat payload.txt
sha256sum -c SHA256SUMS

conv=notrunc là flag quan trọng: nếu thiếu flag này, dd sẽ truncate file tại vị trí nó dừng ghi, và bạn sẽ kiểm tra một dạng hỏng dễ nhận biết hơn nhiều. Kết quả kiểm tra bây giờ là:

payload.txt: FAILED
sha256sum: WARNING: 1 computed checksum did NOT match

echo $? in ra 1. FAILED nghĩa là file đã được đọc nhưng digest của file không khớp với digest trong danh sách. Khôi phục các byte ban đầu rồi xác nhận kiểm tra trả về OK:

printf 'the payload of a totally ordinary download\n' > payload.txt
sha256sum -c SHA256SUMS

Đó là toàn bộ thói quen cần duy trì. Chỉ cần khác một byte ở bất kỳ vị trí nào trong file cũng tạo ra FAILED. Download bị ngắt do mất kết nối, mirror cung cấp bản build của ngày hôm qua, proxy sửa file trong quá trình truyền, hoặc disk trả về một block lỗi: tất cả đều dẫn đến cùng một dòng đó.

Khi danh sách chỉ đến một file bạn chưa tải xuống

Một file SHA256SUMS thực tế từ một distribution liệt kê mọi image mà project phát hành, còn bạn chỉ tải xuống một trong số đó. Hãy tái hiện tình huống này ở đây.

printf 'a second file\n' > notes.txt
sha256sum payload.txt notes.txt > SHA256SUMS.all
rm notes.txt
sha256sum -c SHA256SUMS.all
payload.txt: OK
sha256sum: notes.txt: No such file or directory
notes.txt: FAILED open or read
sha256sum: WARNING: 1 listed file could not be read

FAILED open or read là một lỗi khác với FAILED, và nhầm lẫn hai lỗi này sẽ làm mất thời gian. FAILED có nghĩa là các byte không đúng. FAILED open or read có nghĩa là sha256sum hoàn toàn không tìm thấy file, nên không có gì được so sánh. Khi tải xuống thực tế, nguyên nhân thường là working directory, vì các tên trong danh sách được tính tương đối từ thư mục nơi bạn chạy lệnh. Chuyển vào thư mục chứa file rồi chạy lại. Để chỉ kiểm tra những file bạn thực sự có, hãy dùng tùy chọn đó:

sha256sum --ignore-missing -c SHA256SUMS.all

Lệnh này in payload.txt: OK rồi thoát với mã 0. Nếu không có tên nào trong danh sách tồn tại, --ignore-missing không âm thầm thành công với 0 file. Nó báo no file was verified rồi thoát với mã khác 0. Đây là hành vi bạn cần, vì một lần kiểm tra thành công nhưng không kiểm tra gì cả là lỗi mà bạn sẽ không bao giờ phát hiện.

Dán digest do nhà phát hành công bố mà không cần tự đọc

Việc so sánh 64 ký tự thập lục phân bằng mắt thường là lúc thói quen này thực sự gây lỗi. Người ta kiểm tra 4 ký tự đầu và 4 ký tự cuối rồi kết luận là khớp. Đây chính xác là kiểu so sánh mà kẻ tấn công có chủ đích nhắm tới. Hãy để tool tự so sánh. Đặt EXPECTED thành digest bạn đã copy từ nhà phát hành. Dùng EXPECTED= rồi thêm giá trị đã dán vào, sau đó tạo một dòng duy nhất mà -c yêu cầu:

printf '%s  %s\n' "$EXPECTED" payload.txt > payload.sha256
cat payload.sha256
sha256sum -c payload.sha256

Có hai khoảng trắng giữa digest và tên file. Vì vậy format string cũng phải chứa hai khoảng trắng. Đây là định dạng mà sha256sum ghi ra và -c phân tích. File chỉ chứa digest, không có nội dung nào khác, không phải là một checksum line hợp lệ. Vì vậy thao tác kiểm tra sẽ từ chối toàn bộ file với no properly formatted checksum lines found thay vì đoán bạn muốn kiểm tra file nào. Một số project công bố theo định dạng BSD có tag, dùng SHA256 (payload.txt) = rồi đến digest. GNU coreutils ghi định dạng đó bằng sha256sum --tag payload.txt và đọc lại bằng -c, nên bạn có thể lưu theo một trong hai định dạng.

Khi thao tác kiểm tra cho kết quả bất thường, hãy xem trực tiếp list bằng cat -A SHA256SUMS. Lệnh này đánh dấu cuối mỗi dòng bằng $ và hiển thị các ký tự mà bạn không thể thấy theo cách khác. Dòng kết thúc bằng ^M$ đã nhận thêm carriage return từ một Windows editor. GNU sha256sum bỏ qua ký tự ở cuối đó và vẫn in OK. Vì vậy, list dùng CRLF không phải nguyên nhân làm thao tác kiểm tra bị lỗi, dù các tool ngoài coreutils có thể xử lý kém linh hoạt hơn. Hãy chuẩn hóa bản copy bạn lưu bằng tr -d '\r' < SHA256SUMS > SHA256SUMS.clean.

Checksum chứng minh điều gì và không chứng minh điều gì?

Checksum chỉ chứng minh một điều: các byte trên đĩa của bạn chính là các byte đã tạo ra digest được công bố. Điều này phát hiện đầy đủ các hư hỏng do lỗi ngoài ý muốn. Nó cũng phát hiện trường hợp attacker bất cẩn thay file trên download mirror nhưng không thể sửa trang đã công bố digest.

Checksum không chứng minh ai là tác giả. Digest là thông tin về các byte, không phải thông tin về con người. Nếu một trang cung cấp cả file và digest, thì bất kỳ ai có thể sửa một thứ cũng có thể sửa thứ còn lại. Khi đó, dòng OK chỉ cho biết mirror khớp với chính nó. Vì vậy, đây là quy tắc khiến việc chạy checksum có giá trị: lấy digest từ một nơi khác với nơi bạn lấy file. Ví dụ, lấy digest từ domain chính thức của project qua TLS (transport layer security), trong khi image được tải từ mirror hoặc torrent. Khi đó, attacker phải kiểm soát 2 nơi thay vì 1. Checksum cũng không cho biết các byte đã xác minh sẽ làm gì sau khi bạn chạy chúng. Đây là một câu hỏi riêng cần đặt ra với mọi thứ thực thi thay bạn, từ install script đến plugin dsh chạy với quyền của agent của bạn.

Thuật toán cũng rất quan trọng. SHA-256 (secure hash algorithm, đầu ra 256-bit) chưa có collision được biết đến tính đến August 2026, nên các publisher sử dụng thuật toán này. MD5 (message digest 5) và SHA-1 không còn đủ an toàn: từ 2004, người ta đã có thể tạo 2 file khác nhau nhưng có cùng digest MD5. Một collision SHA-1 với chosen-prefix đã được công bố vào 2020. File MD5SUMS vẫn phát hiện download bị cắt ngắn, vì hỏng ngẫu nhiên không phải là collision được tạo có chủ đích. Nó không thể ngăn người đang cố đánh lừa bạn. Khi project công bố cả 2 loại, hãy dùng dòng SHA-256.

Khi chữ ký trở thành lớp xác thực chính

Chữ ký khắc phục khoảng trống mà digest để lại. Nhà phát hành dùng private key để ký file digest, còn bạn dùng public key của họ để kiểm tra: gpg --verify SHA256SUMS.asc SHA256SUMS. Nếu bước này thành công, danh sách digest đúng là do người nắm giữ key đó tạo ra. Sau đó, sha256sum -c SHA256SUMS liên kết file trên disk của bạn với danh sách này, tạo thành chuỗi tin cậy từ key đến tận các byte.

Điểm yếu lúc này chuyển sang key. Nếu lấy key từ chính trang đã cung cấp file, bạn trao cả hai phần cho attacker. GnuPG thể hiện rõ điều này: lần verify đầu tiên sẽ in Good signature cùng với WARNING: This key is not certified with a trusted signature!. Good signature chỉ có nghĩa là phép toán mật mã hợp lệ. Nó không có nghĩa key đó thuộc về project mà bạn đang nghĩ đến. Hãy lấy fingerprint từ một nguồn thứ hai, chẳng hạn documentation của project trên domain khác hoặc một distribution package đã có sẵn key, rồi so sánh toàn bộ fingerprint thay vì chỉ so sánh 8 ký tự cuối. Đây là mức cẩn trọng tương tự cần có với SSH private key, vì cùng một lý do: key là quyết định về mức độ tin cậy, và mọi thành phần phía sau đều kế thừa quyết định đó.

Reproducible build đẩy ý tưởng này đi xa hơn một bước. Một digest được công bố vẫn chỉ liên kết bạn với binary do một máy tạo ra. Khi build của một project có thể tái lập, bất kỳ ai cũng có thể compile cùng source và tạo ra output giống hệt từng byte. Nhờ đó, các builder độc lập có thể xác nhận digest đã công bố thay vì buộc bạn tin vào một server duy nhất. Điều này càng quan trọng qua từng năm, khi ngày càng nhiều code được đưa vào qua các pipeline tự động và các bản vá do máy tạo ra. Quyết định nội dung nào được phép đưa vào một build là vấn đề policy, và policy mã nguồn mở cho code có AI hỗ trợ cũng xử lý cùng supply chain này, nhưng từ đầu còn lại.

Trình quản lý gói đã tự làm việc này cho bạn

Trên Debian và Ubuntu, apt tự động thực hiện chuỗi kiểm tra này mỗi lần cài đặt mà không cần bạn yêu cầu. Chỉ mục gói chứa digest SHA-256 cho từng tệp .deb. Tệp Release chứa digest của các tệp chỉ mục đó, còn InRelease chứa chữ ký trên Release. Chữ ký này được kiểm tra bằng các key trong /usr/share/keyrings và /etc/apt/trusted.gpg.d. Khi chuỗi xác minh bị lỗi, apt sẽ thông báo: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY khi thiếu key của repository bên thứ ba, hoặc Hash Sum mismatch khi chỉ mục bạn tải về không khớp với Release đã được ký. Nguyên nhân thường là caching proxy đã trả về tệp cũ hoặc bạn đã lấy dữ liệu từ một mirror đang đồng bộ.

Đó là tiêu chuẩn để đối chiếu khi trang chủ của một project yêu cầu bạn pipe script từ curl thẳng vào shell. Không có bước nào xác minh các byte và bạn cũng không thấy nội dung script. Server còn có thể trả về một nội dung cho script và nội dung khác cho trình duyệt, trong khi sau đó bạn không có bản sao nào để kiểm tra. Hãy tải script xuống tệp bằng curl -fsSL <url> -o install.sh, tính hash, đọc nội dung bằng less, rồi chỉ chạy sau đó. Thói quen này chỉ mất khoảng twenty giây. Bạn cũng nên bắt đầu áp dụng nó với một VPS hoàn toàn mới trong mười phút đầu tiên, trước khi cài bất kỳ thứ gì khác trên máy.

Giữ danh sách digest cho những gì bạn cài thủ công

Các package được cài bởi apt sẽ được theo dõi. Binary bạn sao chép vào /usr/local/bin thì không, và không có thành phần nào trên system đang theo dõi nó. Danh sách digest biến việc này thành một kiểm tra có thể chạy khi cần:

printf 'a second file\n' > notes.txt
sha256sum *.txt > inventory.sha256
sha256sum -c --quiet inventory.sha256

--quiet không in gì khi mọi file đều khớp, và chỉ in các dòng kiểm tra thất bại khi có file không khớp. Vì vậy, không có output nghĩa là kiểm tra đạt, còn echo $? xác nhận kết quả đó bằng 0. Đây là dạng nên dùng trong scheduled job. --status đi xa hơn và hoàn toàn không in output, chỉ để lại exit status. Áp dụng cùng mẫu cho các file thực tế bằng sha256sum /usr/local/bin/* > ~/local-bin.sha256 là bạn có một baseline. Các path được lưu trong danh sách đúng như lúc bạn nhập, vì vậy dùng absolute path sẽ giúp kiểm tra hoạt động từ mọi directory.

Cần hiểu rõ baseline này có giá trị đến đâu. Nó phát hiện file đã bị thay đổi. Nó không phát hiện attacker đã có root, vì attacker đó có thể sửa inventory.sha256 dễ dàng như khi sửa binary. Nếu muốn danh sách này có ý nghĩa, hãy lưu nó bên ngoài máy. Đây là một phần của câu hỏi rộng hơn về mức độ bạn thực sự tin cậy một VPS và những ai khác có thể truy cập disk bên dưới nó.

FAQ

Checksum trùng khớp có nghĩa là file tải xuống an toàn không?

Không. Điều đó chỉ có nghĩa là các byte bạn có khớp với digest mà bạn đã dùng để đối chiếu. Nếu kẻ tấn công kiểm soát trang đăng digest, họ có thể đăng digest của chính file độc hại của họ, và phép kiểm tra sẽ in OK. Kết quả trùng khớp chỉ xác nhận tính nhất quán. Muốn xác nhận an toàn, cần có chữ ký được xác minh bằng một key mà bạn lấy từ nguồn khác. Khi đó digest mới kế thừa mức độ tin cậy từ key này.

Vì sao sha256sum -c in ra FAILED open or read?

Vì lệnh chưa đọc file. Ngay phía trên có một dòng riêng ghi No such file or directory cùng với tên file mà lệnh đang tìm. Tên file trong file SHA256SUMS là đường dẫn tương đối so với thư mục bạn chạy lệnh. Vì vậy, hãy chuyển vào thư mục chứa file tải xuống rồi chạy lại. Nếu danh sách còn có tên những file bạn chưa tải xuống, hãy thêm --ignore-missing. Trường hợp ngược lại là khi FAILED không có open or read: file đã được đọc, nhưng digest của file không khớp.

MD5 có đủ để xác minh file tải xuống không?

Có, nếu chỉ cần phát hiện hư hỏng ngẫu nhiên. Một lần truyền bị thiếu hoặc một block trên disk bị lỗi sẽ không tình cờ tạo ra MD5 digest trùng khớp. Nhưng không đủ để chống kẻ tấn công. Có thể tạo ra hai file khác nhau nhưng có cùng MD5 digest từ năm 2004, và SHA-1 đã bị phá bằng collision có tiền tố được chọn vào năm 2020. Khi project công bố cả hai loại, hãy dùng dòng SHA-256. Nếu project chỉ dùng MD5, hãy xem đó là dấu hiệu của một quy trình release cũ.

sha256sum -c khác gpg --verify như thế nào?

sha256sum -c chứng minh một file khớp với một digest. gpg --verify chứng minh file digest đã được ký bằng private key của một chủ thể cụ thể. Hai cơ chế này trả lời hai câu hỏi khác nhau, vì vậy hãy chạy cả hai khi project cung cấp cả hai. Chữ ký làm cho danh sách digest đáng tin cậy, sau đó danh sách digest giúp xác nhận file tải xuống đáng tin cậy.

Làm thế nào để kiểm tra một file với digest được in trên trang web?

Không so sánh các ký tự bằng mắt. Hãy lưu digest và tên file trên cùng một dòng, ngăn cách bằng hai dấu cách. Sau đó chạy sha256sum -c đối với file đó và đọc kết quả OK hoặc FAILED mà lệnh in ra. Dùng printf '%s %s\n' để tạo dòng này sẽ tránh các lỗi định dạng khiến sha256sum từ chối file với no properly formatted checksum lines found.

#checksums#sha256sum#integrity#supply-chain#bảo mật