“普通人不想自由。他只是想要安全。” - H. L. Menken
我正在尝试编写非常安全的C.下面我列出了一些我使用的技术,并且问我们是否像我认为的那样安全。请不要犹豫将我的代码/先入之见撕成碎片。任何能找到最微不足道的漏洞或者教会我一个新想法的答案都将被高度重视。
根据GNU C Programming Tutorial getline:
getline函数会 自动放大块 根据需要通过realloc记忆 功能,所以永远不会缺货 空间 - getline的一个原因 太安全了[..]请注意,getline可以 安全地处理你的输入线,没有 不管它有多长。
我认为getline应该在所有输入下,防止在从流中读取时发生buffer overflow。
如果malloc遇到错误,malloc将返回NULL指针。这会带来安全风险,因为仍然可以将指针算法应用于NULL(0x0)指针,因此维基百科recommends
/* Allocate space for an array with ten elements of type int. */
int *ptr = (int*)malloc(10 * sizeof (int));
if (ptr == NULL) {
/* Memory could not be allocated, the program should handle
the error here as appropriate. */
}
当使用sscanf时,我已经养成了将要提取的字符串分配给输入字符串大小的习惯,希望避免出现溢出的可能性。例如:
const char *inputStr = "a01234b4567c";
const char *formatStr = "a%[0-9]b%[0-9]c":
char *str1[strlen(inputStr)];
char *str2[strlen(inputStr)];
sscanf(inputStr, formatStr, str1, str2);
因为str1和str2是inputStr的大小,并且不能从inputStr读取比strlen(inputStr)更多的字符,所以看起来不可能,因为inputStr的所有可能值导致缓冲区溢出?
虽然我发布了大量问题,但我不希望任何人回答所有这些问题。这些问题更多地是我正在寻找的各种答案的指南。我真的很想学习安全的C语言。
许多资源都来自答案。
答案 0 :(得分:6)
我认为你的sscanf例子是错误的。用这种方式它仍然会溢出。
尝试此操作,指定要读取的最大字节数:
void main(int argc, char **argv)
{
char buf[256];
sscanf(argv[0], "%255s", &buf);
}
Take a look at this IBM dev article about protecting against buffer overflows.
在测试方面,我会编写一个程序,生成随机长度的随机字符串并将它们提供给您的程序,并确保它们得到适当的处理。
答案 1 :(得分:4)
开始查看此内容的好地方是David Wheeler's excellent secure coding site。
他的免费在线图书“Secure Programming for Linux and Unix HOWTO”是一个定期更新的优秀资源。
您可能还想看看他出色的静态分析器FlawFinder以获得更多提示。但是请记住,没有一个自动化工具可以替代一双经验丰富的眼睛,或者像大卫那样慷慨地说它。
任何静态分析工具,例如Flawfinder,都只是一种工具。没有工具可以替代人类思想!简而言之,“带工具的傻瓜仍然是个傻瓜”。认为分析工具(如flawfinder)可以替代安全培训和知识是错误的
我已经亲自使用David的资源已经好几年了,并且发现它们非常出色。
答案 2 :(得分:4)
getline()
“将根据需要自动扩大内存块这一事实”意味着这可以用作拒绝服务攻击,因为生成一个如此长的输入是微不足道的它会耗尽进程的可用内存(或者更糟糕的是系统!)。一旦出现内存不足的情况,其他漏洞也可能会发挥作用。低/无内存中的代码行为很少很好,很难预测。恕我直言,为所有事情设置合理的上限更安全,特别是在安全敏感的应用程序中。
此外(正如您通过提及特殊字符所预期的那样),getline()
仅为您提供缓冲区;它不保证缓冲区的内容(因为安全性完全取决于应用程序)。因此,对输入进行清理仍然是处理和验证用户数据的重要部分。
我倾向于使用正则表达式库,并且为用户数据定义非常精确的regexp,而不是使用sscanf
。这样,您可以在输入时执行大量验证。
一般评论
答案 3 :(得分:1)
答案 4 :(得分:1)
Yannick Moy在他的博士和applied it to the CERT managed strings library期间为C开发了一个Hoare / Floyd最弱的预处理系统。他发现了许多错误(见他的回忆录第197页)。好消息是图书馆现在更安全。
答案 5 :(得分:1)
您还可以查看Les Hatton的网站here以及您可以从亚马逊获得的更安全的C 这本书。
答案 6 :(得分:0)
请勿使用gets()
进行输入,请使用fgets()
。要使用fgets()
,如果你的缓冲区是自动分配的(即“在堆栈上”),那么使用这个习语:
char buf[N];
...
if (fgets(buf, sizeof buf, fp) != NULL)
如果您决定更改buf
的大小,这将继续有效。我更喜欢这种形式:
#define N whatever
char buf[N];
if (fgets(buf, N, fp) != NULL)
因为第一个表单使用buf
来确定第二个参数,并且更清晰。
Check the return value of fclose()
.