C언어에서 gets()
함수는 입력을 처리하는 데 사용되었지만, 심각한 보안 문제로 인해 더 이상 사용되지 않습니다. 실제로, 최신 C 표준(C11)에서는 gets()
함수가 완전히 제거되었습니다. 아래에서는 gets()
함수의 위험성과 그에 대한 안전한 대안을 살펴보겠습니다.
1. gets()
함수가 위험한 이유
1.1. 버퍼 오버플로우 문제
gets()
함수는 입력 버퍼의 크기를 확인하지 않고 무제한으로 입력을 읽습니다.- 만약 사용자 입력이 버퍼 크기를 초과하면, 메모리의 다른 영역을 덮어쓰게 됩니다.
- 결과: 프로그램이 비정상적으로 종료되거나, 공격자가 임의의 코드를 실행할 수 있는 취약점(버퍼 오버플로우 공격)이 발생합니다.
예제 코드:
char buffer[10];
gets(buffer); // 버퍼 크기를 확인하지 않고 입력을 읽음
문제 시나리오:
- 입력값:
123456789012345
- 결과: 메모리 오버플로우로 인해 프로그램 동작이 예측 불가능하게 됩니다.
1.2. 보안 사고 사례
- 1988년 모리스 웜(Morris Worm):
- 인터넷 웜의 초기 사례 중 하나로,
gets()
함수의 버퍼 오버플로우 취약점을 악용해 시스템 간에 웜이 퍼졌습니다. - 이 사건 이후
gets()
함수는 대표적인 보안 취약점으로 주목받았습니다.
- 인터넷 웜의 초기 사례 중 하나로,
2. gets()
의 대안
2.1. fgets()
함수
fgets()
는 입력 크기를 제한하며, 지정된 버퍼 크기만큼만 읽습니다.- 사용 예:
char buffer[10];
fgets(buffer, sizeof(buffer), stdin); // 안전하게 입력 처리
- 특징:
- 버퍼 크기를 초과하는 입력은 자동으로 잘립니다.
- 개행 문자(
\n
)가 포함되므로 필요시 제거해야 합니다:
buffer[strcspn(buffer, "\n")] = '\0'; // 개행 문자 제거
2.2. POSIX getline()
함수
getline()
함수는 동적으로 메모리를 할당하여 무제한 입력을 안전하게 처리할 수 있습니다.- 사용 예:
char *line = NULL;
size_t len = 0;
getline(&line, &len, stdin);
printf("입력값: %s", line);
free(line); // 동적 메모리 해제
- 특징:
- 동적으로 메모리를 관리하므로 입력 크기에 제한이 없습니다.
- 사용 후 **
free()
**를 호출해 메모리를 해제해야 합니다.
2.3. C11 gets_s()
함수
- C11 표준에서는
gets()
의 대체로gets_s()
함수를 제안합니다. - **
gets_s()
**는 버퍼 크기를 명시적으로 전달하며, 크기를 초과하는 입력은 읽지 않습니다. - 사용 예:
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
char buffer[10];
gets_s(buffer, sizeof(buffer)); // 안전한 입력 처리
- 한계:
- 대부분의 컴파일러와 표준 라이브러리에서 지원하지 않습니다.
- 주로 Windows 환경에서 사용 가능합니다.
3. 권장 대안
- 일반적인 입력 처리:
fgets()
함수 사용 - 큰 데이터 입력 처리: POSIX의
getline()
함수 사용 - 특정 플랫폼:
gets_s()
사용(C11 지원 환경)
4. 결론
gets()
함수는 버퍼 크기를 확인하지 않아 심각한 보안 취약점을 초래합니다. 이러한 문제로 인해 C11 표준에서 공식적으로 제거되었으며, 더 이상 사용하지 않는 것이 좋습니다. fgets()
나 getline()
과 같은 안전한 대체 함수를 사용하는 것이 현대적인 C 프로그래밍의 필수적인 보안 습관입니다.
Reference