摘要:涉及安全問題時,有很多情況都會導致出現麻煩。您可能信任所有在您的網絡上運行的代碼,賦予所有用戶訪問重要文件的權限,并且從不費神檢查您機器上的代碼是否已經改變。您也可能沒有安裝防病毒軟件,沒有給您自己的代碼建立安全機制,并賦予太多帳戶以太多的權限。您甚至可能非常大意地使用大量內置函數從而允許惡意侵入,并且可能任憑服務器端口開著而沒有任何監控措施。顯然,我們還可以舉出更多的例子。哪些是真正重要的問題(即,為了避免危及您的數據和系統,應立即予以關注的最危險的錯誤)?安全專家 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 在函數的堆�?蚣苌吓c返回地址相鄰,此時攻擊者即可通過代碼執行一些惡意操作。
彌補的方法就是不要信任用戶的輸入,并且不信任 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: Safer String Handling in C(英文)中找到它們。
3. 防止跨站點腳本
跨站點腳本攻擊是 Web 特有的問題,它能通過單個 Web 頁中的一點隱患危害客戶端的數據。想像一下,下面的 ASP.NET 代碼片段會造成什么后果:
<script language=c#>
Response.Write("您好," + Request.QueryString("name"));
</script>
有多少人曾經見過類似的代碼?但令人驚訝的是它有問題!通常,用戶會使用類似如下的 URL 訪問這段代碼: http://explorationair.com/welcome.aspx?name=Michael
該 C# 代碼認為數據始終是有效的,并且只是包含了一個名稱。但攻擊者會濫用這段代碼,將腳本和 HTML 代碼作為名稱提供。如果輸入如下的 URL http://northwindtraders.com/welcome.aspx?name=<script>alert('您好!'); </script>
您將得到一個網頁,上面顯示一個對話框,顯示“您好!”。您可能會說,“那又怎樣?”想像一下,攻擊者可以誘導用戶點擊這樣的鏈接,但查詢字符串中卻包含一些真正危險的腳本和 HTML,由此會得到用戶的 cookie 并把它發送到攻擊者擁有的網站;現在攻擊者便獲得了您的私人 cookie 信息,或許會更糟。
要避免這種情況,有兩種方法。第一種是不信任輸入,并嚴格限制用戶名所包含的內容。例如,可以使用正則表達式檢查該名稱是否只包含一個普通的字符子集,并且不太大。以下 C# 代碼片段顯示了完成這一步驟的方法:
Regex r = new Regex(@"^[w]{1,40}$");
if (r.Match(strName).Success) {
// 好!字符串沒問題
} else {
// 不好!字符串無效
}
這段代碼使用正則表達式驗證一個字符串僅包含 1 到 40 個字母或數字。這是確定一個值是否正確的唯一安全方法。
HTML 或腳本不可能蒙混過此正則表達式!不要使用正則表達式尋找無效字符并在發現這種無效字符后拒絕請求,因為容易出現漏掉的情況。 第二種防范措施是對所有作為輸出的輸入進行 HTML 編碼。這會減少危險的 HTML 標記,使之變成更安全的轉義符。您可以在 ASP.NET 中使用 HttpServerUtility.HtmlEncode,或者在 ASP 中使用 Server.HTMLEncode 轉義任何可能出現問題的字符串。
最新評論共有 0 位網友發表了評論
查看所有評論
發表評論