在電腦程式中,每種類型的整數(Integer)都有其可以儲存的數值上限與下限。當一個計算的結果超出了這個範圍,就像試圖將兩公升的水裝進一公升的瓶子裡,水滿溢出來了,這就是「整數溢位 (Integer Overflow)」。這種溢位可能導致程式行為異常、崩潰,甚至產生嚴重的安全漏洞。
什麼是整數溢位?
整數溢位是一種算術錯誤,發生在當一個整數變數被賦予一個超出其資料型別所能表示的最大值(上溢, Overflow)或最小值(下溢, Underflow)時。
舉個例子,一個 8 位元的無號整數 (Unsigned 8-bit Integer) 只能儲存 0 到 255 的數字。如果你對一個值為 255 的變數再加 1,它不會變成 256,而是會「繞回 (wrap around)」變成 0。
同樣地,一個 8 位元的有號整數 (Signed 8-bit Integer) 範圍是 -128 到 127。如果你對一個值為 127 的變數再加 1,它會變成 -128。
攻擊原理與範例
攻擊者可以利用這種可預測的「繞回」行為來破壞應用程式的邏輯。
情境:從鉅額負債變成鉅額資產
- 系統背景:一個線上購物平台允許使用者賒帳,其後端系統使用一個 32 位元的有號整數來記錄使用者的負債金額。32 位元有號整數的最小值約為 -21.4 億 (
-2,147,483,648
)。 - 攻擊行為:攻擊者在該平台上瘋狂購物,不斷累積負債。
- 觸發下溢:當他的負債金額達到
-2,147,483,648
時,他再購買一個價值 1 元的商品。理論上負債應為-2,147,483,649
。 - 漏洞觸發:由於這個數字超出了 32 位元有號整數的下限,發生了整數下溢。變數的值從最小值「繞回」到了最大值,變成了
2,147,483,647
。 - 攻擊成功:系統的邏輯被完全破壞。攻擊者的帳戶狀態從「負債 21 億」瞬間變成了「資產 21 億」,他可以用這筆「飛來橫財」繼續購物。
風險與影響
- 繞過安全檢查:例如,在需要檢查購買數量是否大於 0 的地方,透過溢位將一個負數變成一個巨大的正數,從而繞過檢查。
- 服務阻斷 (Denial-of-Service, DoS):非預期的計算結果可能導致程式崩潰或陷入無限迴圈。
- 記憶體損毀與任意程式碼執行:在 C/C++ 等底層語言中,整數溢位可能導致緩衝區溢位 (Buffer Overflow),進而讓攻擊者有機會執行任意程式碼,這是最高風險的情況。
防禦與預防措施
1. 使用能容納計算結果的資料型別
- 在進行算術運算前,預先評估結果可能的最大值與最小值。
- 選擇一個足夠大的資料型別來儲存結果,例如,當處理金錢或大量計數時,使用 64 位元整數 (
long long
或Int64
) 通常比 32 位元整數更安全。
2. 在運算前進行邊界檢查
- 在執行加、減、乘等運算之前,先檢查運算元是否會導致結果超出目標資料型別的範圍。
- 例如,在執行
a + b
之前,可以先檢查b
是否大於MAX_INT - a
。
3. 使用經過安全設計的函式庫
- 某些程式語言或函式庫提供了「安全算術」功能,當偵測到溢位時,它們會自動拋出異常,而不是默默地讓「繞回」發生。應優先使用這些安全的函式庫。
4. 謹慎處理不同型別間的轉換
- 在有號整數與無號整數之間進行轉換時要特別小心,因為這可能改變數值的解釋方式並引發漏洞。
說些什麼吧!