[英]Is the function strcpy always dangerous?
strcpy、gets 等函數總是危險的嗎? 如果我寫這樣的代碼怎么辦:
int main(void)
{
char *str1 = "abcdefghijklmnop";
char *str2 = malloc(100);
strcpy(str2, str1);
}
這樣函數不接受參數(參數...)並且 str 變量將始終具有相同的長度...這里是 16 或略多,具體取決於編譯器版本...但是 100 就足夠了2011 年 3 月 :)。 有沒有辦法讓黑客利用上面的代碼? 10 倍!
絕對不。 與 Microsoft 為其非標准功能進行的營銷活動相反, strcpy
在正確使用時是安全的。
以上是多余的,但大多是安全的。 唯一的潛在問題是您沒有檢查malloc
返回值,因此您可能正在取消引用 null(如 kotlinski 所指出的)。 在實踐中,這可能會導致立即 SIGSEGV 和程序終止。
不當和危險的使用是:
char array[100];
// ... Read line into uncheckedInput
// Extract substring without checking length
strcpy(array, uncheckedInput + 10);
這是不安全的,因為 strcpy 可能會溢出,導致未定義的行為。 在實踐中,這很可能會覆蓋其他局部變量(這本身就是一個重大的安全漏洞)。 其中之一可能是退貨地址。 通過返回lib C攻擊,攻擊者可以使用system
等C函數來執行任意程序。 溢出還有其他可能的后果。
但是, gets
本質上確實是不安全的,並且將從 C (C1X) 的下一個版本中刪除。 根本無法確保輸入不會溢出(導致與上述相同的后果)。 有些人會爭辯說,與已知的輸入文件一起使用時它是安全的,但實際上沒有理由使用它。 POSIX 的getline
是一個更好的選擇。
此外, str1
的長度不會因編譯器而異。 它應該總是 17,包括終止 NUL。
你強行將完全不同的東西歸為一類。
函數gets
確實總是危險的。 有沒有辦法讓一個安全的呼吁gets
不論什么步驟,你願意花,你是如何防守願意得到。
如果您願意采取 [簡單] 必要步驟來確保對strcpy
strcpy
是安全的,那么函數strcpy
是完全安全的。
這已經將gets
和strcpy
置於截然不同的類別中,它們在安全性方面沒有任何共同之處。
針對strcpy
安全方面的流行批評完全基於軼事社會觀察,而不是正式事實,例如“程序員是懶惰和無能的,所以不要讓他們使用strcpy
”。 在 C 編程的上下文中,這當然是無稽之談。 按照這個邏輯,出於完全相同的原因,我們還應該聲明除法運算符完全不安全。
實際上, strcpy
沒有任何問題。 另一方面, gets
是一個完全不同的故事,正如我上面所說的。
是的,這很危險。 經過 5 年的維護,您的代碼將如下所示:
int main(void)
{
char *str1 = "abcdefghijklmnop";
{enough lines have been inserted here so as to not have str1 and str2 nice and close to each other on the screen}
char *str2 = malloc(100);
strcpy(str2, str1);
}
在這一點上,有人會去改變 str1 到
str1 = "這是一個非常長的字符串,現在將超出任何用於將其復制到的緩沖區,除非采取預防措施來檢查字符串的限制。很少有人記得在使用 BLEMGFIX 時會這樣做越野車計划”
忘記查看 str1 的使用位置,然后隨機錯誤將開始發生......
您的代碼不安全。 malloc
的返回值是未經檢查的,如果它失敗並返回 0,則strcpy
將給出未定義的行為。
除此之外,除了示例基本上沒有做任何事情之外,我認為沒有其他問題。
strcpy
並不危險,因為您知道目標緩沖區足夠大以容納源字符串的字符; 否則strcpy
會很高興地復制比目標緩沖區可以容納的更多的字符,這可能會導致一些不幸的后果(堆棧/其他變量覆蓋,這可能導致崩潰、堆棧粉碎攻擊等)。
但是:如果您在輸入中有一個尚未檢查過的通用char *
,唯一確定的方法是將strlen
應用於此類字符串並檢查它是否對您的緩沖區太大; 但是,現在您必須遍歷整個源字符串兩次,一次檢查其長度,一次執行復制。
這是次優的,因為如果strcpy
更先進一點,它可以接收緩沖區大小作為參數並在源字符串太長時停止復制; 在完美的世界中,這就是strncpy
執行方式(遵循其他strn***
函數的模式)。 然而,這並不是一個完美的世界,而且strncpy
並不是為了做到這一點而設計的。 相反,非標准(但流行)的替代方法是strlcpy
,它不會超出目標緩沖區的邊界,而是截斷。
一些 CRT 實現不提供此功能(特別是 glibc),但您仍然可以獲得 BSD 實現之一並將其放入您的應用程序中。 標准(但較慢)的替代方法是使用snprintf
和"%s"
作為格式字符串。
也就是說,既然你用 C++ 編程(編輯我現在看到 C++ 標簽已被刪除),你為什么不避免所有的 C 字符串廢話(如果你可以,顯然)並使用std::string
? 所有這些潛在的安全問題都消失了,字符串操作變得更加容易。
malloc 可能失敗的唯一方式是發生內存不足錯誤,這本身就是一場災難。 您無法可靠地從中恢復,因為幾乎任何事情都可能再次觸發它,而且操作系統很可能會終止您的進程。
正如您所指出的,在受限情況下 strcpy 並不危險。 更典型的做法是接收字符串參數並將其復制到本地緩沖區,這時事情會變得危險並導致緩沖區溢出。 請記住在調用 strcpy 之前檢查您的副本長度,然后 null 終止字符串。
除了可能取消引用 NULL(因為您沒有檢查 malloc 的結果)這是 UB 並且可能不是安全威脅之外,這沒有潛在的安全問題。
gets()
總是不安全的; 其他功能可以安全使用。
即使您完全控制輸入, gets()
也是不安全的——總有一天,程序可能會被其他人運行。
使用gets()
的唯一安全方法是將其用於單次運行:創建源; 編譯; 跑; 刪除二進制文件和源代碼; 解釋結果。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.