June 29, 2011
http://lwn.net/Articles/449460/
翻译:朱翊然/李凯
正确的处理好用户控制的数据是计算机安全基本原则之一。多种内核日志消息允许用户通过“%s”格式将自己控制的内容放入消息中,这可能被攻击者用在字符串中插入控制字符的方式来混淆管理员。所以 Vasiliy Kulikov提出了一个可以转义特定字符的补丁。关于究竟应该转义哪些字符引发了争议,这背后更大的问题是在安全领域存在已久的问题:白名单还是黑名单。
问题来源于这样一种想法:管理员经常用类似tail和more这样的工具在TTY上查看日志文件,如果用户可以在日志文件中插入控制字符(特别是转义序列),他们可能会导致重要信息被忽略或者其他类型的混乱。在最坏的情况下,转义序列可能会利用终端模拟程序的一些漏洞去执行代码或者引起其他的不正常行为。在该补丁中,Kulikov给出一下例子:“控制字符可以通过tty愚弄查看日志的管理员,比如用^[1A去消除上一个日志行”,对于被过滤的字符,该补丁简单的用“#xx”来替换它们,xx是字符的十六进制值。
在一定程度上,这是相当小的问题,但是我们并不完全了解什么情况下需要使用控制字符。争论中提到的两个很常见的例子就是文件名以及USB产品ID字符串。补丁的第一个版本做的工作显然太过分了,它除了控制字符,把所有 0x7e 以上的字符都转义了,这样Uincode以及其他非ASCII字符都将被转义。但是在抱怨这件事情后,Kulikov的第二个版本仅仅转义了控制字符(小于0x20),但是不包括换行和制表符。
Ingo Molnar 觉得这样并不好,他认为与其把这些已知的字符(newline/tab)列入白名单,还不如把有潜在危害的字符列入黑名单:
另外,我认为这将是更好的方法:排除少数有危害的控制字符(例如退行和控制台转义),而不是试图包括那些有用的字符。
[...]这也是内核开发的一个准则:我们处理已知有害的东西,其他的放任不管。
但是为了创建白名单,不同终端模拟器上不同控制字符的影响必须仔细的确定,而白名单的方法可以简单的形成一张很大的网络。 Kulikov 指出,找出哪些字符有问题不简单:
你能不阅读之前的讨论而立即回答那些控制字符是有害的吗,哪些字符是有时有害的(在一些 tty上),哪些又总是安全的以及原因(甚至回答为什么它总是有害的)?我对tty不精通,我必须去阅读console_codes(4)或者类似的文档去回答这个问题,大多数的内核工程师或许也不得不去读这些文档。
类似 Molnar 和 Kulikov 的分歧在安全领域已经存在很多年了。至今也没有分出到底谁的观点更好。安全领域的绝大多数方面都涉及到了白名单和黑名单之间的平衡点。一般而言,基于用户提供的数据(例如在web应用中),达成了这么个共识,即把好的输入列为白名单,而不是试图去排斥那些“bad”输入。至少在这方面,Molnar并不认为白名单是一个好机制:黑名单是明确的:它禁止显示一些特定的字符,因为那些字符是危险的。
白名单在另一方面白名单却走了一条错路,它把“举证责任”给了有用的好家伙,这实际上起了反作用
Kulikov并不同意之前的分析,这一点都不奇怪:“如何应对那些还未知的危险字符”。当然这里有一个问题,虽然把已知的好的字符列入白名单更加安全,但是如果在用户提供的字符串中的其他受控制的字符中有合法的用途的话,白名单制就不够灵活了。
在这个特殊的案例中,任何一个解决方案都不错,因为并没有什么好的理由去包含这些字符,但是 Molnar 可能是对的,ASCII中并没有什么隐藏的危险 。有一个疑问就是这种改变是否有必要。管理员可能会错过重要的信息,或被精心制作的输入欺骗(Willy Tarreau 提供了有趣的例子,是有关第二种情况的),这种担心让这个补丁诞生。 Linus Torvalds不相信这是一个真正需要解决的问题:我的确认为应该在用户进程那里做过滤——人们不应该用 cat 查看 dmesg。如果他们这样做了,他们真的是咎由自取。
就我所知,我们也没有在控制台层面上做任何转义序列处理,所以控制字符也不会搞乱控制台。
最危险的字符是看起来没有过滤的那个:我们最先想到的字符应该是’\n’,而且当你在字符串中插入一个新行后再尽力使其余的字符串看起来非常不爽的时候,那么你也许会引发一些混乱的日志消息。
鉴于Torvalds的怀疑论,这个补丁似乎并不能适用于任何地方,即使像Molnar倡导的那样把它变为一种黑名单的方法。这个是,或者应该是相当不引人注意的,但是关于黑名单VS白名单的问题,将来我们也许会再次听到。这里有大量的例子是关于科学技术应用在安全(和其它)上下文的。这经常会归结到一个更安全(通常是指白名单)或者更实用(黑名单)的选择上来。其实,这种情况并没有什么不同的,而且其它的情况也肯定会突然发生的。
最新评论