這根本不是 BASH 的 BUG,是特征!
在前幾天看到 CVE-2014-6277 這個(gè) BASH 的 bug 的時(shí)候,我就覺(jué)得挺奇葩的:這這種明顯是有意實(shí)現(xiàn)的功能怎么會(huì)存在這么大的安全隱患呢?我不是專門(mén)搞安全的,同時(shí)覺(jué)得,這個(gè) bug 可能雖然影響廣泛,但并不是什么很有技術(shù)含量的利用思路。所以我就把這個(gè)事情放下沒(méi)去想它。然而,隨之而來(lái)的國(guó)內(nèi)國(guó)外的各種媒體宣傳、安全專家的聯(lián)名建議、茶余飯后的坊間暢談……對(duì)于 BASH 的這個(gè) bug 無(wú)人不認(rèn)為是個(gè)大 bug。不少人為此還在幸災(zāi)樂(lè)禍……但是我卻沒(méi)從各種評(píng)論中找到我的問(wèn)題的答案。
但是,當(dāng)我看到這篇隨筆時(shí),我不得不贊同作者的觀點(diǎn):這根本不是 BASH 的 bug!
所以我將原文翻譯至此,希望能夠帶來(lái)一些思考。
也許我們今天看到的一個(gè)愚蠢的 bug,在歷史上的某一天,是一個(gè)有意而為之的神奇特性。也許我們應(yīng)該思考的不僅僅是這一刻的 bug 或者安全隱患本身,而是在軟件項(xiàng)目這個(gè)***工程和創(chuàng)作品雙重特性的活動(dòng)中,如何有效的保證某個(gè)特性不會(huì)變成 bug。所以什么規(guī)范了,文檔了,可真得不是紙上談兵!
不過(guò)話說(shuō)回來(lái),無(wú)論如何,我仍然堅(jiān)信:“Less is exponentially more!(大道至簡(jiǎn))”少一點(diǎn) Feature 或許就是少一點(diǎn) Bug 呢?
————翻譯分隔線————
我想要討論一下,關(guān)于這個(gè) BASH 的安全問(wèn)題其實(shí)不是一個(gè) bug。這顯然是一個(gè)特性。誠(chéng)然,這是一個(gè)被錯(cuò)誤實(shí)現(xiàn)并被錯(cuò)誤使用的特性。不過(guò)它仍然是個(gè)特性。
問(wèn)題在于它是在 25 年前設(shè)計(jì)的。Apache 在那五年之后才出現(xiàn)!沒(méi)錯(cuò),那個(gè)時(shí)候互聯(lián)網(wǎng)已經(jīng)有了,不過(guò)那是個(gè)親密無(wú)間的小圈子。在那時(shí),互聯(lián)網(wǎng)軟件和協(xié)議的安全根本不在考慮之列,更不用說(shuō)開(kāi)發(fā)像 shell 這樣的程序的時(shí)候了。
因此,我們討論的上下文是設(shè)計(jì)一個(gè) UNIX shell,其子進(jìn)程用非正式且常見(jiàn)的方式創(chuàng)建和運(yùn)行。當(dāng)創(chuàng)建一個(gè)新的子進(jìn)程,環(huán)境變量可以用于從父進(jìn)程向子進(jìn)程傳遞某些數(shù)據(jù)。在 BASH 的情況里,這是一個(gè)需求提到的特性,在 BASH 父進(jìn)程中定義的函數(shù)可以傳遞給子進(jìn)程并獲得定義。使用環(huán)境變量傳遞這些函數(shù)的定義是自然而然的事情。
而在環(huán)境變量傳遞的函數(shù)定義之后可以執(zhí)行任何命令,就是那個(gè)略微超出設(shè)計(jì)規(guī)格的實(shí)現(xiàn)了。由于大部分情況下 BASH 程序在環(huán)境變量中存放的是要傳遞的函數(shù),所以通常不會(huì)有其他命令。
不過(guò)在 BASH 被設(shè)計(jì)的時(shí)候,一個(gè)用戶是否能添加命令到這樣的環(huán)境變量中,會(huì)被認(rèn)為是一個(gè)特性。在任何情況下,子進(jìn)程的行為依賴于配置這個(gè)環(huán)境變量的用戶,所以沒(méi)有任何關(guān)于安全方面的擔(dān)憂。
這個(gè)特性被記錄在用于導(dǎo)出內(nèi)建命令的 -f 選項(xiàng)中。而使用內(nèi)容以“() {”開(kāi)始的環(huán)境變量在函數(shù)定義后可以包含更多的命令的實(shí)現(xiàn)細(xì)節(jié)并沒(méi)有文檔記錄,不過(guò)仍然可以認(rèn)為是一個(gè)特性。
問(wèn)題在于,五年后,新的使用 BASH 作為子進(jìn)程,并仍然使用環(huán)境變量傳遞數(shù)據(jù)的軟件被開(kāi)發(fā)出來(lái)(Apache,DHCP 等等)。不幸的是,一些數(shù)據(jù)不再是來(lái)自可信的本地系統(tǒng)用戶(譯注:典型的物理安全信任),而是來(lái)自這個(gè)星球上的,互聯(lián)網(wǎng)上任意的用戶或者程序。同時(shí),沒(méi)有文檔記錄的(但已經(jīng)被發(fā)布的)BASH 的特性卻被遺忘了。
這是一個(gè)關(guān)于 UNIX 系統(tǒng)的古老觀念,環(huán)境變量可以由父進(jìn)程控制,還有更古老、更通用的觀念是輸入的數(shù)據(jù)應(yīng)當(dāng)是合法的。
大概像 Apache 這樣的程序都對(duì)環(huán)境變量進(jìn)行了正確的過(guò)濾。但不幸的是,它們?cè)谡_校驗(yàn)輸入的數(shù)據(jù)時(shí)失敗了,因?yàn)樗鼈儾⑽纯紤]到以“() {” 開(kāi)始的數(shù)據(jù),將會(huì)被它們產(chǎn)生的 BASH 子進(jìn)程解釋。如果這里有 bug 的話,也不是在 BASH 中,而是在 Apache 以及其他面向網(wǎng)絡(luò)的程序,沒(méi)有正確的驗(yàn)證和控制它們傳遞給 BASH 的數(shù)據(jù)。
也就是說(shuō),BASH 有自己的問(wèn)題,只不過(guò)跟大多數(shù)軟件一樣:它缺少一個(gè)規(guī)范的文檔,并且擁有沒(méi)有記錄的特性。
我們的問(wèn)題不在于 BASH bug,這基本上與 Ariane 5 的 bug 類(lèi)似:使用來(lái)自早期的系統(tǒng)中,規(guī)范已經(jīng)過(guò)期的模塊。
在該特定情況中,使用過(guò)期的規(guī)范的原因似乎是由于沒(méi)有任何規(guī)范被記錄下來(lái),并且對(duì)于相關(guān)的實(shí)現(xiàn)細(xì)節(jié)也沒(méi)有文檔。但從另一方面來(lái)說(shuō),這是自由軟件,因此查閱源代碼的難度就跟在臉上找鼻子一樣容易。當(dāng)復(fù)用一個(gè)沒(méi)有規(guī)范和文檔的模塊時(shí),檢查源代碼的實(shí)現(xiàn)應(yīng)當(dāng)是一個(gè)標(biāo)準(zhǔn)流程,不過(guò)顯然 Apache 或 DHCP 的開(kāi)發(fā)者沒(méi)有這么做。
bug 還在那里,就像 Ariane 5 的 bug 不是 Ariane 4 的 bug 一樣!