雜記 › 技術筆記 › 下載的檔案被竄改了嗎?用 MD5 校驗 1 分鐘驗明正身

下載的檔案被竄改了嗎?用 MD5 校驗 1 分鐘驗明正身

去年冬天我給 NAS 做了一次冷備份,兩顆 4TB 硬碟,rsync 跑了將近十一小時,跑完只看了結束碼是 0 就收工。兩個月後要還原一個記帳用的壓縮檔,解壓時報 unexpected end of archive——那個包本來 2.1GB,磁碟裡只剩 1.4GB,中間某次寫入悄悄斷了。我沒有任何辦法證明其他三百多個包是好的。從那之後我的備份流程裡多了一步:算完雜湊、把清單存到另一台機器上。雜湊到底能證明什麼、對哪一類問題無能為力,是那之後才弄清楚的。

一、雜湊是內容的指紋,不是加密

MD5 把任意長度的資料壓成 128 位元、通常寫成 32 個十六進位字元的一串。三個特性決定了它能做什麼:輸出定長,一個 3 位元組的文字和一個 4GB 映像檔算出來的結果一樣長;單向不可逆,拿到 5d41402abc4b2a76b9719d911017c592 也推不回原文(它是 hello 的 MD5,空字串的是 d41d8cd98f00b204e9800998ecf8427e);雪崩效應,改一個位元,結果面目全非。

所以「MD5 加密」這個說法本身是錯的,它只能回答兩個問題:這兩份資料是不是同一份?這份資料還是不是我拿到的那一份?想保密要靠加密,想存口令要靠加鹽的慢雜湊,兩者都不該拿 MD5 頂替。

二、校驗的關鍵其實是「期望值從哪來」

很多人把流程記成「下載—算雜湊—比對」,但決定結論價值的只有第三步裡參照物的來源。分開看:

期望值來源校驗通過說明什麼校驗失敗說明什麼
官網 HTTPS 頁面單獨公布檔案與官網那份一致,沒有在傳輸中壞掉傳輸截斷、被替換或版本拿錯,重新下載
和檔案同一個第三方下載站只能說明這兩樣東西配套,幾乎不能說明安全連站家的說明都抄錯了
GPG/程式碼簽章,另附公開金鑰來源可信且未被竄改,這才是防竄改簽章無效,別安裝
自己上次備份時記錄的清單這段時間裡檔案沒變、沒壞儲存媒體或寫入出問題了,立刻找另一份副本

中間那一行是我覺得最該寫進說明書的:攻擊者替換安裝包時,順手改掉頁面上的 MD5 只需要幾秒。雜湊保證的是「完整性」,不是「真實性」,後者要靠簽章和管道信任。

三、我實際怎麼算,用哪些指令

系統內建的指令先記住,不依賴網路也能用:

平台指令輸出
Windows(cmd)certutil -hashfile app.iso MD532 位元十六進位
Windows(PowerShell)Get-FileHash -Algorithm SHA256 app.iso64 位元十六進位
macOSmd5 app.iso / shasum -a 256 app.isoMD5 / SHA-256
Linux、Git Bashsha256sum app.iso;整批 sha256sum -c SHA256SUMS逐行 OK / FAILED

手邊只有一兩個檔案、不想敲路徑時,我把它們直接拖進檔案 MD5 計算:批次拖入後一次得到 MD5、SHA-1、SHA-256 三種值,同時列出檔名、大小、類型與修改時間,雜湊相同的會標紅——上次清重複安裝包就是靠這個標紅挑出來的。計算用瀏覽器內建的介面完成,檔案不上傳;幾十 GB 的映像檔我還是用命令列更穩。

備份這邊我的固定動作是三步:拷完 → 在來源端產生一份 SHA256SUMS.txt → 把清單複製到另一台機器。還原前 -c 跑一遍,兩百多個包哪幾個壞了直接看得到。文字類的短字串(介面簽章用的原文)我另開一頁算,MD5 工具支援 16 位與 32 位、大小寫切換和多行批次。

四、MD5 現在還能不能信

答案取決於對手是誰。MD5 的碰撞已經被實際構造出來,2008 年研究者利用它偽造過 CA 憑證,所以對抗性場合都不該再用:軟體簽章、憑證鏈、口令儲存,一律換 SHA-256 起步。反過來,「我這份檔案在拷貝時有沒有斷」這種非對抗場景它照樣夠用,因為壞檔不是有人專門針對你的檔案構造出來的。

用途合適的演算法原因
下載完整性、備份自檢MD5 或 SHA-256只需發現無意損壞
安裝包、映像檔對外公布SHA-256 + 簽章MD5 可被碰撞,擋不住蓄意替換
口令儲存bcrypt / scrypt / Argon2MD5 太快,加鹽也救不了
介面簽章、防重放HMAC-SHA256需要帶金鑰的認證碼,雜湊計算器一次出 MD5 到 SHA-512 六種結果並支援 HMAC
檔案去重MD5 起步速度快;重要資料去重後再抽查一次內容

五、幾個會讓人白排查的坑

  • 16 位和 32 位不是兩種演算法:16 位只是取 32 位結果的第 9 到 24 個字元。比對前先確認長度,不然會以為「完全對不上」。
  • 大小寫:a-f 與 A-F 是同一個值,只是顯示格式。腳本比對前統一轉小寫。
  • 換行符號改變文字雜湊:同一份 README.md 在 Windows 下是 CRLF、Linux 下是 LF,MD5 必然不同;Git 的 core.autocrlf 也會造成同樣結果。比文字雜湊前先統一行尾。
  • 改名、改時間不影響雜湊:指紋只算內容,所以「我改了檔名雜湊應該變」的直覺是錯的,也正因如此它才適合用來判斷兩份內容是否相同。
  • 外層包和內層檔案是兩回事:zip 的雜湊一致只保證包沒壞,包內有沒有被替換要看逐檔清單。
  • 目錄沒有單一雜湊:檔案順序、權限、時間戳都會改變打包結果。核對整個目錄要用逐檔清單或 rsync 的校驗模式。

六、常見疑問

Q:兩個檔案 MD5 相同就一定完全一樣嗎?

日常場景可以這麼判斷,隨機損壞導致相同的機率低到可以忽略。只有當你面對一個會主動構造碰撞的對手時才需要升級演算法。

Q:官網只給 SHA-256,我機器上只有 md5sum 怎麼辦?

換演算法而不是換檔案:PowerShell 的 Get-FileHash、macOS 的 shasum -a 256、Linux 的 sha256sum 都能直接算,不必重新下載。

Q:校驗不一致該怎麼處理?

先重新下一次再算,仍不一致就當它被動過:不要執行,不要用其中的檔案,同時確認自己是不是拿錯了版本或是從鏡像站下載的。

Q:備份一定要留雜湊清單嗎,直接定期重拷不行?

重拷不能告訴你磁碟裡那份是不是已經壞了,只能賭。清單的成本是幾十秒計算,收益是還原前就知道哪些包可用。

Q:算大檔案要多久?

主要卡在磁碟讀取而不是演算法,同一顆硬碟上 SHA-256 和 MD5 的耗時差別往往小於讀寫速度本身。機械硬碟上等幾分鐘正常,瀏覽器裡過大的檔案還會受記憶體限制。

那次壞檔最後沒有造成實質損失——同批資料在另一台機器上還有一份舊副本,只缺了兩個月。真正改變的是流程:現在備份一結束我就把雜湊清單寫到第二份儲存上,因為「有一份備份」和「知道備份是好的」是兩回事。

📎 相關文章

PNG 壓了三遍只減 426 位元組:無損壓縮的真實邊界 2026-10-22 WebP 轉 PNG 後體積漲了幾倍:什麼時候必須轉,怎麼把漲幅壓住 2026-10-22 截圖縮到四分之一,小字糊成一團的三種原因 2026-10-22 同樣裁 300×300,頭像為什麼總偏右下角半格 2026-10-22 按每月 1.7 倍預估 18 個月,腳本和表格為什麼給出兩個數 2026-10-22