programing

gets 기능이 왜 그렇게 위험해서 사용하면 안 되는가?

prostudy 2022. 5. 8. 22:01
반응형

gets 기능이 왜 그렇게 위험해서 사용하면 안 되는가?

를 사용하는 C 코드를 컴파일하려고 할 때gets()GCC와 함께 작동하면 다음과 같은 경고를 받는다.

(.text+0x34): 경고: '위험' 기능은 사용해서는 안 된다.

나는 이것이 스택 보호와 보안과 관련이 있다는 것을 기억하지만, 왜 그런지 정확히 모르겠다.

어떻게 하면 이 경고를 제거할 수 있으며, 왜 사용과 관련된 경고가 있는가?gets()?

만약gets()그렇다면 왜 우리는 그것을 제거할 수 없을까?

왜 그럴까?gets()위험한

최초의 인터넷 웜(Morris Internet Worm)은 약 30년 전(1988-11-02) 탈출했고, 이를 이용했다.gets()시스템에서 시스템으로 전파하는 방법의 하나로 버퍼 오버플로를 들 수 있다.기본적인 문제는 함수가 버퍼의 크기를 모르기 때문에 뉴라인을 찾거나 EOF를 만날 때까지 계속 읽으며 주어진 버퍼의 한도를 넘칠 수 있다는 것이다.

는 그 을 들은 을 잊어야 .gets()존재했다

에서 C11 표준 ISO/IEC 9899:2011 제거가 되었다.gets()표준 함수인 A Good Thing™(ISO/IEC 9899:1999/Cor.3:2007 — C99용 기술 Corrigendum 3에서 공식적으로 '불완전' 및 '불완전'으로 표시되었다가 C11에서 제거됨).슬프게도, 그것은 역호환성을 이유로 여러 해 동안 도서관에 남아있을 것이다.내가 결정할 일이라면, 의 이행은.gets()다음이 될 수 있음:

char *gets(char *buffer)
{
    assert(buffer != 0);
    abort();
    return 0;
}

어차피 당신의 코드가 조만간 깨질 것이기 때문에, 그 문제는 그 때보다는 빨리 해결하는 것이 좋다.오류 메시지를 추가할 준비가 된 경우:

fputs("obsolete and dangerous function gets() called\n", stderr);

은 연하하면 컴하라면 을 연결하면 경고를 시킨다.gets()— 또한 보안 문제가 있는 일부 다른 기능도 해당된다.mktemp(), …).

에 대한 대안gets()

fgets().

다른 모든 사람들이 말했듯이, 에 대한 표준적인 대안은gets()지정 중stdin파일 스트림에서.

char buffer[BUFSIZ];

while (fgets(buffer, sizeof(buffer), stdin) != 0)
{
    ...process line of data...
}

아직 아무도 언급하지 않은 것은gets()뉴라인은 포함하지 않지만fgets()그러니까, 포장지를 둘러야 할 필요가 있겠네fgets()새로운 라인을 삭제하는 방법:

char *fgets_wrapper(char *buffer, size_t buflen, FILE *fp)
{
    if (fgets(buffer, buflen, fp) != 0)
    {
        size_t len = strlen(buffer);
        if (len > 0 && buffer[len-1] == '\n')
            buffer[len-1] = '\0';
        return buffer;
    }
    return 0;
}

또는 더 나은 방법:

char *fgets_wrapper(char *buffer, size_t buflen, FILE *fp)
{
    if (fgets(buffer, buflen, fp) != 0)
    {
        buffer[strcspn(buffer, "\n")] = '\0';
        return buffer;
    }
    return 0;
}

또한 카페가 논평에서 지적하고 팍스디아블로(paxdiablo)가 그의 대답에서 보여주듯이, 그의 대답에서는 다음과 같이 말하고 있다.fgets()데이터가 한 줄에 남아 있을 수도 있어내 래퍼 코드는 다음 번에 읽을 데이터를 남겨두므로, 다음 중 원하는 경우 데이터 라인의 나머지 부분을 게걸스럽게 수정하십시오.

        if (len > 0 && buffer[len-1] == '\n')
            buffer[len-1] = '\0';
        else
        {
             int ch;
             while ((ch = getc(fp)) != EOF && ch != '\n')
                 ;
        }

나머지 문제는 EOF 또는 오류, 선 읽기 및 잘리지 않음, 부분 선 읽기는 하지만 데이터는 잘린 세 가지 결과 상태를 보고하는 방법이다.

이 문제는 에 발생하지 않는다.gets()왜냐하면 그것은 당신의 버퍼의 끝부분을 알 수 없고 끝부분을 즐겁게 짓밟고, 아름답게 처리된 당신의 메모리 레이아웃을 엉망으로 만들고, 종종 그 스택에 버퍼가 할당되어 있으면 반환 스택(Stack Overflow)을 엉망으로 만들거나, 또는 버퍼가 동적으로 할당되어 있으면 제어 정보를 짓밟거나, 다른 프리시에 데이터를 복사한다.ous 글로벌(또는 모듈) 변수(버퍼가 정적으로 할당되는 경우).이 중 어느 것도 좋은 생각이 아니다. 즉 '정의되지 않은 행동'이라는 문구를 잘 나타내고 있다.


또한 TR 24731-1(C 표준 위원회의 기술 보고서)이 있어 다음을 포함한 다양한 기능에 대한 안전한 대안을 제공한다.gets():

제6.5.4.1조gets_s기능을 하다

시놉시스

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
char *gets_s(char *s, rsize_t n);

런타임-불규칙성

sNull 포인터가 되지 않아야 한다. n0과 같거나 RSIZ_보다 한다.MAX보다 크면 안 된다.읽기 내에서 새로운 줄 문자, 파일 끝 또는 읽기 오류가 발생해야 한다.n-1에서 온 인물들stdin.25)

3 런타임으로 인한 위반이 있을 경우,s[0] null 문자에서 한다.stdin새 줄 문자를 읽거나, 파일 끝 또는 읽기 오류가 발생할 때까지.

설명

4 Thegets_s보다 한 .n가 가리키는 시냇물에서.stdin, 에 의해 가리킨 배열로.s 새 줄 파일 후 수 추가 문자는 새 줄 문자(폐기) 이후 또는 파일 종료 후에 읽히지 않는다.버려진 새로운 줄 문자는 읽은 문자 수에 반영되지 않는다.가 바로

5 파일 끝부분이 발생하여 배열에 문자를 넣지 않았거나 작업 중에 읽기 오류가 발생한 경우s[0] null 문자의 는 null 문자로 설정된다.s불특정 가치를 지니다

권장 프랙티스

6 Thefgets함수는 적절하게 작성된 프로그램이 결과 배열에서 저장하기에 너무 긴 시간 동안 입력 라인을 안전하게 처리할 수 있도록 한다.일반적으로 이것은 다음 사항을 호출하는 사람을 필요로 한다.fgets결과 배열에서 새 줄 문자의 유무에 주의한다.사사또를 하는 것을 한다.fgets(새로운 줄 문자를 기반으로 하는 필요한 처리와 함께)gets_s.

25) Thegets_s기능과는 달리 기능하다.gets는 입력 라인이 버퍼에 오버플로되어 저장되는 런타임 처리 위반으로 만든다.와는 달리fgetsgets_s입력 회선과 성공적인 통화 사이의 일대일 관계를 유지한다.gets_s. 사용하는 프로그램gets그런 관계를 기대하다

마이크로소프트 비주얼 스튜디오 컴파일러는 TR 24731-1 표준에 근사치를 구현하지만, 마이크로소프트가 구현한 서명과 TR의 서명에 차이가 있다.

C11 표준인 ISO/IEC 9899-2011은 도서관의 선택적 부분으로 부속서 K의 TR24731을 포함한다.불행히도 유닉스 같은 시스템에서는 거의 구현되지 않는다.


getline() - POSIX

POSIX 2008은 또한 다음과 같은 안전한 대안을 제공한다.gets()부름을 받았다그것은 동적으로 선을 위한 공간을 할당하기 때문에, 당신은 그것을 자유롭게 할 필요가 있다.따라서 선 길이의 제한을 없앤다.읽은 데이터의 길이도 반환한다.-1(그렇지도 않고)EOF!) 즉, 입력의 null 바이트는 신뢰성 있게 처리될 수 있다.또한 '자신의 단문자 구분 기호 선택'이라는 변형도 있다.getdelim(); 이것은 당신이 의 출력을 다루는 경우에 유용할 수 있다.find -print0이 표시되어 .'\0'예를 들어 캐릭터.

사용하기 위해gets안전하게, 여러분은 얼마나 많은 문자를 읽을 것인지 정확히 알아야 한다. 그래야 버퍼의 크기가 충분히 커질 수 있다.어떤 자료를 읽고 있는지 정확히 알아야 비로소 알 수 있을 것이다.

사용하는 대신gets, 사용하고자 하는 , 이 서명이 있는 .

char* fgets(char *string, int length, FILE * stream);

(fgets줄한 줄만 '을을면'을'\n'현악기 안에서; 너는 그것을 다루어야 할 것이다.)

gets1999년 ISO C 표준까지 공식 언어의 일부로 남아있었지만, 2011년 표준에서 공식적으로 제거되었다.대부분의 C 구현은 여전히 이를 지원하지만, 적어도 gcc는 이를 사용하는 모든 코드에 대해 경고를 발한다.

API를 파괴하지 않고는 API 기능을 제거할 수 없다.만약 당신이 원한다면, 많은 애플리케이션들은 더 이상 컴파일하거나 전혀 실행되지 않을 것이다.

한 참고문헌이 다음과 같은 이유를 제시한다.

s가 가리키는 배열을 넘나드는 선을 읽으면 정의되지 않은 동작이 발생한다.fget()의 사용을 권장한다.

왜냐하면getsstdin에서 바이트를 가져와 어딘가에 넣는 동안 어떤 종류의 확인도 하지 않는다.간단한 예:

char array1[] = "12345";
char array2[] = "67890";

gets(array1);

자, 우선, 당신이 원하는 글자 수를 입력하도록 허용된다.gets신경 안 쓸 거야두 번째로, 바이트를 배치한 어레이 크기(이 경우)array1)은(는) 그들이 기억에서 찾은 모든 것을 덮어쓸 것이다.gets쓸거야앞의 예에서 이것은 만약 당신이 입력한다면"abcdefghijklmnopqrts"아마도, 예측 불가능하게, 그것은 또한 덮어쓸 것이다.array2뭐, 뭐 그런 거든.

그 기능은 일관된 입력을 가정하기 때문에 안전하지 않다.절대 사용하지 마십시오!

잡동사니

Stdin에서 읽으려면:

char string[512];

fgets(string, sizeof(string), stdin); /* no buffer overflows here, you're safe! */

gets()사용자가 프롬프트에 너무 많이 입력하여 프로그램을 중단시킬 수 있기 때문에 위험하다.사용 가능한 메모리의 끝을 감지할 수 없기 때문에 목적에 맞게 메모리 양을 너무 작게 할당하면 seg 결함을 유발하고 충돌할 수 있다.때때로 사용자가 한 사람의 이름을 의미하는 프롬프트에 1000자를 타이핑할 가능성은 거의 없어 보이지만, 프로그래머로서 우리는 우리의 프로그램을 방탄으로 만들어야 한다.(사용자가 너무 많은 데이터를 전송하여 시스템 프로그램을 손상시킬 수 있는 경우에도 보안 위험이 될 수 있다.)

fgets()변수를 오버런하지 않도록 표준 입력 버퍼에서 몇 개의 문자를 빼는지 지정할 수 있다.

사용해서는 안 된다.gets보다 더 나 더 결과를 때문이다사용자가 버퍼에 들어갈 수 있는 것보다 더 많은 데이터를 입력하면 손상되거나 더 나빠질 가능성이 크다.

사실 ISO는 실제로 제거의 단계를 밟았다. gets역호환성을 얼마나 높게 평가하는지 볼 때 해당 기능이 얼마나 나쁜지 나타내는 C 표준(C11을 기준으로, C99에서 더 이상 사용되지 않음)으로부터.

올바른 방법은 다음 제품을 사용하는 것이다.fgets의 기능을 하다stdin사용자가 읽은 문자를 제한할 수 있으므로 파일 핸들.

그러나 이것은 다음과 같은 문제도 가지고 있다.

  • 사용자가 입력한 추가 문자는 다음 번에 선택된다.
  • 사용자가 너무 많은 데이터를 입력했다는 빠른 알림은 없다.

그것을 위해, 그들의 경력의 어느 시점에 거의 모든 C 코더는 주위에 더 유용한 포장지를 쓸 것이다.fgets뿐만 아니라.여기 내 것이 있다:

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

#define OK       0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
    int ch, extra;

    // Get line with buffer overrun protection.
    if (prmpt != NULL) {
        printf ("%s", prmpt);
        fflush (stdout);
    }
    if (fgets (buff, sz, stdin) == NULL)
        return NO_INPUT;

    // If it was too long, there'll be no newline. In that case, we flush
    // to end of line so that excess doesn't affect the next call.
    if (buff[strlen(buff)-1] != '\n') {
        extra = 0;
        while (((ch = getchar()) != '\n') && (ch != EOF))
            extra = 1;
        return (extra == 1) ? TOO_LONG : OK;
    }

    // Otherwise remove newline and give string back to caller.
    buff[strlen(buff)-1] = '\0';
    return OK;
}

일부 테스트 코드:

// Test program for getLine().

int main (void) {
    int rc;
    char buff[10];

    rc = getLine ("Enter string> ", buff, sizeof(buff));
    if (rc == NO_INPUT) {
        printf ("No input\n");
        return 1;
    }

    if (rc == TOO_LONG) {
        printf ("Input too long\n");
        return 1;
    }

    printf ("OK [%s]\n", buff);

    return 0;
}

다음과 같은 보호 기능을 제공한다.fgets이는 버퍼 오버플로를 방지하지만, 또한 발신자에게 발생한 일에 대해 통지하고 초과 문자를 지워 다음 입력 작업에 영향을 미치지 않도록 한다.

원하시는 대로 사용하십시요, 이에 따라 "빌어먹을 원하는 대로 하십시오" 라이선스 :-)

C가 기능을 얻는 것은 위험하고 비용이 많이 드는 실수였다.Tony Hoare는 그의 강연 "Null Reference:억만장자 실수":

http://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare

1시간 내내 볼 만하지만 30분 후부터는 구체적인 내용을 담은 댓글이 39분 전후로 비판을 받고 있다.

이것이 전체 강연에 대한 여러분의 욕구를 자극하기를 바라며, 이것은 어떻게 우리가 언어에서 더 공식적인 정확성 증명이 필요한지, 그리고 어떻게 언어 디자이너들이 프로그래머가 아닌 그들의 언어에서 실수를 저질렀다고 비난 받아야 하는지에 관심을 끈다.이것은 나쁜 언어의 디자이너들이 '프로그래머의 자유'라는 미명하에 프로그래머들에게 책임을 떠넘긴 모든 의심스러운 이유인 것 같다.

나는 최근에 USENET 포스트에서 그것을 읽었다.gets()표준에서 삭제되고 있어우후

위원회가 방금 초안에서도 () gets()를 없애기 위해 투표했다는 것을 알면 기뻐할 것이다.

C11(ISO/IEC 9899:201x)에서 다음과 같이 표시하였다.gets()제거되었다.(ISO/IEC 9899:1999/Cor.3:2007(E)에서 더 이상 사용되지 않음)

에 더하여fgets(), C11은 새로운 안전한 대안을 소개한다.gets_s():

K.3.5.4.1gets_s기능을 하다

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
char *gets_s(char *s, rsize_t n);

단, 권장 프랙티스 섹션에서는fgets()여전히 선호되고 있다.

fgets함수는 적절하게 작성된 프로그램이 결과 배열에서 저장하기에 너무 긴 시간 동안 입력 라인을 안전하게 처리할 수 있도록 한다.일반적으로 이것은 다음 사항을 호출하는 사람을 필요로 한다.fgets결과 배열에서 새 줄 문자의 유무에 주의한다.사사또를 하는 것을 한다.fgets(새로운 줄 문자를 기반으로 하는 필요한 처리와 함께)gets_s.

는 C도서원을 .gets라이브러리에서 "누구나 여전히 의존하고 있는 경우": 구현을 다음 항목과 동등한 것으로 대체하십시오.

char *gets(char *str)
{
    strcpy(str, "Never use gets!");
    return str;
}

이것은 아무도 여전히 그것에 의존하지 않도록 하는 데 도움이 될 것이다.감사합니다.

몇 마디 말로gets()(can) 사용자가 변수를 저장할 충분한 공간보다 더 큰 값을 입력할 수 있으므로 위험할 수 있다.첫 번째 대답은 다음과 같다.fgets()그리고 왜 그것이 더 안전한지.

추가 정보:

보낸 사람man 3 getsLinux Ubuntu에서 확인 가능(강조 추가):

DESCRIPTION
       Never use this function.

그리고 여기 있는 cppreference.com wiki(https://en.cppreference.com/w/c/io/gets)에서 다음 내용을 확인하십시오.Notes Never use gets().:

메모들

gets()함수는 경계 검사를 수행하지 않으므로 이 함수는 버퍼링 공격에 매우 취약하다.안전하게 사용할 수 없다(프로그램이 나타날 수 있는 것을 제한하는 환경에서 실행되지 않는 한).stdin이러한 이유로 C99 표준에 대한 세 번째 각막에서 기능이 더 이상 사용되지 않고 C11 표준에서 모두 제거되었다.fgets()그리고gets_s()권장 교체품이다.

절대 사용하지 마십시오.gets().

보시다시피 C11 이상에서 기능이 저하되어 완전히 제거되었다.

아니면 대신 쓰세요.

참조URL: https://stackoverflow.com/questions/1694036/why-is-the-gets-function-so-dangerous-that-it-should-not-be-used

반응형