在 C 语言编程中,我们常常会涉及到字符串操作,如文件读写、协议交互等等,此时我们可以使用 C 库中自带的字符串操作函数,由于库已经帮我们封装好了各种字符串操作的内部实现,用起来自然也是非常方便。然而,我们日常使用的库函数有一部分实际上是不安全的!稍不注意就会导致数据异常,甚至程序崩溃。下面我们就来列举几个常见的“不安全”函数,看看你中招了吗?
gets – 从标准输入中读取一行字符串
gets 的函数声明如下:
char *gets(char *str)
该函数会从标准输入读取一行,并将其存储在指定的缓冲区 str 中。读取操作在遇到换行符或文件结束符时终止,并用空字符(null)终止字符串。但该函数不会检查输入字符串的长度。一旦标准输入中的字符串长度大于 str 缓冲区的大小,此时就会导致缓冲区溢出,从而引发潜在的安全漏洞:
char buffer[10];
gets(buffer); // 如果输入的字符串长度大于 10 就会导致缓冲区溢出
替代方案:fgets
fgets 的函数声明如下:
char *fgets(char *str, int n, FILE *stream)
该函数会从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止。由于限定了读取的最大长度(当然此处长度必须要合理,如果缓冲区本身只有 10 个字节,你却硬是传了 15 进去,那只能说是程序 BUG 了),因此就避免了产生缓冲区溢出的问题:
char buffer[10];
fgets(buffer, sizeof(buffer), stdin); // 无论输入是多长,此处 fgets 最多只会读 9 个有效字符
strcpy – 字符串拷贝
strcpy 函数的声明如下:
char *strcpy(char *dest, const char *src)
该函数将源字符串复制到目标缓冲区中,包括终止的空字符(null)。但其不会检查目标缓冲区的大小,因此一旦源字符串长度超过目标缓冲区大小,就会导致缓冲区溢出:
char dest[10];
char *src = “This is a long string”;
strcpy(dest, src); // 可能导致缓冲区溢出
替代方案:strncpy
strncpy 函数的声明如下:
char *strncpy(char *dest, const char *src, size_t n)
该函数把 src 所指向的字符串复制到 dest,最多复制 n 个字符。当 src 的长度小于 n 时,dest 的剩余部分将用空字节填充。因此由于限制了复制的长度,同样也就不会导致缓冲区溢出。
char dest[10];
char *src = "This is a long string";
strncpy(dest, src, sizeof(dest) - 1); // 安全复制
dest[sizeof(dest) - 1] = ''; // 确保终
strcat – 字符串拼接
strcat 函数的声明如下:
char *strcat(char *dest, const char *src)
该函数把 src 所指向的字符串追加到 dest 所指向的字符串的结尾。很显然如果 src + dest 的字符串长度大于 dest 缓冲区的大小,就会造成缓冲区溢出:
char dest[20] = “Hello, “;
char *src = “world!”;
strcat(dest, src); // 缓冲区溢出
替代方案:strncat
strncat 函数的声明如下:
char *strncat(char *dest, const char *src, size_t n)
该函数把 src 所指向的字符串追加到 dest 所指向的字符串的结尾,直到 n 字符长度为止。由于限制了最大长度,一旦长度太大,追加的字符串就会被截断,自然也就不会出现缓冲区溢出的问题:
char dest[10] = "Hello, ";
char *src = "world!";
strncat(dest, src, sizeof(dest) - strlen(dest) - 1); // 安全追加
sprintf – 格式化字符串输出
sprintf 函数的声明如下:
int sprintf(char *str, const char *format, …)
该函数会按指定要求格式化一个字符串并将其存储在目标缓冲区中。其不检查目标缓冲区的长度,因此当格式化出来的字符串长度大于目标缓冲区长度时,就会导致缓冲区溢出:
char buffer[10];
int value = 123;
sprintf(buffer, “The value is %d”, value); // 缓冲区溢出
替代方案:snprintf
snprintf 函数的声明如下:
int snprintf ( char * str, size_t size, const char * format, … )
该函数在 sprintf 函数的基础上增加了输出字符数的限制参数,从而避免缓冲区溢出。
char buffer[10];
int value = 123;
snprintf(buffer, sizeof(buffer), “The value is %d”, value); // 安全格式化
以上就是常用的几个 “不安全” 函数,你中招了吗?如果有类似的经历可以在评论区分享。
实际在实现对应功能时还是推荐要用这些函数的安全版本,如果出于某些原因不得不用这些函数,也一定要做好输入输出的限制,尽可能杜绝潜在的风险 。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至2705686032@qq.com 举报,一经查实,本站将立刻删除。原文转载: 原文出处: