3.3 編輯內(nèi)存分配標(biāo)準(zhǔn)和使用address guard或是sanitizer
如果在對抗來自潛在的漏洞攻擊,在未知的環(huán)境里你現(xiàn)在就要使用一個(gè)程序怎么辦呢?
一個(gè)方法就是使用偵測在分配的內(nèi)存的最后區(qū)域來實(shí)現(xiàn)讀的機(jī)制,但是使用這種方法你不能改變測試怎么運(yùn)行;這個(gè)觀點(diǎn)就是你實(shí)際上用的在一個(gè)分配要求下的多重分配機(jī)制。
存在運(yùn)行時(shí)間偵測漏洞的多種機(jī)制;這就是一些例子:
1、Address sanitizer。你要重復(fù)調(diào)試一個(gè)程序時(shí)可以使用它。在LLVM/clang和gcc編輯器上Address sanitizer就是一個(gè)標(biāo)志,這相對與C程序的軟件簡單的多,這占了平均運(yùn)行的73%,和2x-4x的存儲。這不是你想只能手機(jī)上做的,很多繁忙的網(wǎng)站不歡迎這些。現(xiàn)在的計(jì)算機(jī)比過去的有更好的能力和存儲,一些環(huán)境中就會被接受…這就是你能夠立刻對抗未知攻擊的可能性。Address sanitizer在偵測一長系列潛在問題上很有作用,包括大量無效的緩沖區(qū)訪問。Address sanitize不是在所有的編輯器里都無效;這要在其他的如C, C++, 和Objective-C編輯器中來添加它。
2、Intel Memory Protection Extensions。MPX新增了叫邊界寄存器的寄存器來控制指針的邊界,使用新的指令來運(yùn)行和使用邊界。MPX使用Skylake架構(gòu),但是在2014年這些CPU不能和公眾見面。這要更長的時(shí)間被廣泛的得到使用,那不能組成non-Intel系統(tǒng)。
3、內(nèi)存分配保護(hù)頁面。一些系統(tǒng)內(nèi)存分配能夠在分配一個(gè)用來組織讀和寫的內(nèi)存后,添加一個(gè)未定的保護(hù)頁面。這些能否會禁止和阻止心臟出血漏洞,這些取決于它是如何實(shí)施的。OpenBSD的malloc的實(shí)施支持保護(hù)界面。在OpenBSD中,G選項(xiàng)會導(dǎo)致“使用保護(hù)頁面后的每個(gè)頁面分配到的數(shù)據(jù)大小過大,這些會導(dǎo)致訪問錯(cuò)誤。”這會與P選項(xiàng)進(jìn)行組合來移動(dòng)一個(gè)頁面內(nèi)的分配。OpenBSD機(jī)制可以啟動(dòng)特定的程序,甚至是特定的默認(rèn)情況下,在整個(gè)系統(tǒng)中啟動(dòng),這樣就可以在更多的環(huán)境下得到保護(hù)。OpenBSD的malloc機(jī)制有一個(gè)弱點(diǎn):即使開啟G和P兩個(gè)啟動(dòng)項(xiàng),少量的分配不會立刻完成保護(hù)頁面。如果OpenBSD的保護(hù)界面機(jī)制能夠在較少量的分配后立刻插入一個(gè)保護(hù)頁面,我認(rèn)為會更好,即使這可能會對速度和內(nèi)存大小有很大的影響。但是即使是這樣,開啟G和P就意味著所有大于半頁的分配會立刻跟隨一個(gè)保護(hù)頁面,并且分配一個(gè)半頁或是更少將會泄漏半頁。這就會明顯的減少泄漏規(guī)模,相比于原來心臟出血漏洞攻擊時(shí)泄露的64K。內(nèi)存分配必須要對齊,所以保護(hù)頁面可能泄漏一些字節(jié)的信息,這就取決于如何實(shí)施的。我懷疑Address sanitizer要比增加保護(hù)頁面的分配快,但是添加保護(hù)頁面不要求更多的程序來進(jìn)行重新編譯,這就是它的優(yōu)勢。不幸運(yùn)的是GUN的libc中malloc不能有附加的這些功能。
當(dāng)然,這種方法假設(shè)你有一個(gè)能啟動(dòng)(1)的內(nèi)存保護(hù)機(jī)制和(2)內(nèi)存保護(hù)機(jī)制也會在這種機(jī)制下工作。很多的機(jī)制可以對抗緩存寫溢出,不是緩存讀溢出,心臟出血漏洞就利用了讀溢出。例如:GUN的libc中的malloc()可以選擇MALLOC_CHECK_。這就是防止寫溢出的方法,但是我不認(rèn)為它能對抗類似心臟出血的讀溢出。同樣,Dmalloc’s fence-post檢測“在程序從這個(gè)區(qū)域中讀取時(shí)不能注意到,只有在寫入時(shí)才會有通知?!蔽矣X得GUN的libc和一些類似的運(yùn)行過程中也要增加類似OpenBSD的malloc的保護(hù)頁面機(jī)制,從而對抗讀溢出。
這是一個(gè)可以減少傷害的方法,而不是一個(gè)消除個(gè)問題的辦法。從安全的角度來看這種方法把缺少保密變成了缺少實(shí)用。然而在很多的情況下這是一個(gè)很好的協(xié)議。一旦受到攻擊,這個(gè)方法就會使問題變成可視化的,一旦問題可視化后就變的很好改正了。
這個(gè)方法很容易和honeypot或honeynet聯(lián)系在一起。在honeypot或honeynet系統(tǒng)上設(shè)置這些硬化的方法。如果攻擊者試圖破壞軟件,這個(gè)軟件不會崩潰,并且會記錄下攻擊者的重要日志和追蹤記錄。Forensics就會偵測到一些專門利用一日0攻擊。我認(rèn)為通過一些日志記錄結(jié)合入侵偵測系統(tǒng)來進(jìn)行追蹤;在硬化密碼庫中發(fā)生了崩潰,就會特意的記錄下。這就會使普遍的偵測利用一日0攻擊更加的容易。分布核心基礎(chǔ)設(shè)施組織和在互聯(lián)網(wǎng)上其他組織都可以建立這些類保護(hù)我們。
雖然這種方法并不能完全解決這個(gè)問題,但是他能提供一個(gè)有力的緩解功能。一些發(fā)行者或組織可能需要在特定情況下使用這些措施,或至少使這些措施變得更容易。
修改代碼不會很復(fù)雜,并且重新編譯也是很簡單的。不過,在很多的設(shè)備上性能的欠佳都體現(xiàn)的很顯著,可能是你失去了硬件后的性能。特別是在使用Address sanitizer時(shí),你會失去一半的速度。因此,我指望使用這種復(fù)雜的解決方法,就要考慮到硬件的消耗。在很多的情況下,會影響到運(yùn)行,在智能手機(jī)上就會降低運(yùn)行速度和電池的壽命,對于當(dāng)前流行的服務(wù)器的話,也會減慢反應(yīng)速度和增加電量的消耗。如果將來的CPU能支持Address sanitizer,對速度的影響就會顯著的降低了。我希望CPU制造商能考慮下這點(diǎn)。
3.4 關(guān)注各個(gè)領(lǐng)域的手動(dòng)檢測驗(yàn)證
漏洞的代碼是人為審查的,顯然只有一個(gè)人來審查是不行的。
然而,大量的工作就要有專門的人來檢查每個(gè)領(lǐng)域,為確保得到有效的驗(yàn)證,有時(shí)會在計(jì)算機(jī)安全中得到一個(gè)不好的名字。我懷疑的原因之一就是有時(shí)候,那些部署清單的人在做什么,之后也不能很好的利用它。但是出色的飛行員經(jīng)常使用儀表盤,他們知道是做什么的。如果補(bǔ)丁是他們使用清單上工具后的唯一成果,“必須證明每一個(gè)不可信的數(shù)據(jù)字段進(jìn)行驗(yàn)證,”之后這個(gè)漏洞被反擊。
列入人為檢查/審計(jì)的一部分,和一些簡單的方法不同。然而,這確實(shí)要就檢測人能了解所有的補(bǔ)丁,它不能依靠以前的代碼來得到幫助。
3.5 對文件包括注解系統(tǒng)的配置源代碼的弱點(diǎn)分析
傳統(tǒng)的源代碼弱點(diǎn)分析是找不到心臟出血漏洞,因?yàn)樗麄兪褂玫氖峭ㄓ玫膯l(fā)式方法,代碼復(fù)雜,在這種情況下不能很好的起到作用。它總是你能看到的最簡潔的代碼,但是基于你要完成的任務(wù)總是會有一些復(fù)雜性,真實(shí)情況下人類是不能達(dá)到完美的簡約。Coverity公司正在開發(fā)一些新的,他們認(rèn)為能夠檢測到心臟出血漏洞的啟發(fā)方法…并且對他們是有好處的。至少有一個(gè)人已經(jīng)使用了類似的啟發(fā)方式。事實(shí)上,我希望所有的代碼分析工具都能得到改善,從而發(fā)現(xiàn)他們以前不能發(fā)現(xiàn)的漏洞。但通用的啟發(fā)方式在某個(gè)特定的時(shí)間點(diǎn)只能達(dá)到這個(gè)程度,你能做的更好嗎?
回答是肯定的,它叫做為上下文配置的源代碼弱點(diǎn)分析工具?;舅枷胧牵汩_始使用一個(gè)惡源代碼弱點(diǎn)分析工具,之后你在提供更多的你要分析的程序的信息。這種方法比僅僅運(yùn)行源代碼弱點(diǎn)分析工具需要更多的時(shí)間,而這些額外的信息通常要和一個(gè)特定的工具聯(lián)系在一起。然而,提供你需要的程序的信息,源代碼弱點(diǎn)分析工具可以能更好的工作。
Klocwork已經(jīng)表示這種方法對心臟出血漏洞是很有效的。
現(xiàn)在讓我們來談?wù)勛⑨屜到y(tǒng)。在很多的地方來為靜態(tài)分析工具提供這種額外的信息。一個(gè)常用的方法就是對程序添加額外的注釋機(jī)制,在修改程序時(shí)會使用他們。這些注解可能在更改的代碼中進(jìn)行添加,添加在注釋中,或是加在單獨(dú)的文件里。使用C的工具或是注解包括Microsoft’s SAL、splint、Deputy、Oink/CQual++、cqual、和Frama-C ANSI/ISO C。你可以很容易得出添加這些信息確實(shí)是一個(gè)不同的技術(shù)。
認(rèn)真的使用這些額外的注解來對抗漏洞就要有很大的工作量,如果從現(xiàn)存的代碼來說。對于C來說存在許多不同的不兼容的注釋系統(tǒng)。對于他們來說是沒有什么標(biāo)準(zhǔn)的,這會進(jìn)一步的阻礙他們的使用。畢竟,它需要添加注釋和這些注釋會把你鎖到一個(gè)特定的工具中;Microsoft SAL會有更多的問題,沒有FLOSS的應(yīng)用和這只能在Windows上使用。我認(rèn)為如果針對每個(gè)主要的編程語言包括C在內(nèi),任何一種單一被廣泛接受的標(biāo)準(zhǔn)注釋符號,注釋系統(tǒng)將會更加廣泛的應(yīng)用。當(dāng)沒有這么個(gè)符號時(shí),像C語言等語言就會很難得到那樣一個(gè)協(xié)議。Peter Gutmann已經(jīng)寫了一些他的經(jīng)歷。
但是,注解系統(tǒng)是由一些好處的,注解系統(tǒng)能夠發(fā)現(xiàn)簡單的漏洞,不用在轉(zhuǎn)變成不同的語言。他們也很少去轉(zhuǎn)變成不同的語言,當(dāng)然,這并不沖突;你可以切換語言,使用一種新的語言在注釋系統(tǒng)中。
3.6 實(shí)現(xiàn)100%的分支覆蓋率
或許有另一種方法可以發(fā)現(xiàn)心臟出血漏洞,實(shí)現(xiàn)100%的分支覆蓋率。如前面所述,在一個(gè)缺失特定程序的中輸入有效的驗(yàn)證碼時(shí),分支測試是不檢測到的。但是分支覆蓋可以在不同的實(shí)現(xiàn)方法中檢測未經(jīng)驗(yàn)證的分支程序。努力實(shí)現(xiàn)一個(gè)測試套件,讓多個(gè)實(shí)現(xiàn)全覆蓋分支大大增加了丟失了驗(yàn)證碼和遺漏了異常處理時(shí)被檢測到的可能性。更強(qiáng)的測試覆蓋措施也會工作的很好,如修改條件/判定語句。
這個(gè)測試套件必須要包含多個(gè)應(yīng)用,實(shí)現(xiàn)100%的分支覆蓋。更重要的是,有不同的實(shí)現(xiàn)方式,效果更好。最終,用一個(gè)特別的方法來發(fā)現(xiàn)漏洞。此外,這種方法比其他的方法更難發(fā)現(xiàn)安全漏洞??赡苁且?yàn)樵谙嗤穆窂较螺斎氩煌臄?shù)值,但是只有小部分可以引起問題。如果在測試中其他的一種方法實(shí)施了特定的組件和實(shí)現(xiàn)了潛在的缺失驗(yàn)證碼的代碼,它也只能有作用。我從來沒有在其他的文獻(xiàn)中見過這個(gè)特定的方法;人們通常討論一個(gè)執(zhí)行分支的覆蓋。不過,會注意到這種方法不僅可以提高能力,也能發(fā)現(xiàn)特殊的漏洞。
實(shí)現(xiàn)100%的分支覆蓋率比徹底的negative測試更加復(fù)雜,這是因?yàn)槿绻阌袀€(gè)很差的測試套件,它會花費(fèi)大量的時(shí)間來從一個(gè)錯(cuò)誤的分支轉(zhuǎn)向,來弄清楚怎么激發(fā)它。錯(cuò)過的分支往往是很難觸發(fā)的在特定錯(cuò)誤的處理系統(tǒng)中,或是對無法驗(yàn)證“不會發(fā)生”的分支作防御性設(shè)計(jì)。此外,這個(gè)套件變得更強(qiáng)大能夠?qū)崿F(xiàn)100%的覆蓋;很多的組織不能嘗試增加一個(gè)單一的方法來使分支覆蓋到100%,不關(guān)心100%的分支覆蓋。
這就存在一個(gè)問題:這不能很好的反擊心臟出血漏洞,因?yàn)樵诤艽蟪潭壬先Q于所有的配置擴(kuò)展或是注解以及怎么使用。在另一方面,它們不取決于完全沖擊的正確輸入;靜態(tài)分析工具可以同時(shí)檢測大量的問題。
3.7 攻擊運(yùn)行認(rèn)定
軟件開發(fā)人員積極的插入和開啟運(yùn)行認(rèn)定。有人猜測這是對心臟出血的反擊,所以我將在這里研究下這中可能性。
軟件開發(fā)人員可以斷言各種價(jià)值關(guān)系和狀態(tài)必須是正確的。這些斷言可以在運(yùn)行時(shí)停留。幾乎所有的語言都會有一種內(nèi)置的判斷機(jī)制,有些語言會有一些內(nèi)置的先進(jìn)機(jī)制的前置條件,后置條件和不變量。在某些情況下,這些語言可以優(yōu)化一些判句,會留下一些在優(yōu)化過程中不能優(yōu)化的問題,一個(gè)注解系統(tǒng)可以用靜態(tài)來實(shí)現(xiàn),一部分可以用動(dòng)態(tài)實(shí)現(xiàn);我先前對注釋系統(tǒng)的靜態(tài)應(yīng)用的評論。
暫時(shí)增強(qiáng)系統(tǒng)邏輯斷言是一個(gè)更為先進(jìn)的使用暫時(shí)斷句的研究方法。你可以在http://www.cl.cam. ac.uk/research/security/ctsrd/tesla/.網(wǎng)站上發(fā)現(xiàn)更多的信息。
不用懷疑斷句可以有一個(gè)極好的機(jī)制來用于檢測無效狀態(tài),無效狀態(tài)有時(shí)是一個(gè)最弱的指標(biāo)。
然而,這中方法在涉及到對抗心臟出血漏洞時(shí)確實(shí)有些不足。不論是原開發(fā)商或是檢查的人意識到檢查請求報(bào)文的長度值是很重要的;因?yàn)闆]有使用長度檢查,開發(fā)者是不能添加判據(jù)來檢查它。這是一個(gè)在進(jìn)行negative測試時(shí)的問題,但是negative測試可以通過分割這些要開放的功能的代碼來簡單的實(shí)現(xiàn),很容易證明所有的數(shù)據(jù)字段都在進(jìn)行檢查,所以我感覺negative測試會更有可能發(fā)現(xiàn)存在漏洞的類型。因此,雖然積極的注釋可以很有效的對抗漏洞,在某種程度上它會在特定的情況下工作。
我把這種方法看作是一個(gè)較為復(fù)雜的選擇。使用這種方法可以檢測到心臟出血漏洞,需要積極使用判據(jù)。增加這些判據(jù)要使用大量的開發(fā)時(shí)間和提高運(yùn)行的成本。
3.8 更安全的語言
心臟出血漏洞產(chǎn)生的原因是C語言不包含有任何的內(nèi)部檢測或是方法來對抗緩沖區(qū)不當(dāng)?shù)南拗?。不恰?dāng)?shù)南拗茣?dǎo)致災(zāi)難性的問題,所以幾乎所有其他的編程語言都會自動(dòng)對抗不正當(dāng)?shù)南拗啤?/P>
如果在一個(gè)給定的程序中的漏洞可以造成災(zāi)難性的影響,那么選擇它的程序語言時(shí)更應(yīng)該減少漏洞存在的可能性。越是災(zāi)難性的影響,就越要有更好的表現(xiàn)。大多數(shù)的程序語言提供對其他危險(xiǎn)漏洞的保護(hù)措施,如不恰當(dāng)?shù)南拗票Wo(hù)。某些程序語言有更小的可能性出現(xiàn)被誤用和不正確使用的結(jié)構(gòu)。理想情況下,一種語言將會阻止所有漏洞。通用的語言都不能阻止所有的漏洞,但是它是編程者爭取的一個(gè)目標(biāo)。沒有“絕對安全”的程序語言;它是一個(gè)繼續(xù)發(fā)展的事物,一些語言提供了更多的對策。
3.8.1 危險(xiǎn)語言和為什么使用他們
最廣泛使用的與安全有關(guān)的軟件有C,C + +和Objective-C。所有的這些語言都沒有提供緩沖區(qū)的訪問限制,實(shí)際上,它要通過努力來限制緩沖區(qū)讀和寫溢出的出現(xiàn)。對緩沖區(qū)訪問的不恰當(dāng)?shù)南拗茣粡V泛使用類型的災(zāi)難性的影響漏洞。使用或是轉(zhuǎn)變成其他的語言將會消除緩沖區(qū)的漏洞,包括心臟出血漏洞。C語言更是這樣,因?yàn)樗狈芏嗫梢员苊饩彌_區(qū)出現(xiàn)問題的高級結(jié)構(gòu)。大多數(shù)語言也可以防止內(nèi)存釋放錯(cuò)誤,可能會導(dǎo)致安全漏洞,以及一些語言也會被設(shè)計(jì)成對抗其他漏洞。其中在現(xiàn)在系統(tǒng)中有很多漏洞的原因之一是C、C++、和Objective-C語言的過度使用。實(shí)際上,有人提出禁止在安全性敏感的代碼中使用這些語言。
C、C++、和Objective-C語言的廣泛使用是有原因的。在TIOBE編程區(qū)域指數(shù)來衡量的編程語言的流行,2014年4月占到了使用人數(shù)的前四。這些原因包括更高的性能和界面簡單,大型的存儲,更好的表現(xiàn),熟悉性。此外,把語言轉(zhuǎn)變成大型程序是需要很大的努力。讓我們來看看原因。
3.8.2 替代產(chǎn)品的運(yùn)行速度和內(nèi)存性能
一個(gè)經(jīng)常被引用的問題是使用C,C++,和Objective-C比其他的程序的運(yùn)行速度快。此外,當(dāng)要和硬件連接時(shí),其他語言就會缺乏最底層的機(jī)制。如果你要很快的速度,你可以直接連接,語言列表中的運(yùn)行時(shí)間會更短。運(yùn)行速度直接決定著移動(dòng)設(shè)備和服務(wù)器領(lǐng)域?;鶞?zhǔn)游戲中速度分析程序是使用不同的語言編寫的?!俺绦蛘Z言編程的大致等級”中說到,發(fā)送數(shù)據(jù)和不同語言的包是根據(jù)他們的大致速度來實(shí)現(xiàn)。沒有完美的基準(zhǔn),它始終是一個(gè)最好的衡量績效的具體方法。不過,我更喜歡數(shù)字的大致猜測,這個(gè)數(shù)據(jù)即足夠代表開始。如果性能是你要追求的,你不想使用匯編語言,可以考慮下下面的分析:
Fortran。Fortran的應(yīng)用表現(xiàn)經(jīng)常要比其他的語言好,尤其是在數(shù)值計(jì)算上。但是,我不清楚很多人會把很多的代碼轉(zhuǎn)變成更原始的編程語言。特別是據(jù)我所知,即使是現(xiàn)代Fortran也沒有和低級的硬件的接口的標(biāo)準(zhǔn)機(jī)制。
Ada。Ada用于真實(shí)時(shí)間系統(tǒng)的應(yīng)用,因此,它會有更好的性能,包括訪問底層的組件。Ada可以用于對抗錯(cuò)誤,在編譯時(shí)表現(xiàn)的最好,它的語法是專門用于對付錯(cuò)誤的,Ada一定能對抗緩沖區(qū)的心臟出血漏洞。很多人都不喜歡像Ada一樣的語言,因?yàn)锳da要很嚴(yán)格的靜態(tài)類型檢查,但是這中檢查是發(fā)現(xiàn)缺陷的關(guān)鍵機(jī)制之一。Ada一般廣泛的應(yīng)用在像航空鐵路等這些高保障的地方。
ATS。這不是一種眾所周知的廣泛使用的編程語言,但是它確實(shí)非常成功的應(yīng)用在特定的基準(zhǔn)測試套件上。我要指出ATS不在最近使用的程序列表上。
還有很多其他的編程語言,特別當(dāng)你愿意放棄由基準(zhǔn)確定的速度時(shí)。例如Go的性能就很好。Rust是另一種你可以考慮的程序語言。Java在當(dāng)前的JITs上有很合理的表現(xiàn),一旦它運(yùn)行起來,但是這有個(gè)一個(gè)特別的啟動(dòng)時(shí)間。其他的語言在基準(zhǔn)下也很有用,如Scala,F(xiàn)ree Pascal,Lisp SBCL,Haskell, C# on Mono, F# on Mono, and OCaml。不論是D編程語言還是Nimrod語言都列出了相應(yīng)的標(biāo)桿。但是使用他們時(shí)也要考慮到效率問題。
當(dāng)然,如果速度不是關(guān)鍵,很多的軟件都能被使用。一個(gè)研究表明,用.NET, Java, ASP, PHP, Cold Fusion和Perl來編寫的程序中的靜態(tài)漏洞沒有統(tǒng)計(jì)學(xué)上差異。所有這語言要比C,C++或是Objective-C安全。因此所有人都可以防止緩存溢出的問題。
這有太多的編程語言可以使用,我就在這多說了點(diǎn)。我的目的不是列出說所有可以替代的編程語言,而是讓人們知道是有替代的存在。
性能不單單是速度,還有內(nèi)存的管理。在移動(dòng)設(shè)備上尤為重要。C, C++和Objective-C沒有自動(dòng)垃圾收集器,但是其他的語言有這個(gè)功能。開發(fā)人員如果不考慮內(nèi)存管理時(shí),他們考慮的是效率,但是在很多的環(huán)境下是不現(xiàn)實(shí)的。Drew Crawford對移動(dòng)設(shè)備的發(fā)展做了很長時(shí)間的研究,他指出“如果你需要至少6倍的內(nèi)存,自動(dòng)垃圾收集工作會很管用,但是如果這里少于4倍的內(nèi)存,會減少效率?!眎OS基于人工操作的大多數(shù)事情的文化,并且試圖讓編譯器做一些簡單的東西。Android基于他們努力不在實(shí)踐中應(yīng)用垃圾收集器工作,但是不論哪種方式,當(dāng)他們編寫移動(dòng)應(yīng)用程序時(shí),每個(gè)人都花了很多時(shí)間考慮內(nèi)存管理。內(nèi)存是不可以替代的。OS X Mountain Lion v10.8中廢棄了自動(dòng)垃圾收集器,在以后的版本中會把它刪除。都推薦使用自動(dòng)引用算法。不是像OS X和iOS一樣。這就是人們選擇C, C++,和Objective-C的原因。
C, C++, 和 Objective-C編寫的程序比其他的語言的運(yùn)行性能好嗎?回答就是語言就被設(shè)計(jì)成這樣。特別是C語言編寫的程序能夠快速的運(yùn)行并且使用很少的內(nèi)存;C語言中指出C的關(guān)鍵是“相信程序員”,“許多操作被定義為如何在目標(biāo)機(jī)器的硬件上使用它”。另外,C的模型是透明的,所以C或是C++開發(fā)人員可以使用它,通常評估一個(gè)結(jié)構(gòu)。當(dāng)然,現(xiàn)實(shí)會有很大的差距;大量優(yōu)化的編譯器和運(yùn)行時(shí)間要比一般的情況下有更好的性能。
很多的開發(fā)者選擇C, C++,或是Objective-C來簡化其他組件的接口。許多工具都有C的接口,大多數(shù)語言的基礎(chǔ)設(shè)施都可以通過C語言的庫。然而,許多其他的編程語言都有C的接口,兩種方法為C路徑和其他系統(tǒng)通過接口來調(diào)用。因此,這并不重要,重要的理由是選擇哪種語言。
當(dāng)使用C, C++,和Objective-C的開發(fā)人員使用這些語言時(shí)可以減少使用庫的危險(xiǎn)。最新的C標(biāo)準(zhǔn)還增加了一些安全功能,尤其是那些對字符段的處理。C標(biāo)準(zhǔn)仍然錯(cuò)誤的提供易于使用動(dòng)態(tài)調(diào)整大小函數(shù)的asprintf()或是類似的函數(shù)。但是很多現(xiàn)在的系統(tǒng)使用asprintf()。C語言也可以使用GString類型的glib庫,strlcpy/strlcat提供,或是其他解決問題中的一個(gè)。C++程序可以使用std::string或是它的類似內(nèi)容。類似,Objective-C具有NSString和NSMutableString類。但是這些設(shè)施只能在一定程度上降低風(fēng)險(xiǎn);即使使用了這些設(shè)備犯了錯(cuò)誤。
你可以用什么語言來寫不安全軟件。例如,SQL注入的漏洞是另一個(gè)普通弱點(diǎn),而這可能使用每種語言。然而,大多數(shù)語言提供的易于使用,和避免發(fā)生問題的機(jī)制。我要很小心的使用這個(gè)機(jī)制…但是對C, Java,和其他語言來說的。
有些語言通常是通過計(jì)數(shù)器緩沖區(qū)溢出,讓你暫時(shí)停止保護(hù)逃逸機(jī)制。這些逃逸機(jī)制很容易發(fā)現(xiàn)和與精心寫的代碼隔離開來。他們把不安全的隔離成很小的部分,從而降低風(fēng)險(xiǎn)。在很多情況下,你可以重新實(shí)現(xiàn)內(nèi)存緩沖區(qū)高速緩存;你可以啟動(dòng)一些漏洞即使緩沖區(qū)存在保護(hù)時(shí)。但是這種重新實(shí)現(xiàn)是明顯的,在很多的語言中,人們必須要努力避免緩沖區(qū)溢出問題。與其相反的是,在C, C++, 和 Objective-C里,你必須做一些附加的工作來避免這種問題。
創(chuàng)建安全軟件時(shí),也會遇到一些附加的挑戰(zhàn)。我知道沒有辦法安全的擦除Java里的數(shù)據(jù)。這是因?yàn)镴ava里沒有.NET的SecureString的功能;由于內(nèi)存分配和垃圾收集器怎么實(shí)現(xiàn)多次拷貝,Java的結(jié)構(gòu)是在結(jié)束在內(nèi)存中。這不是Java的特點(diǎn),很難安全擦除數(shù)據(jù)在多種語言中。但是Java中,它可以比較容易通過建立一個(gè)小的非Java模塊來擦除一些數(shù)值;該程序的其余部分仍然受到保護(hù)不會出現(xiàn)緩沖溢出。此外,利用額外的內(nèi)存拷貝需要訪問大量的程序和運(yùn)行環(huán)境。安全擦除往往是一個(gè)有用的減少損傷的措施。相比之下,緩沖區(qū)溢出有時(shí)候可以直接減少可以利用的連接,有時(shí)只要通過網(wǎng)絡(luò)連接。一般情況下,緩沖區(qū)溢出要比大多數(shù)其他語言帶來的問題更危險(xiǎn)。
這很難使用C, C++, 和 Objective-C來編寫安全軟件。大多數(shù)的語言都可以內(nèi)嵌和防止緩沖區(qū)溢出保護(hù)…但是C, C++, 和Objective-C例外。另一方面,他們使用這種原因。
開始運(yùn)行每一個(gè)新的安全相關(guān)程序,就要仔細(xì)的考慮下程序語言。選擇一個(gè)更安全的語言是很有必要的,這樣就可以去除潛在的安全漏洞,其中包括緩沖區(qū)溢出的心臟出血漏洞。另外,計(jì)算機(jī)變得更加強(qiáng)大,在很多情況下可以進(jìn)行交易一些性能。更重要的是,在開始編寫新的程序時(shí),使用另外一種編程語言就幾乎變成了零成本。我相信用不太安全的語言時(shí),和重寫代碼需要花費(fèi)很多努力。但是,使用幾乎任何不是C, C++,或是Objective-C,至少會消除緩沖區(qū)溢出和緩沖區(qū)溢出漏洞會有很大的影響。
我已經(jīng)確定了更安全的語言作為一個(gè)更復(fù)雜的方法,因?yàn)榍袚Q一個(gè)不常用的程序,用不同的語言來實(shí)現(xiàn)安全是要花費(fèi)很多的時(shí)間的。
3.8 完全靜態(tài)分析器
一個(gè)完全的靜態(tài)分析器可以被稱為聲音靜態(tài)分析器,用來發(fā)現(xiàn)某個(gè)特定的漏洞。創(chuàng)建這些類型的工具就是在調(diào)整C語言。然而,程序有時(shí)不得不限制他們使用的架構(gòu),并且開發(fā)人員必須提供附加的注解資料。因?yàn)檫@些工具集中發(fā)現(xiàn)一切問題,他們往往會報(bào)告不存在漏洞,這就必須要分析決定是否真的存在漏洞。但是,如果它應(yīng)對所有的漏洞,權(quán)衡是很有必要的。
3.9 完全認(rèn)為的核對
一個(gè)完全徹底不獨(dú)立的人為軟件檢查,主要集中在確保安全性和發(fā)現(xiàn)漏洞,這是發(fā)現(xiàn)漏洞的最佳方式。這些評論又被稱為審核,在展示時(shí),這個(gè)軟件是很脆弱的。
它的觀念是通過人為審核要比通過工具的啟發(fā)式技術(shù)來查找漏洞更直觀。更重要是實(shí)驗(yàn)數(shù)據(jù)證實(shí)了這一點(diǎn)。例如,Kupsch和Miller發(fā)現(xiàn)使用第一原理弱點(diǎn)評估方式的人為審計(jì)分析一個(gè)示例程序比使用Coverity Prevent和Fortify Source Code Analyzer更全面。人為審核也會出現(xiàn)意外,但是這樣的評估會做的相當(dāng)不錯(cuò)。在Kupsch實(shí)驗(yàn)室,F(xiàn)PVA人為檢查發(fā)現(xiàn)了15個(gè)嚴(yán)重的安全漏洞;Fortify發(fā)現(xiàn)了6個(gè),Coverity發(fā)現(xiàn)了1個(gè),既不是自動(dòng)化工具發(fā)現(xiàn)也不是由人的審查發(fā)現(xiàn)。
但是人工核查的缺點(diǎn)也是顯而易見的:這需要努力和專業(yè)知識來做這樣的審核,改變也要審核。人為審查不適合用于所有的軟件,甚至當(dāng)它在面臨很復(fù)雜的情況時(shí)。
請注意,這種審核和以前的可以接受的典型的、簡單的回顧是不同的。心臟出血漏洞是試圖避免漏洞開發(fā)人員發(fā)現(xiàn)的,被另一個(gè)審核接受。然而,補(bǔ)丁的審核通常是是功能的改善和尋找安全漏洞的過程,所以很容易讓他們錯(cuò)過漏洞。正如前面提到的,人為審查每個(gè)補(bǔ)丁來要求每個(gè)領(lǐng)域的有效認(rèn)證,要抓住這點(diǎn)…但是現(xiàn)在代碼的存在,只是審核新的補(bǔ)丁是不夠的。試圖在這一點(diǎn)上單獨(dú)審查每一份文件的補(bǔ)丁可能是不符合成本效應(yīng)的。此外,補(bǔ)丁的審核可能錯(cuò)過重要問題。一個(gè)單獨(dú)的審核關(guān)注整個(gè)系統(tǒng)的漏洞是很有效的。
這種審核確實(shí)可以發(fā)現(xiàn)。事實(shí)上,在心臟出血漏洞被發(fā)現(xiàn)的同時(shí),TrueCrypt的一個(gè)重要組成部分的安全審查發(fā)布了。
在很多情況下軟件應(yīng)該進(jìn)行修改和簡化,在審查之前。我認(rèn)為對于OpenSSL是尤其重要的。那些復(fù)雜的程序都很難為工具和人為的評估。OpenSSL使用的復(fù)雜結(jié)構(gòu),這就讓它很難被人和機(jī)器發(fā)現(xiàn)。
3.10格式化方法
但是如果你真的想在某種程度上肯定什么是這個(gè)程序要做的?存在著一系列的方法叫做“格式化方法”,這要比上面列出的技術(shù)方法更有信心。格式化的方法包括使用“嚴(yán)格的數(shù)學(xué)技術(shù)和工具來規(guī)范、設(shè)計(jì)和驗(yàn)證軟件和硬件系統(tǒng)。”由于使用格式化方法是有困難的,他們更可能是在目前的小程序和模塊上,是絕對可以使用格式化方法的。此外,如果你真的想要擁有很高的信任程序,格式化的方法仍然是實(shí)現(xiàn)這一信心的唯一途徑。
這有很多方面可以使用格式化方法。有些人只用格式化的方法來創(chuàng)建規(guī)范,不會使用格式化的方法來多做什么。有些人可能會想的多一點(diǎn),證明有關(guān)規(guī)范的一些聲明或是改進(jìn)的規(guī)范走向更具體的模型。這些方法都不會發(fā)現(xiàn)心臟出血漏洞。對于心臟出血漏洞來說,格式化方法要?jiǎng)?chuàng)造關(guān)于代碼的證明,在源代碼和可執(zhí)行代碼水平上,這就是我最關(guān)心的。
在關(guān)于有關(guān)代碼注釋的系統(tǒng)的實(shí)踐證明,值得一提的是,注解系統(tǒng)通??梢栽诟鞣N不同的方式來使用簡化的證明。為了了解更多的信息,請參見我有關(guān)注釋系統(tǒng)的評論。
如果你對更多的感興趣,特別是支持格式化的FLOSS工具,請參閱從我的類的格式化方法來開發(fā)安全的軟件。一個(gè)有趣的格式化方法工具套件是Toccata,它結(jié)合了Frama-C和Why3,以及許多自動(dòng)化和互助工具。通過組合這些不同的工具來證明程序的正確,在比以前使用更少的努力。更重要的是,他們可以處理C的大量子集;而最正規(guī)的方法是不能做到的。SPARK 2014就是基于Ada的,但是可以讓你證明相關(guān)程序的聲明,以及他們最近和Toccata聯(lián)系在了一起。
正式驗(yàn)證程序的實(shí)例中有seL4,CompCert C,cakeML,Tokeneer和iFACTS。