以下计划:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int check_authentication(char *password)
{
int auth_flag = 0;
char password_buffer[16];
strcpy(password_buffer, password);
if(strcmp(password_buffer, "unipi") == 0)
auth_flag = 1;
if(strcmp(password_buffer, "SSL") == 0)
auth_flag = 1;
return auth_flag;
}
int main(int argc, char *argv[]) {
if(argc < 2) {
printf("Usage: %s <password>\n", argv[0]);
exit(0);
}
if(check_authentication(argv[1])!=0)
{
printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
printf(" Access Granted.\n");
printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
}
else
{
printf("\nAccess Denied.\n");
}
}
在第strcpy(password_buffer, password);
行,它有一个缓冲区溢出漏洞。如果我们想要在不取出strcpy
的情况下使这个程序安全,那怎么可能?
答案 0 :(得分:2)
易。 您将用户输入的验证更改为其他位置。 使用strlen,以便您可以检查字符串是否短于16个字节。
if(strlen(argv[1]) > 15)
{
printf("too long password\n");
exit(0);
}
答案 1 :(得分:1)
我在Wiki上发现了这个:
为了防止在这个例子中发生缓冲区溢出, 对strcpy的调用可以用strncpy替换,后者占用最大值 A的容量作为附加参数并确保不超过 这个数据量写入A:
strncpy(password_buffer, password, sizeof(A));
请注意,上述代码也没有问题;而a 这次阻止了缓冲区溢出,strncpy库 如果源,函数不会空终止目标缓冲区 字符串的长度大于或等于缓冲区的大小 (传递给函数的第三个参数),因此A就是这个 case,not null-terminated,不能被视为有效的C风格 字符串。
答案 2 :(得分:1)
有几种方法可以解决这个问题。
首先,也许最重要的是, 避免固定内存分配 ,尤其是在处理输入时。在上面的示例中,您可以将缓冲区设置为所需的大小,而不是复制到固定大小的缓冲区。
char password_copy[strlen(password) + 1];
strcpy(password_copy, password);
但这并不总是可行的。也许你已经分配了内存。也许你确实希望截断输入(尽管16 is far too small for a password)。
一个是根本不使用C字符串处理函数,它们充满了缺陷和安全漏洞。而是使用像Gnome Lib这样具有the G_String type功能的库。 G_Strings跟踪它们的长度和分配的大小。这需要更多的记忆,但速度更快。找到字符串的长度,发生了很多事情,并不需要遍历字符串的每个字节。
G_Strings have their own set of string handling functions比C更方便。它还可以根据需要增长字符串或为您分配新的字符串。
/* Allocate memory for the copy and copy the password */
G_String *password_copy = g_string_new(password);
为了与常规字符串函数password_copy->str
兼容,返回正常的char *
。
这是IMO最好的方式。您不再需要记住检查字符串长度和分配的大小,并在使用字符串的任何地方担心空字节。你会忘记的。让计算机做到这一点。
如果必须使用C标准函数,请不要使用strncpy
,因为它无法保证截断的字符串将以空值终止。而是使用strlcpy
。它与strncpy
类似,但它保证复制的字符串将以空值终止。 strlcpy
是BSD扩展,因此无法保证可移植。 glibc refuses to implement it
为了最大限度地提高可移植性,效率和安全性strlcpy
并使用memmove
和#ifndef strlcpy
提供后备,因此只有在strlcpy
尚不可用时才会使用它。
#include <string.h>
#include <stdio.h>
#ifndef strlcpy
size_t strlcpy(char * restrict dst, const char * restrict src, size_t dst_size) {
/* size is the allocated size. len leaves space for the null byte */
size_t dst_len = dst_size - 1;
size_t src_len = strlen(src);
/* Use the smaller of the two string lengths to avoid buffer overflow */
size_t move_len = src_len > dst_len ? dst_len : src_len;
/* Copy the string, truncate if necessary. It will work
* even if src and dst overlap. */
memmove(dst, src, move_len);
/* Guarantee there's a null byte */
dst[move_len] = '\0';
/* strlcpy returns the size of the string it tried to make.
* This is used to detect truncation. */
return src_len;
}
#endif
int main()
{
char dst[10];
char *src = "12345678901234567890";
printf("%zu\n", strlcpy(dst, src, 10));
printf("src: %s, dst: %s\n", src, dst);
return 0;
}