字符串相关的安全问题一般发生在越过字符串末尾写入的情况。在本节中,我们主要关注可能造成这种问题的“标准”函数。
如果使用strcpy
和strcat
这类字符串函数,稍不留神就会引发缓冲区溢出。已经有人提出一些方法来取代,但都没有得到广泛认可。strncpy
和strncat
函数可以对这种操作提供一些支持,它们的size_t
参数指定要复制的字符的最大数量。不过,如果字符数量计算不正确,替代函数也容易出错。
C11中(Annex K)加入了strcat_s
和strcpy_s
函数,如果发生缓冲区溢出,它们会返回错误,目前只有Microsoft Visual C++支持。下面这个例子说明了strcpy_s
函数的使用,它接受三个参数:目标缓冲区、目标缓冲区的长度以及源缓冲区。如果返回值是0就表示没有错误发生。不过在本例中会有错误发生,因为源缓冲区太大了,目标缓冲区装不下:
char firstName [8];
int result;
result = strcpy_s(firstName,sizeof(firstName),"Alexander");
还有scanf_s
和wscanf_s
函数可以用来防止缓冲区溢出。
gets
函数从标准输入读取一个字符串,并把字符保存在目标缓冲区中,它可能会越过缓冲区的声明长度写入。如果字符串太长的话,就会发生缓冲区溢出。
有些Linux系统也支持strlcpy
和strlcat
函数,但GNU C库不支持。有人认为这两个函数制造的问题比解决的还多,而且文档不全。
使用某些函数可能造成攻击者用格式化字符串攻击的方法访问内存。在这类攻击中,将用户提供的格式化字符串(如下所示)打造得可以访问内存,甚至能够注入代码。在这个简单的程序中,我们将第二个命令行参数作为printf
函数的第一个参数:
int main(int argc, char** argv) {
printf(argv[1]);
...
}
这个程序可以用类似于下面的命令执行:
main.exe "User Supplied Input"
输出类似于:
User Supplied Input
程序本身无害,但是精巧的攻击真的可以造成损害。这里不会就这个话题展开,不过,如何实现这样的攻击可以在hackerproof.org上找到。
printf
、fprintf
、snprintf
和syslog
这些函数都接受格式化字符串作为参数,避免这类攻击的一种简单方法是永远不要把用户提供的格式化字符串传给这些函数。