簡體   English   中英

函數 strcpy 總是危險的嗎?

[英]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是完全安全的。

這已經將getsstrcpy置於截然不同的類別中,它們在安全性方面沒有任何共同之處。

針對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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM