Git 3.0 將使 SHA-256 成為新的預設內容雜湊演算法,但這將是一場難以理解的昂貴且最終毫無價值且可避免的全球性災難。

我這幾年一直在觀察這個問題,主要是因為有更聰明的人專注於此,我也不喜歡當後座司機。然而,我認為 Git 3.0 的發布將讓所有人付出大量時間和焦慮,卻幾乎沒有什麼好處,且幾乎沒有人知道即將發生什麼。

所以請準備好爆米花,讓我來講述即將到來的 Git 3.0 重大破壞性變更如何成為一場龐大且昂貴的全球災難,且幾乎沒有實際價值。

我會簡短說明,因為你們大多數人可能已經有基本認識。

Git 是所謂的內容可尋址資料庫。這意味著如果你想在其中儲存和傳輸資料,Git 會計算內容的雜湊值,並在鍵值資料庫中使用該雜湊值作為鍵(值則是內容)。相同的內容總是會得到相同的雜湊值,且是全球唯一的。

這很好,因為相同的檔案內容不會被重複儲存。還有一個很酷的特性是提交會編碼前一個提交的雜湊值,這意味著這種完整性會向後傳播——你無法改變任何東西的雜湊值而不改變後續所有東西的雜湊值。這賦予它「密碼學完整性」,意味著對最新提交的雜湊實際上也涵蓋了之前數百萬個檔案內容、樹狀結構和提交。

在 Git 中,這個雜湊函數一直是 SHA-1。這是 Linus 在 2005 年 Git 啟動時選擇的,20 年來運作良好——速度相對快,且在實際上兩個不同檔案意外產生相同雜湊值幾乎不可能。

事實上,據我所知,Git 歷史上所有檔案、樹狀結構和提交中,從未發生過雜湊碰撞——數以十億計的檔案。

從數學角度來看,SHA-1 的 160 位元輸出,生日悖論界限意味著你需要約 1.4 千萬億億個隨機檔案(1.4 千兆兆個檔案——1,400,000,000,000,000 億億——難以有效描述)在單一專案中,才可能意外產生檔案雜湊碰撞。

不過有個問題,數學上 SHA-1 現在被視為半「破碎」,因為已經有公開的碰撞攻擊(2017 年的 SHAttered,2020 年的 SHA-1 是一團糟)——雖然尚未有實際可利用的案例,但理論上已可能。

因此,經過非常聰明的人大量努力,Git 3.0 預計將預設雜湊演算法從半「破碎」的 SHA-1 改為更強的 SHA-256。

但先停一下,什麼是「破碎」?

這很重要,因為這可能不是一般人理解的「破碎」意義。從密碼學雜湊的角度來看,破碎基本上意味著找到碰撞不再不可能。

換句話說,如果你投入足夠的資金和 GPU,對某些內容形態,你可以故意製造兩個不同的東西,雜湊值完全相同。

這意味著雖然意外產生兩個不同內容的合理檔案雜湊相同仍幾乎不可能,但技術上可以製造兩個不同檔案雜湊相同。

理論上存在攻擊向量,攻擊者可以用惡意版本替換檔案內容,而 Git 無法分辨,因為雜湊值數學上相同。

這些論文顯示 SHA-1 有一個特性,理論上可被現代 GPU 農場利用,以數萬美元成本製造碰撞,而 SHA-256 則沒有此問題(如果你非常在意,可以搜尋「linear message schedule sha-1 vs sha-256」)。

聽起來很可怕,對吧?有人會擔心嗎?

但讓我們退一步談談這些碰撞。

考慮攻擊時,雜湊函數有兩個主要問題(我必須非常簡化):一是「碰撞攻擊」,另一是「第二原像攻擊」。

「碰撞攻擊」是指攻擊者假裝是好人取得信任,故意生成兩個雜湊相同的檔案——一個良性,一個惡意。先給人良性檔案取得信任,然後用惡意檔案替換,因為雜湊相同,Git 無法分辨。甚至可以讓良性檔案的標籤或提交被簽名,看起來惡意檔案也被簽名。

「第二原像攻擊」是指看到想替換的檔案後,製造另一個惡意檔案,雜湊值相同,讓人不知情地下載。重要的是,原始檔案作者不必是攻擊者。

我想強調的是,雖然第二原像攻擊較令人擔憂,但幾乎沒有廣泛使用的雜湊函數會受到此攻擊。

即使 Git 使用 MD5(被視為極度破碎的雜湊函數),仍幾乎免疫於第二原像攻擊。MD5 被視為完全破碎,而 SHA-1 則更強。

「幾乎免疫」是指,即使地球上約 30 億 GPU 全部換成 RTX 5090,且全力運算 MD5,暴力破解特定原像仍需約 160 億年(約宇宙年齡)。

因此,任何現實的攻擊向量都依賴碰撞攻擊,即引入原始檔案的人已預先計算惡意版本,並打算在接受後注入。

但讓我們極度保守,假設第二原像攻擊很容易。假設你能在一小時內製造出任何已知檔案的第二原像。

現在你可以輕鬆替換任何檔案,製造不同的惡意檔案,雜湊值相同。恭喜!你現在可以攻陷任何代碼庫!

但有個小問題,你怎麼做到?

後續所有論點都依賴這些問題的答案,但這些答案通常未被討論。

即使假設 SHA-1 很容易破解,即使假設第二原像攻擊可行(或便宜),實際可利用的攻擊向量並不容易。

原因是,雜湊並非 SCM 世界中信任的機制。它確實提供密碼學完整性,但信任的根本基礎不是它。

Linus 在 Git 誕生時就明確表示這點。

我真的認為人們不應該把 sha1 當作「安全性」。真正的安全在於分發。

信任基於「你從哪裡拉取?」一直如此。

讓我們想像實際攻擊場景:有人在不知情的情況下惡意插入原始碼檔案(或更可能是二進位檔案)。

事實上,這種情況相當常見。

不是因為有人花數十萬美元買 GPU 產生隨機熵來匹配 SHA-1 校驗和。

而是因為有人社交工程攻擊,取得數百萬專案使用的 npm 套件寫入權限。現在不是一個難以偵測的二進位檔案,而是每個依賴該套件的專案都盲目拉取沒有先驗校驗的檔案。

這比暴力破解雜湊碰撞和操控不信任的拉取簡單、便宜且更可能成功億萬倍。

如果我要在 Android 中植入不信任代碼,賄賂或說服受歡迎下游專案的維護者,接管並注入難以偵測的代碼,比起製造易被偵測的雜湊碰撞並放在沒人會拉取的 URL 簡單多了。

你認為沒有疲憊的開源維護者會接受 4 萬美元一次性付款交出維護權嗎?這樣你就不需要租用 GPU,一天內就能替換任何檔案內容。

換句話說,當無償開源維護者和低信任的套件管理平台存在時,雜湊碰撞攻擊可能是最愚蠢的取得不信任代碼方式。

回到 Linus 的論點,我不會因為信任 GPG 簽署最新提交的 SHA 而從 https://github.com/rust-lang/rust 拉取代碼,並假設任何來源都沒問題。

我從那裡拉取,是因為我信任 GitHub 的認證機制,認為維護者不會不知情地被人惡意推送。這也是為什麼我不會從 https://randomhash.onion/hAAAxx0r/rust 拉取,僅因為某封郵件告訴我。

我不在乎雜湊演算法是什麼,也不在乎生成大型二進位檔案雜湊碰撞可能少花多少億年計算時間,Rust 明顯不會把這種檔案提交到倉庫。

這根本是荒謬的前提。

我所知道的所有攻擊場景,都讓我覺得即將強制推行的昂貴 SHA-256 遷移毫無必要。所有問題都能用更強、更簡單的來源和內容保護輕鬆解決,而非稍強的雜湊演算法。

如果我們認為 SHA-1 足夠好且快速,能為受信任的倉庫產生唯一鍵,且接受雜湊本身不應用於信任,那就沒理由替換它。甚至用 MD5 也可能沒問題。

意外內容碰撞在合理代碼庫中幾乎不可能,其他問題可由簽名驗證、外部認證和社交信任機制處理。

若不接受此觀點,我們將陷入理論碰撞漏洞被發現後,不斷遷移整個 Git 生態系統的循環。SHA-1 遷移到 SHA-256,然後量子電腦破解 256,又回到原點。

這只是因為我們混淆了密碼學完整性與信任。

等一下,Scott,你說這會是場災難,這不會誇張嗎?

不管怎麼算,成本都不會低也不會簡單。Emily Shaffer 最近在 Google 的演講中說明他們如何準備應對這問題,情況並不樂觀。

讓我們分析 Git 3.0 預設啟用 SHA-256 時會發生什麼。

首先,所有用 git init 新建的倉庫將使用 SHA-256 雜湊演算法。你今天就能試試 git init --object-format=sha256。

你會注意到(除了雜湊值更長)你無法將此代碼推送到 GitHub,但這應該會在 Git 3.0 發布前解決。這可能是 3.0 延遲的主要原因。

但當你想推送到 GitHub(或其他主機)時,必須在伺服器建立倉庫時告知這是 sha256 專案。每個專案只能是其中一種格式,不能混用。

這會讓人困擾,因為你需要知道本地 git init 用的是哪個版本,並確保在 GitHub 建立伺服器倉庫時選擇正確格式。

原因有幾個。依主機標示方式,很難知道上游倉庫該用哪種格式。你可能用 256 格式上游,卻嘗試用 pre-3.0 版本本地推送,或反之亦然。

此外,對於函式庫來說,這很麻煩,因為子模組只能用相同格式的專案,必須維護兩個版本,才能同時被舊專案和新專案使用。

可能主機會透過保留另一格式的鏡像來支援兩種格式,但這會增加 GitHub 等站點的負載,並加劇信任問題。

若現有專案決定從 SHA-1 轉換到 SHA-256,必須將專案中所有物件轉換格式,這會破壞所有現有簽名。且所有使用者必須同時切換,避免分支衝突。或者設置鏡像並切換寫入權限,但仍無法解決其他未有 256 版本鏡像的物件替換問題。

轉換後,所有含 SHA-1 雜湊的 URL、Slack、郵件連結將失效,需重新導向(如果可能,且未換主機)。

全球所有內部或其他工具若預期雜湊長度為 40 字元,將會壞掉或需更新以偵測格式。

雖然 Git 核心支援兩種格式,但大多數函式庫不支援,幾乎沒有完整支援。

因為 Git 是非重入、GPL 授權且不可連結的庫,生態系統多數專案使用從零開始的重寫版本。這些函式庫支援零或部分,所有非透過 Git 執行檔的腳本和工具都會在新倉庫上出現不同程度的故障。

我可以繼續說,但這是個龐大且仍未解決的問題,沒有人提出共識或好方案讓這變得容易。Emily 甚至提到 Google 可能會設置系統級覆蓋,確保所有新專案仍用 SHA-1,盡可能延遲 3.0 預設。

我個人認為這是為理論問題尋找不必要的解決方案,即使是理論且不實際的問題,也能用更簡單直接的方式解決,針對少數真正在意的專案。

不要用雜湊來信任內容。

就像 Linus 20 年前說的。

如果你假設倉庫來源是可信的,那這些問題根本不重要。99% 的人只與可信倉庫合作。對大多數 Git 使用者來說,複雜的後門雜湊碰撞攻擊無關緊要,因為如果寫入權限被攻破,任何人都能在主分支放入任何東西,沒人會注意。你不需要複雜的物件替換技巧來騙人。

如果你不完全信任來源(剩下 1%),或許我們應該嘗試其他更簡單、更好的方法,而非迎來全球性的 Hashmageddon。

如果我們用不同角度看這事,或許可以簡單地用另一種演算法獨立重新雜湊樹狀內容,然後將該標頭注入簽署的物件中,讓簽名同時涵蓋兩種雜湊?一個(SHA-1)用於內容檢索,另一個(例如 SHA-256)用於獨立內容驗證。

我想深入探討這點,因為這種方法幾乎能解決所有理論問題,且不必分裂整個 Git 生態系統,避免讓大家困擾。

假設你想依賴外部函式庫或供應商,並想減少物件碰撞攻擊風險。你無法信任 commit 或 tag 上的 SSH/GPG 簽名,因為它簽的是用於儲存內容的 SHA-1 雜湊,而這已證明可被替換而不被偵測。

在簽署 commit 或 tag 時,獨立計算樹狀內容的 SHA-256(或 BLAKE3 等)雜湊,並將其作為新標頭注入該物件,然後簽名。這樣簽名同時涵蓋基於 SHA-1 的內容和歷史,以及獨立計算的樹狀內容雜湊。

當你將此拉入另一專案時,可以選擇用公鑰驗證簽名,確保檢出的內容同時符合兩種簽名。

這不是新點子。Colin Walters 的 git-evtag 自 2015 年起幾乎做了這件事:它是 git tag -s 的替代品,在簽名前加入 Git-EVTag-v0-SHA512 校驗碼,涵蓋 commit、樹狀結構和所有 blob(遞迴子模組),可獨立於同一樹的 SHA-1 驗證。

如果 SHA-256 被破解,我們可以新增支援其他雜湊函數,關心的專案可開始要求使用(例如 tree-blake3 標頭)。我們甚至可以同時使用多種雜湊,驗證其中任意或全部以確保內容信任。每當演算法被破解,只需新增雜湊和驗證方法,而非遷移所有專案。

缺點是可能無法信任每個 commit,只能信任帶有標頭且已簽名的物件,但對大多數關心此事的專案來說,這應該沒問題。此時簽名的信任不會向下傳播整個歷史,但這真的是大問題嗎?這類專案幾乎都鎖定標記版本。

建立此獨立內容簽名會稍微增加成本,但只在簽署時增加。我做了概念驗證,測試了我能想像的最壞情況——Chromium 及其所有子模組遞迴校驗。

這是 35GB、210 萬檔案的工作樹。我的工具在 M5 Mac 多線程下 5 秒內生成校驗碼,這幾乎是最壞情況。

Linux 树(1.5GB)耗時 257 毫秒,Git 專案耗時 17 毫秒。大多數專案甚至可以在每次 commit 中加入此簽名。且可回溯補簽,輕鬆為過去 commit 加入簽名校驗碼。

任何關心的樹狀結構都可獨立校驗並簽名,且不改變核心雜湊模型。技術上這比單用 SHA-256 更安全,因為必須同時在兩種雜湊中產生碰撞才會有問題。

我們可以停止用 SHA-1 來信任內容,而不必丟棄 SHA-1 或破壞整個生態系統。我們可以新增另一個內容信任向量,而不造成大量混亂,僅針對少數有信任問題的專案。

謝謝收看我的 TED 講座。

這些論點並非新鮮事。這些討論已在 Git 郵件列表上由比我更聰明的人討論多年。本文只是想在按下 3.0 觸發鍵前,讓大家稍作反思,看看是否要重新考慮,避免影響整個 Git 生態系統。

這種第二簽名方法也可解決 NIST 合規問題。NIST 2030 年 SHA-1 截止日期是針對「用於加密保護」的 SHA-1,而非 SHA-1 在堆疊中存在。如果每個簽名也涵蓋 SHA-256 內容雜湊,SHA-1 就不再用於保護,只是內容尋址鍵。FIPS 模式系統已處理此問題:OpenSSL 3 允許應用程式要求非 FIPS 實作的雜湊(Python 的 usedforsecurity=False 就是這樣),Git 也不透過 OpenSSL 產生物件 ID,而是用內建 SHA-1 程式碼,完全不在任何 FIPS 加密模組內。

我甚至可以更進一步,完全移除 sha1dc(碰撞偵測)計算成本,這是我們為避免特定碰撞類型所付出的代價。如果假設這不是檢查的重點,我們可以加快 clone 和 push 的速度。

Scott Chacon 是 GitHub 和 GitButler 共同創辦人,致力於打造現代版本控制的創新工具。他是《Pro Git》作者,並在全球演講 Git 和軟體協作。

JJ Con 2026 里斯本會議的所有演講現已上傳 YouTube,這裡有快速概覽。

我用兩個 AI 代理自動化設計代幣發布,每次運行只需六分鐘。我的插件多年來的按鈕操作只需幾秒。

最新本地大型語言模型在最新 Apple 硬體上的一般編碼任務表現如何?

Git 3.0 預設改用 SHA-256 將帶來高昂代價的錯誤Git 3.0 預設改用 SHA-256 將帶來高昂代價的錯誤Git 3.0 預設改用 SHA-256 將帶來高昂代價的錯誤Git 3.0 預設改用 SHA-256 將帶來高昂代價的錯誤Git 3.0 預設改用 SHA-256 將帶來高昂代價的錯誤Git 3.0 預設改用 SHA-256 將帶來高昂代價的錯誤