軟件測試 | 什么是安全測試
測試應(yīng)用的功能通常是很簡單的 —— 我們遵循普通用戶所采取的方法來使用它。如果我們不確定預(yù)期行為是什么,通常也會有某種方法能知道 —— 詢問別人,閱讀需求,使用我們的直覺。負(fù)面測試遵循一些從正面測試中自然而然直接地獲取的原則。我們知道銀行的“存款”不應(yīng)該是負(fù)值;密碼不應(yīng)該是1MB的JPEG圖片;電話號碼中不應(yīng)該包含字母。隨著我們對應(yīng)用進(jìn)行測試并建立起正面的功能測試,建立反面測試就自然而然地成為下一步。那么這與安全測試有什么關(guān)系?
安全測試就是要提供證明表明,在面對敵意和惡意輸入的時候,應(yīng)用仍然能夠充分地滿足它的需求。
提供證據(jù)
在安全測試中,我們考慮無法接受的輸入的全體集合 —— 無限集 —— 并重點關(guān)注那些很可能在我們軟件的安全需求方面造成嚴(yán)重失效的輸入子集 —— 仍然是無限集。我們需要確定這些安全需求是什么,并決定什么類型的測試能夠證明這些需求得到滿足。這并不簡單,但是通過邏輯和勤奮,我們能夠想產(chǎn)品所有者提供有用的證據(jù)。
我們證明安全滿足需求的方式將與證明功能滿足要求的方法相同。我們建立輸入,確定預(yù)期結(jié)果,然后建立并運行測試來鍛煉系統(tǒng)。以我們與不熟悉安全測試的測試人員交往的經(jīng)歷來看,第一步和最后一步是最難的。設(shè)計反安全的輸入和對軟件進(jìn)行測試是最難做的事情。大多數(shù)時間,預(yù)期的結(jié)果相當(dāng)簡單。如果我詢問產(chǎn)品經(jīng)歷:“有人能夠在不登錄的情況下下載敏感數(shù)據(jù)嗎?”。通常他很容易就會說不。因此,提供證據(jù)過程中較難的部分是創(chuàng)造出可能會造成這種狀況的輸入,然后確定這種情況是否會發(fā)生。
滿足需求
有關(guān)軟件工程學(xué)的ANSI/IEEE標(biāo)準(zhǔn)729將“需求”定義為用戶為了解決問題或達(dá)成目標(biāo)所需要的條件或功能,或為了滿足合同、標(biāo)準(zhǔn)、規(guī)范或其他正式起效的文檔,系統(tǒng)所必須擁有或滿足的條件或功能。在得知需求的情況喜愛,所有測試人員都進(jìn)行測試直到滿足需求。即使需求并不是以充斥著“該軟件應(yīng)當(dāng)”語句的形式出現(xiàn),軟件測試人員也往往能夠就正確的響應(yīng)達(dá)成共識,然后以預(yù)期結(jié)果的形式將其整理到測試之中。
安全測試與功能測試相似,因為它同樣也依賴于對“我們想要怎樣的行為”的理解。當(dāng)然也可以說,于功能測試相比,安全測試更加依賴于需求,因為它有更多可能的輸入和輸出可供篩選。在需求編寫者的腦海里,安全行為的定義往往更加模糊,因為大多數(shù)軟件都不是安全軟件。該軟件有一些其他方面的主要用途,而安全是一種必須存在的非功能性需求。因為對安全的關(guān)注不夠,所以這方面的需求常常缺失或不完整。
充分地滿足需求,這種想法如何?因為安全是一個不斷發(fā)展的過程,而且因為安全通常不是我們的主要功能,所以我們并不總是因為更安全就去做某件事。真正的軟件安全實際上指的是風(fēng)險管理。我們確保軟件的安全程度滿足我們的業(yè)務(wù)需求。有時,安全純粹主義者會認(rèn)為軟件不夠安全。只要它能夠滿足業(yè)務(wù)所有者 —— 當(dāng)這些所有者意識到風(fēng)險并充分理解自己所承擔(dān)的風(fēng)險時 —— 那么這個軟件就足夠安全。安全測試提供了必要的證據(jù)和信息,以便業(yè)主就承擔(dān)多少安全風(fēng)險方面做出知情決策。
安全測試是老調(diào)重談
安全是一段旅程,而不是目的地。我們永遠(yuǎn)也無法做到能夠宣城軟件已經(jīng)安全而我們的任務(wù)已完成的地步。在執(zhí)行功能測試時,我們通常使用指定的、可接受的輸入,這些輸入將產(chǎn)生已知的、預(yù)期的結(jié)果。在安全測試中,并不存在同樣的有限性來約束我們的期望。
設(shè)想我們正在測試這樣一種需求:"對于最大不超過MAXINT的正整數(shù),convertInToRoman(int)函數(shù)將返回有效的羅馬數(shù)字字符串“。如果我們只是在進(jìn)行功能測試,我們將提供5作為輸入并確保函數(shù)返回“V”。邊界值測試將檢查最大整數(shù)值,0,-1等取值。我們會檢查“-5”作為輸入時程序給出正確的異常處理,并確保輸出不會是“-V”,而是適當(dāng)定義的錯誤響應(yīng)。最后,異常測試將使用等價類來確保函數(shù)在輸入為3.42時不會返回“III.IVII”作為輸出,并能夠在輸入是“Fork”等奇怪字符串時給出適當(dāng)?shù)腻e誤處理。
但是,安全測試則超出上述內(nèi)容,它需要理解問題域并精心構(gòu)造惡意輸入,例如,羅馬數(shù)字算法中不易處理的一類輸入是由許多9和4組成的數(shù)字(比如,9494949494)。因為它需要遞歸或參考前一個羅馬數(shù)字,這可能在軟件中導(dǎo)致深堆?;騼?nèi)存使用過量。這不僅僅是個邊界條件。如果我們在功能測試基礎(chǔ)上進(jìn)行安全測試,則需要增加大量測試用例。這意味著必須做兩件事來使之便于管理:縮小我們的重點以及自動化。
所有熟悉軟件測試的人都理解邊界值和等價類劃分的概念。不必牽涉到太深的標(biāo)準(zhǔn)測試著作,讓我們重洗回顧一下這兩點,因為我們的許多Web安全測試將遵循同樣的模型。如果你已經(jīng)熟悉這些測試中的過程,你會發(fā)現(xiàn)很容易就能夠利用它們來組織你的安全測試。
邊界值
邊界值獲取給定的輸入并非常仔細(xì)地圍繞著它能夠接受的邊界值進(jìn)行測試。例如,如果輸入允許使用從0到100(包含0和100)的整數(shù)來表示百分百,那么我們可以生成下列邊界值:-1,0,1,3,99,100,101。為了生成邊界案例,我們重點關(guān)注給定范圍中最大和最小的兩個值(0和100)。對每個邊界,我們使用邊界值本身,邊界值減1和邊界值加1.另外,我們選擇一些位于中間的值,這些值的結(jié)果應(yīng)該非常好。這是個基準(zhǔn)案例。
等價類
在試圖找出反面測試值時,我們知道不可接受的輸入的集合是一個無限集。作為一種戰(zhàn)略,我們從中抽樣,而不是試圖去測試大量的輸入。我們將無限的集合拆分成有一些共同之處的組 —— 等價類,然后我們從每個組中選出幾個具有代表性的樣品。
繼續(xù)考慮“邊界值”一節(jié)中的例子,我們需要選出幾種非法輸入類并進(jìn)行試驗。我們可以選擇這樣的類:負(fù)數(shù)、非常大的正數(shù)、字母組成的字符串、小數(shù)以及一些有意義的特殊值,比如MAXINT。通常,我們會從每個類中挑選出少量的數(shù)值(比如兩個)并將其添加到我們的測試輸入集。
安全類
“邊界值”一節(jié)中的7個邊界值,以及從“等價類”一節(jié)中大約9種等價類中每一種挑選兩個值,將反面數(shù)據(jù)測試用例集合從無限多減少到25個。這是個很好的開始?,F(xiàn)在我們開始基于常見攻擊和漏洞添加安全測試用例。這就是如何將安全測試變?yōu)槿粘9δ軠y試中簡單而普通的一部分。我們選擇具有安全意義的特殊邊界值,以及具有安全意義的特殊等價類值,并將這些融入到我們的測試規(guī)劃和計劃策略過程中。
有幾種得到普通認(rèn)可的安全輸入類:SQL注入字符串,跨站式腳本字符串以及其他類的編碼形式。例如,為了繞過某些應(yīng)用的輸入驗證程序,你可以使用Base-64或URL方式將某些攻擊字符串編碼?,F(xiàn)在,不同于邊界值和其他等價類,這些安全類實際上是無限多的。因此,我們再次戰(zhàn)略性地對其抽樣,使其成為易于處理的集合。就編碼而言,我們可以選擇3或4種編碼。這會使我們的測試集合增加到3或4倍,將25個值變?yōu)?5或100個值。有些其他辦法,系統(tǒng)進(jìn)行某種編碼時或者失敗,或者成功。如果在你使用URL方法編碼-1時系統(tǒng)失敗了,那么它很可能也會在你使用URL方法編碼101時失敗。因此,你或許可以選擇使用Base-64來編碼一些值,URL來編碼其他值,HTML來編碼其他值,并對其他一些值進(jìn)行多重編碼。這樣,你能夠覆蓋這些編碼,而且不必將測試用例數(shù)量增加到4倍。或許這個數(shù)量只倍增到50個測試用例。
現(xiàn)在,SQL注入和跨站式腳本的攻擊字符串就交給你了。你必須進(jìn)行一些判斷,并選擇一個能夠在自己所擁有的時間內(nèi)完成的合理的子集。如果你所測試的系統(tǒng)部分易于自動化,那么你可以在每個類中完成許多的測試用例。如果你在進(jìn)行手動測試,那么你或許應(yīng)當(dāng)獲取一個不同攻擊字符串的長列表,并在每次進(jìn)行測試時嘗試不同的字符串。這樣,盡管你沒有在每次測試運行時都測試每一條字符串,但是最終你將完成大量不同的案例。