安全專家Michael Howard和Keith Brown提出了十條技巧來幫助您解脫困境。
安全問題涉及許多方面。安全風險可能來自任何地方。您可能編寫了無效的錯誤處理代碼,或者在賦予權限時過於慷慨。您可能忘記了在您的服務器上正在運行什麼服務。您可能接受了所有用戶輸入。如此等等。為使您在保護自己的計算機、網絡和代碼方面有個良好開端,這裡展示了十條技巧,遵循這些技巧可以獲得一個更安全的網絡策略。
1. 信任用戶的輸入會將自己置於險境
即使不閱讀余下的內容,也要記住一點,“不要信任用戶輸入”。如果您總是假設數據是有效的並且沒有惡意,那麼問題就來了。大多數安全薄弱環節都與攻擊者向服務器提供惡意編寫的數據有關。
信任輸入的正確性可能會導致緩沖區溢出、跨站點腳本攻擊、SQL 插入代碼攻擊等等。
讓我們詳細討論一下這些潛在攻擊方式。
2. 防止緩沖區溢出
當攻擊者提供的數據長度大於應用程序的預期時,便會發生緩沖區溢出,此時數據會溢出到內部存儲器空間。緩沖區溢出主要是一個 C/C++ 問題。它們是種威脅,但通常很容易修補。我們只看到過兩個不明顯且難以修復的緩沖區溢出。開發人員沒有預料到外部提供的數據會比內部緩沖區大。溢出導致了內存中其他數據結構的破壞,這種破壞通常會被攻擊者利用,以運行惡意代碼。數組索引錯誤也會造成緩沖區下溢和超限,但這種情況
沒那麼普遍。
請看以下 C++ 代碼片段:
void DoSomething(char *cBuffSrc, DWORD cbBuffSrc)
{
char cBuffDest[32];
memcpy(cBuffDest,cBuffSrc,cbBuffSrc);
}
問題在哪裡?事實上,如果 cBuffSrc 和 cbBuffSrc 來自可信賴的源(例如不信任數據並因此而驗證數據的有效性和大小的代碼),則這段代碼沒有任何問題。然而,如果數據來自不可信賴的源,也未得到驗證,那麼攻擊者(不可信賴源)很容易就可以使cBuffSrc 比 cBuffDest 大,同時也將 cbBuffSrc 設定為比 cBuffDest 大。當 memcpy將數據復制到 cBuffDest 中時,來自 DoSomething 的返回地址就會被更改,因為cBuffDest 在函數的堆棧框架上與返回地址相鄰,此時攻擊者即可通過代碼執行一些惡意操作。
彌補的方法就是不要信任用戶的輸入,並且不信任 cBuffSrc 和 cbBuffSrc 中攜帶的任何數據:
void DoSomething(char *cBuffSrc, DWORD cbBuffSrc)
{
const DWORD cbBuffDest = 32;
char cBuffDest[cbBuffDest];
#ifdef _DEBUG
memset(cBuffDest, 0x33, cbBuffSrc);
#endif
memcpy(cBuffDest, cBuffSrc, min(cbBuffDest, cbBuffSrc));
}
此函數展示了一個能夠減少緩沖區溢出的正確編寫的函數的三個特性。首先,它要求調用者提供緩沖區的長度。當然,您不能盲目相信這個值!接下來,在一個調試版本中,代碼將探測緩沖區是否真的足夠大,以便能夠存放源緩沖區。如果不能,則可能觸發一個訪問沖突並把代碼載入調試器。在調試時,您會驚奇地發現竟有如此多的錯誤。最後也是最重要的是,對 memcpy 的調用是防御性的,它不會復制多於目標緩沖區存放能力的數據。
在 Windows Security Push at Microsoft(Microsoft Windows? 安全推動活動)中,我們為 C 程序員創建了一個安全字符串處理函數列表。您可以在 Strsafe.h: SaferString Handling in C(英文)中找到它們。