echo "This is a test" > /tmp/test$$ # DON';T DO THIS.
复制代码
不要再次使用临时文件名称(即不要删除和重新创建文件),不管您最初是如何获得“安全的”临时文件名称。攻击者都有可能观察到原始的文件名称,并在您第二次重新创建它时非法控制它。当然,要始终使用合适的文件权限。
做好自己的清理工作,或者通过使用退出处理器,或者利用 UNIX 文件系统语义,在创建后立即 unlink() 该文件,以便在清除目录条目的同时仍然可以访问该文件,直到指向它的最后一个文件描述符被关闭。于是,您就可以在自己的程序中通过传送文件描述符来访问该文件。对代码维护来说,解除文件的链接有很多好处:不管您的程序是怎样崩溃的,文件都会被自动删除。它还降低了维护者不安全地使用文件名的可能性(改为使用文件描述符)。立即解除链接也有一个小问题,即这使得管理员查看磁盘空间使用情况的难度稍有增加。
使这些对策成为操作系统的一部分已经取得了一些成功,尽管它们当前还没有被广为使用。要获得更多资料,请参阅参考资料列表中关于来自 OpenWall 项目的 Solar Designer 的 Linux 内核补丁、RaceGuard,以及 Eugene Tsyrklevich 和 Bennet Yee 的工作链接。
信号处理
在信号中也会发生竞争条件。程序可以注册处理各种类型的信号,但是信号可能会在最不合适的时候出现,包括您正在处理另一个信号的时候。在一个信号处理器内部,您通常应该做的一件事是,设置一个将在以后处理的全局标记。还有几个操作可以在信号中安全地完成,但不是很多,而且在处理信号之前,您必须对它有深入的理解。那是因为只有一些系统调用可以安全地调用内部信号:只有可重入的(re-entrant)或者不被信号中断的调用才可以被安全地调用。您可以调用库函数,但是只有极少数函数是被安全调用的;在一个信号处理器中调用大部分函数是出问题的主要原因,比如 free() 或者 syslog()。要获得更多资料,请阅读 Michal Zalewski 的名为 “Delivering Signals for Fun and Profit”的一篇文章。但是您最好只在一个信号处理器中设置标记(别的什么都不做),这胜过尝试创建复杂的处理器。
结束语
本文讨论了什么是竞争条件,以及它为什么会导致安全问题。我们已经分析了如何正确地创建锁文件及其替代者。还研究了如何处理文件系统,并重点讨论了如何处理共享目录,以完成在 /tmp 目录下创建临时文件等一些常见任务。我们还简要地研究了信号处理,至少充分了解了使用它们的一种安全方法。
当然,重要的是保护您的程序不受竞争条件的破坏。但是,当前的大部分程序都不能自己完成所有的事情;它们必须向其他程序库和程序(比如命令解释程序和 SQL 服务器)发出请求。攻击程序使用的最常见方式之一就是利用这些程序向其他程序发出请求的方式。所以,接下来我们将分析如何在不暴露缺陷的同时去调用其他程序。
参考资料
您可以参阅本文在 developerWorks 全球站点上的 英文原文。
阅读 developerWorks 上 David 的其他安全编程专栏文章。
关于作者
David A. Wheeler 是计算机安全性方面的专家,他长期致力于提高大型和高风险软件系统的开发技术的工作。他是Secure Programming for Linux and Unix HOWTO 一书的作者,而且还是通用标准(Common Criteria)的验证者。David 撰写了 Why Open SourceSoftware/Free Software? Look at the Numbers! 一文,并且是 Springer-Verlag 出版的 Ada95: The Lovelace Tutorial 一书的作者,此外,他还是由 IEEE 出版的 Software Inspection: An Industry Best Practice 一书的合著者和第一编撰人。这篇 developerWorks 文章代表了作者的观点,但并不一定代表 Institute for Defense Analyses 的立场。您可以通过 dwheelerNOSPAM@dwheeler.com 与 David 联系(删掉 “NOSPAM”以后)。 作者: x86 时间: 2005-3-23 23:00 标题: 安全编程: 避免竞争条件