首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

安全编程 警惕输入 找出并保护程序的入口(2)

安全编程 警惕输入 找出并保护程序的入口(2)

文件正如我在前一期文章中提到的,不要信任可以被攻击者设置的文件名。Linux 和 Unix 允许用任意的字符序列来作为文件名,所以,如果您正在使用一个来自攻击者的目录或者接受他的一个文件名,一定要有所准备。攻击者可以创建以“-”开头的文件名,或者含有“&”等特殊字符的文件名,等等。
不要信任可以被不可信用户控制的文件内容。这包括那些被程序浏览或编辑的可能是由攻击者寄来的文件。例如,著名的文本编辑器 vim 版本 5.7,当要编辑一个文件时,将查找一个内置的         statusline 命令来在它的状态行上设置信息,而那个命令又可以执行任意的 shell 程序。攻击者可以用电子邮件给受害者发送特别处理过的文件,如果受害者用 vim 来阅读或者编辑它,受害者就可能会去运行攻击者想要运行的任何程序!!!      
避免从当前目录中获得配置信息,因为用户可能会浏览一个由攻击者控制的目录,攻击者在那里创建了一个恶意的配置文件(例如,攻击者可能已经发送了一个包括数据和恶意配置文件的压缩目录)。而应该从 /etc、用户的主目录和/或桌面环境的库中获得配置信息。通常,将配置信息以及其他信息存储在“~/.        program-name”文件中是很方便的;文件名最前的句点是为了让它不影响正常的显示。如果您真正必须要从当前目录下得到配置信息,那么要非常严格地检查其中的所有数据。      
不要让攻击者控制任何临时文件。我建议,如果一个用户是可信的,那么将临时目录放在那个用户的主目录下。如果这不可接受,那么要用安全的方法来创建和使用临时文件(我将在后一期文章中讨论如何安全地创建临时文件)。
文件描述符不怀好意的攻击者可能启动一个程序而只是对它的标准输入、标准输出或者标准错误做一些奇怪的事情。例如,攻击者可能会关闭它们中的一个或多个,以使得您打开的下一个文件同时也是正常的输出位置。这对setuid/setgid 程序来说尤其是一个问题。当前的一些 Unix 类系统已经可以防范这一问题,但不是所有的系统都可以。
setuid/setgid 程序防范这一攻击的一种方法是,使用         open() 反复打开 /dev/null 直到文件描述符的值大于 2(您必须在打开文件前做这件事情,最好是在程序初始化时)。然后,如果对         open() 的第一次调用返回的是 2 或者更小,那么不输出任何消息并退出。通过先反复打开 /dev/null,您自己保护了自己 —— 如果您偶尔试图去打开文件并输出错误消息时,不会再发生坏的事情。在这种情况下不需要输出错误消息,因为文件描述符 0 到 2 只是在攻击者试图去搅乱您的程序的时候才会被关闭。      
命令行程序启动时可以接受来自命令行的数据 —— 但是您可以相信这些数据吗?setuid/setgid 程序尤其不能。如果您不能相信这些数据,那就要自己做好一切准备,包括大的参数、大量的参数、不可知的字符,等等。注意,程序的名字只是命令行值的第 0 个参数 ——         不要相信程序名,因为攻击者会改变它。      
不但如此,还要尽力去设计您的命令行语法,以使它更容易安全地使用。例如,支持用标准的“--”(双破折号)选项来表示“不再有选项”,这样脚本就可以使用这个选项来防止攻击者通过创建以破折号开头的文件名(如“-fr”)来攻击。否则,攻击者可以创建“-fr”文件,并让用户运行“yourcommand *”;这时您的程序可能会将文件名(“-fr”)曲解为一个选项。
图形用户界面(GUI)这里是应对灾难的一个方案:一个进程拥有特别的特权(例如,如果它设置了 setuid/setgid),它使用操作系统的图形用户界面(GUI)库,而且 GUI 用户不是完全可信任的。问题是,GUI 库(包括 Unix 的、Linux 的和 Windows 的)并不是设计这样使用的。这样做也不现实 —— GUI 库很大,而且依赖于庞大的基础结构,所以很难为了安全性而去分析所有的代码。GTK+ GUI 库当发现它是在 setuid 程序中运行时甚至会停止,因为它没有假定会这样使用(感谢 GTK+ 的开发者主动预防了这一安全问题)。
难道这意味着您只能使用命令行?不是。将您的程序分为小一些的部分,用没有特权的部分去实现 GUI,用单独的部分去实现需要特权的操作。下面是一些常见的做法:
  • 通常,简单的方法是将有特权的操作作为命令行程序来实现,由 GUI 调用 —— 那样您可以“无偿地”获得 GUI 和命令行界面(CLI),从而简化了脚本编写和调试。典型地,CLI 特权程序是一个 setuid/setgid 程序。当然,有特权的程序必须保护自己不受攻击,但是这个方法通常意味着这一部分必须是安全的程序,这些程序应更小并且更容易保护。
  • 如果您需要高速通信,将这个程序作为有特权的程序启动,把它分为可以安全通信的独立的进程,然后将一个进程永久释放特权并去运行 GUI。
  • 另一种方法是实现有特权的服务器来响应请求,并创建 GUI 作为客户机。
  • 使用 Web 界面;创建一个有特权的服务器,然后使用 Web 浏览器作为客户机。这实际上是先前方法的一个特例,但它很灵活,因此通常值得考虑。如任何其他为我们带来网络数据问题的Web 应用程序一样,您将需要使它安全。
网络数据        如果数据来自于网络,您应该认为它是高度不可信的。不要相信“源 IP”地址、HTTP“Referrer”头的值或者类似的数据所告诉您的数据来自何方;那些来自发送者的值可以被伪造。当心来自域名系统(DNS)的值;DNS实现的是一个分布式数据库,那些值中有一些可能是攻击者提供的。
如果您有一个客户机/服务器系统,服务器应该永远不要相信客户机。客户机数据在到达服务器前可以被操纵,客户机程序可能已经被修改,或者攻击者可能创建了他们自己的客户机(很多这种情况!)。如果您正在从 Web 浏览器获得数据,不要忘记 Web cookie、HTML 表单数据、URL 等可以被用户设置为任意的值。这是网络购物车应用程序中常见的问题;许多这样的应用程序使用隐藏的 HTML 表单域来存储产品信息(比如价格)和相关信息(比如运费),当用户发送这些值时就盲目地接收。用户不仅能将产品价格设置为更低的值或者零,有时他们还可以设置负值的价格,以得到商品和附加的现金反款。记住,必须检查        所有的数据;有一些网络购物车检查了产品数据却忘记去检查运费。      
如果您正在编写一个 Web 应用程序,查询数据时要限制使用         GET 请求。不要让         GET 请求实际上去改变数据(比如传输的钱数)或者进行其他行为。用户很容易被欺骗去点击他们Web 浏览器中恶意的超链接,这样就会发送         GET 请求。相反,如果您得到的         GET 请求有查询以外的行为,那么返回一个“you askedme to do X,is that okay? (Ok,Cancel)”格式的确认消息。注意,限制         GET 查询不能帮您解决错误的客户机数据的问题(如先前段落所讨论的) —— 服务器还是需要检查来自它们的客户机的数据!      
其他来源程序有很多其他的输入,比如当前目录、信号、内存映射、System V IPC、umask、文件系统状态。有了在这里获得的信息,重要的是不要忽略这些也可以作为输入,即使它们有时看起来不像是输入。
结束语安全的程序必须检查每一个不可信的输入通道,这样做可以避免很多问题。但是那也还不够。有时,即使只是读入数据也可以是安全漏洞 —— 甚至在数据被检查之前!处理数据可以导致程序以可怕的方式失败。我们将要讨论的是当前第1 号安全漏洞 —— 缓冲区溢出。我的下一期文章将论述这个漏洞是什么样的,如何进行防范,以及为什么可以期望它未来将不再是问题。
返回列表