编写安全C和安全C语言

“普通人不想自由,他只是想安全。” – HL Menken

我正在尝试编写非常安全的C语言。下面我列出一些我使用的技术,并询问它们是否像我想的那样安全。 请不要犹豫,把我的代码/先入之见撕成碎片。 任何答案,即使是最微不足道的漏洞,或教我一个新的想法将受到高度重视

从stream中读取:

根据GNU C编程教程 getline:

getline函数会根据需要通过realloc函数自动放大内存块,所以永远不会有空间不足 – getline是如此安全的一个原因。 请注意,getline可以安全地处理您的input行,不pipe它多长时间。

我认为getline应该在所有input下防止从stream中读取时发生缓冲区溢出 。

  • 我的假设是否正确? 有没有可能导致利用的input和/或分配scheme? 例如,如果stream中的第一个字符是一些奇怪的控制字符 ,可能是0x08 BACKSPACE(ctl-H)。
  • 有没有工作做mathcertificategetline是安全的?

Malloc在失败时返回空值:

如果malloc遇到错误malloc返回一个NULL指针。 由于仍然可以将指针运算应用于NULL(0x0)指针,因此存在安全风险,因此维基百科build议

/* 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:

当使用sscanf时,我习惯于将大小被提取的string分配给inputstring的大小,以避免出现溢出的可能性。 例如:

 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的所有可能的值导致缓冲区溢出似乎是不可能的。

  • 我对么? 有没有想到的奇怪的angular落案件?
  • 有没有更好的方法来写这个? 已经解决了它的图书馆?

一般的问题:

虽然我发布了大量的问题,但我不希望任何人回答所有问题。 这些问题更多的是我正在寻找的答案的指导方针。 我真的想学习安全的C心态。

  • 还有哪些其他安全的C语言?
  • 我需要经常检查哪些angular落案件?
  • 我如何编写unit testing来执行这些规则?
  • 我怎样才能以可testing性或可证实的方式强制约束呢?
  • 任何推荐的静态/dynamic分析工具或C工具?
  • 你遵循什么安全的C实践,你如何为自己和他人辩护?

资源:

许多资源是从答案中借来的。

  • Linux和Unix的安全编程HOWTO David Wheeler
  • 安全C编程 – SUN Microsystems
  • 不安全的编程例子
  • 添加更多NOPS – 覆盖这些问题的博客
  • CERT安全编码倡议
  • flawfinder – 静态分析工具
  • Yannick Moy 使用Thmcertificate安全
  • libsafe的
  1. 从stream中读取

getline() “会根据需要自动放大内存块”的事实意味着这可能被用作拒绝服务攻击,因为生成一个很长的input将会耗尽可用的内存的过程(或更糟的是,系统!)。 一旦发生内存不足的情况,其他漏洞也可能发挥作用。 代码在低/无内存中的行为很less,很难预测。 恕我直言,设置一切合理的上限是安全的,特别是在安全敏感的应用程序。

此外(正如你所预料的,通过提及特殊字符), getline()只会给你一个缓冲区; 它没有对缓冲区内容做任何保证(因为安全性完全取决于应用程序)。 因此,对input进行消毒仍然是处理和validation用户数据的重要部分。

  1. sscanf的

我倾向于使用正则expression式库,并且为用户数据定义了非常狭义的正则expression式,而不是使用sscanf 。 这样,您可以在input时进行大量的validation。

  1. 普通的留言

    • 模糊工具可用于生成随机input(有效和无效),可用于testing您的input处理
    • 缓冲区pipe理至关重要:缓冲区溢出,下溢,内存不足
    • 竞争条件可以在其他安全的代码中被利用
    • 二进制文件可以被操纵,以注入无效的值或超大的值,所以文件格式的代码必须坚如磐石,而不是假设二进制数据是有效的
    • 临时文件通常可能是安全问题的来源,必须仔细pipe理
    • 代码注入可以用来代替恶意版本的系统或运行时库调用
    • 插件为攻击提供了一个巨大的载体
    • 作为一般原则,我会build议有明确定义的接口,用户数据(或来自应用程序之外的任何数据)被假定为无效和敌对的,直到处理,消毒和validation,以及用户数据进入应用程序的唯一方式

我认为你的sscanf例子是错误的。 使用这种方式时,它仍然可以溢出。

试试这个,它指定了要读取的最大字节数:

 void main(int argc, char **argv) { char buf[256]; sscanf(argv[0], "%255s", &buf); } 

看看这篇IBM开发的关于防止缓冲区溢出的文章。

在testing方面,我会编写一个随机生成随机string的程序,并将它们提供给您的程序,并确保它们得到适当的处理。

天儿真好,

David Wheeler是一个非常好的安全编码站点 。

他的免费在线书籍“ Secure Programming for Linux and Unix HOWTO ”是定期更新的优秀资源。

你也可以看看他的优秀静态分析器FlawFinder,以获得更多的提示。 但请记住,没有一个自动化的工具可以代替一双经验丰富的眼睛,或者像David这样色彩缤纷的眼睛。

任何静态分析工具,如Flawfinder,只是一个工具。 没有工具可以替代人的思想! 总之, “用工具傻瓜还是个傻瓜” 。 认为分析工具(如缺陷探测器)是安全培训和知识的替代品是错误的

我已经亲自使用了大卫的资源好几年了,并发现他们是优秀的。

HTH

干杯,

不安全的编程例子
博客中有一些答案

Yannick Moy在PhD期间为C开发了一个Hoare / Floyd最弱的预处理系统,并将其应用于CERTpipe理的string库 。 他发现了一些错误(参见他的回忆录197页)。 好消息是图书馆为他的工作更安全。

你也可以在这里看到莱斯哈顿的网站,也可以看看你可以从亚马逊那里得到的安全C这本书。

不要使用gets()来input,使用fgets() 。 要使用fgets() ,如果你的缓冲区是自动分配的(即“在堆栈上”),那么使用这个习惯用法:

 char buf[N]; ... if (fgets(buf, sizeof buf, fp) != NULL) 

这将继续工作,如果你决定改变buf的大小。 我更喜欢这种forms:

 #define N whatever char buf[N]; if (fgets(buf, N, fp) != NULL) 

因为第一种forms使用buf来确定第二个参数,并且更清楚。


检查fclose()的返回值。