2014-07-22 201 views
0

我正在編寫一個小的C代碼來接收一些用戶輸入,這將是一個字符串。現在我讀了很多地方,使用gets()會非常不安全,因爲它可能導致緩衝區溢出攻擊。而在大多數地方,我發現作爲一種替代方法是使用fgets(),而就緩衝區溢出而言更安全。調整gets()以避免緩衝區溢出

現在我有一個問題場景,我不知道之前的緩衝區大小。它不能確定。它可能是任何東西。所以在這種情況下,fgets()會很方便嗎?

另外,如果我使用gets()來解決這個問題,那麼會出現什麼問題呢?

char * temp_buffer_to_hold_user_input = NULL; 
cahr * actual_buffer_that_stores_user_input = NULL; 
int length_of_user_input =0; 

/* taking user input, irrespective of its length using gets() */ 

gets(temp_buffer_to_hold_user_input); 

/* now finding the length of the user input string and allocating the required number of bytes for proper (safe) usage */ 

length_of_user_input=length(temp_buffer_to_hold_user_input); 
actual_buffer_that_stores_user_input = (char*)malloc(length_of_user_input*sizeof(char)); 
strcpy(actual_buffer_that_stores_user_input, temp_buffer_to_hold_user_input); 

/* and now we work with our actual buffer */ 

那麼gets()的上述用法仍然存在緩衝區溢出問題?因爲在上面我們沒有首先聲明一個固定大小的緩衝區......所以沒有緩衝區溢出是我所期望的。

如果我錯過了某些東西,請糾正我!

+4

確實沒有緩衝區溢出。 'gets()'將字符串存儲在'NULL'處將會受到傷害。 – Quentin

+1

只要說** NO **到'gets()'並且繼續你的生活。僅供參考:自2011年12月以來,'gets()'不再是C語言的一部分(一些C2011編譯器將其作爲擴展提供;其他編譯器可能不兼容C2011)。 – pmg

+0

因爲使用動態數組(char * temp_buffer_to_hold_user_input = NULL;),所以不會發生緩衝區溢出問題。我認爲沒有必要將i/p存儲到另一個陣列。 – Sathish

回答

5
char * temp_buffer_to_hold_user_input = NULL; 

您將指針設置爲NULL。因此有根本沒有緩衝區gets將會失敗,出現未定義的行爲(實際上可能是分段錯誤)。

gets要求您提供一個有效的指針緩衝區。空指針不指向任何東西,因此這個前提條件不被滿足。由於所有緩衝區的長度都是有限的,並且用戶輸入的長度未知,因此根本沒有辦法避免發生潛在的緩衝區溢出(更不用說安全風險)。從官方標準中刪除了gets已被刪除。

正確的方法是使用fgets。具有可變大小的輸入處理是棘手的,所以你有兩個選擇:

  • 使用fgets有「足夠大的我所有的情況下,」緩衝區大小。簡單的出路。最糟糕的情況是你失去了一些輸入。
  • 反覆使用fgets並連接到某些動態分配的數組(並且不要忘記根據需要調整此數組的大小!),直到達到分隔符爲止。 注意:取決於你對字符串所做的事情,你可能甚至不需要把整個事情都放在一起,這簡化了事情。
+0

我同意。在實踐中你可以做的是重複調用「fgets」,使用有限長度temp_buffer_to_hold_user_input,直到你讀取的緩衝區爲空,並且每次增加actual_buffer_that_stores_user_input的大小並追加新數據。 –

2

如果你不知道你在動手之前可以看看到getline(),或建立自己的功能和realloc你的字符串,像緩衝區大小:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int main(void) 
{ 
    char buf[8], *s = NULL, *p; 
    size_t i = 0; 

    while (fgets(buf, sizeof buf, stdin)) { 
     if (i++ == 0) { 
      s = malloc(sizeof buf); 
      if (s == NULL) { 
       perror("malloc"); 
       exit(EXIT_FAILURE); 
      } 
      strcpy(s, buf); 
     } else { 
      s = realloc(s, (i + 1) * sizeof(buf)); 
      if (s == NULL) { 
       perror("realloc"); 
       exit(EXIT_FAILURE); 
      } 
      strcat(s, buf); 
     } 
     if ((p = strchr(s, '\n'))) { 
      *p = '\0'; 
      break; 
     } 
    } 
    printf("%s\n", s); 
    free(s); 
    return 0; 
} 

沒有一箇中間緩衝區:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

#define BUF_LEN 8 

int main(void) 
{ 
    size_t len = BUF_LEN; 
    char *s, *p; 

    p = s = malloc(len); 
    if (s == NULL) { 
     perror("malloc"); 
     exit(EXIT_FAILURE); 
    } 
    while (fgets(p, BUF_LEN, stdin)) { 
     if ((p = strchr(p, '\n'))) { 
      *p = '\0'; 
      break; 
     } else { 
      len += BUF_LEN - 1; 
      s = realloc(s, len); 
      if (s == NULL) { 
       perror("realloc"); 
       exit(EXIT_FAILURE); 
      } 
      p = s + len - BUF_LEN; 
     } 
    } 
    printf("%s\n", s); 
    free(s); 
    return 0; 
} 
+1

我喜歡關於總是檢查'malloc'和'realloc'的結果的示例代碼下面的警告。 http://en.wikipedia.org/wiki/File:MagrittePipe.jpg –

0

扭捏得到(),以避免緩存溢出

其他人已經在正文中處理了您的問題。這是一個簡單的答案,可以解決標題中的問題。

標準C通過gets_s提供gets的「更安全」變體。它被添加到C標準ISO/IEC TR 24731-1。其中,TR 24731-1的安全功能檢查目標緩衝區大小,以避免其「不安全」對應端的許多緩衝區溢出問題。

下面是從文檔:

enter image description here

所以,你真的不需要調整任何東西。您只需要使用正確的作業功能;)