最小化特权

最小化有特权的模块

如前所述,只有需要特权的部分程序才应用拥有特权。这就是说,当您设计您的程序时,尽量将程序分解为独立的部分, 以使得只有小而独立的部分需要特定的特权。

如果不同的部分必须同时运行,那么在类 UNIX 系统中使用进程(不是线程)。线程共享它们的安全特权,有问题的线程 可能会干扰进程中所有其他线程。编写有特权的部分时,就当作其它的程序正在攻击它:某一天会可能!确保有特权的部分只去 做尽可能少的事情;受限的功能意味着更不易被利用。

一个通常的方法是,创建功能极度受限的拥有特定特权(比如是 setuid 或者 setgid)命令行工具。UNIX 的 passwd 命令就是一个例子;它是一个具有特定特权的命令行工具,用于修改密码(setuid root), 但是它所能做的只是修改密码。于是各种 GUI 工具可以要求 passwd 来做实际的更改。 如果有可能,尽量完全避免创建 setuid 或 setgid 程序,因为很难确保您正在真正保护所有输入。不过,有时您需要 创建 setuid/setgid 程序,所以,当需要时,尽可能使程序最小且最受限制。

有很多其他的方法。例如,您可以有一个具有特定特权的小的“服务器(server)”进程;那个服务器只允许特定的请求, 而且只是在确认请求者被允许发出请求之后。另一个常见的方法是,使用特权启动一个程序,这个程序然后派生放弃 所有特权的第二个进程,而由这个进程来做大部分工作。

要当心这些模块彼此之间如何通信。在很多类 UNIX 系统上,命令行值和环境可以被其他用户看到,所以不是在 进程间保密地发送数据的好办法。管道可以胜任,但是要细心地避免死锁(一个两端都可以刷新的简单的请求/响应协议就可以胜任)。

 

最小化授与的特权

确保您只授与特权给确实需要的程序——到此为止。UNIX 进行获得特权的主要途径是它们以哪个用户或组的身份运行。 通常,进程以使用它们的用户和组身份运行,不过,“setuid” 或 “setgid” 的程序会获得拥有这个程序的用户或组的特权。

悲哀的是,还是有一些不自主地给予程序“setuid root”特权的类 UNIX 系统上的开发者。这些开发者认为 他们使得事情对自己来说变得“容易”,因为他们不必再去深入考虑他们的程序确切需要什么特权。问题 是,由于这些程序程序可以在大部分类 UNIX 系统上做差不多所有的事情,所以任何一个缺陷都可以很 快成为一个安全灾难。

不要只是因为您需要完成一个简单的任务就给出所有可能的特权。而应该只给予程序它们所需要的特权。 如果您可以,以 setgid 来运行它们,而不要用 setuid——setgid 给予的特权更少。创建特定的用户和组 (不要使用 root),并根据您的需要使用它们。确保 root 所拥有的那些可执行程序只能由 root 来写, 这样其他人就不能修改它们。设置非常严格的文件权限——如果不是绝对需要,不要让所有人都可以读或写文件, 并且使用那些特定的用户和组。能说明所有这些的一个例子可能是游戏“top ten”分数的标准惯例。很多程序 都是“setgid games”,以使得只有游戏程序可以修改“top ten”分数,而且存储这些分数的文件的主人是 games 组 (而且只有这个组可以写)。即使攻击者攻击并进入了一个游戏程序,所有他能做的事情将是修改分数文件。 无论如何,游戏开发者还是需要编写他们的程序来防止恶意的分数文件。

chroot() 系统调用是一个实用的工具——不幸的是有一些难用。当进程查看文件系统的 “root”时,这个系统调用会修改进程所看到的内容。如果您计划用它——而且它可能是实用的——要准备好花一些时间来 用好它。必须精心准备 “new root”,这是复杂的,因为确切的应用程序依赖于平台和应用程序的特性。您 必须 以 root 身份来进行 chroot() 调用,而且您 应该快速地 改变为 非 root 身份(root 用户可以脱离 chroot 环境,所以如果它要生效,您需要解除那个 特权)。而且 chroot 不会改变网络访问。这可以是一个实用的系统调用,所有有时候 需要考虑它,但是要做好付出努力的准备。

限制资源是一个经常被遗忘的工具,这既包括存储的资源也包括进程的资源。这些限制拒绝服务攻击尤其有用:

  • 对存储来说,您可以为每个用户或组设置每个挂载的文件系统的存储量或文件数的配额(限定)。在 GNU/Linux 系统中 查看 quota(1)、quotactl(2) 和 quotaon(8) 来深入了解这一功能,不过,尽管它们不是哪里都能用,大部分类 UNIX 系统都包含了 quota 系统。在 GNU/Linux 和很多其他系统中,您可以设置“硬”界限(永远不能超出)和“软”界限(可以 临时超出)。
  • 对进程来说,您可以设置很多限定,比如打开文件的数目、进程的数目,等等。这种能力实际上是标准的一部分(比如单一 UNIX 规范(Single UNIX Specification)),所有它们在类 UNIX 系统上几乎普遍存在;要深入了解,请查看 getrlimit(2)、 setrlimit(2) 以及 getrusage(2)、sysconf(3) 和 ulimit(1)。进程永远不能超出“当前界限”,但是它们可以将当前界限 一路上升到“上限”。不幸的是,这里有一个不合常理的术语问题可能会使您迷惑。“当前界限”也被称为“软”界限,上限也称为 “硬”界限。这样,您就会处在一个异乎寻常的情形,进程 永远不能超出进程界限的软(当前)界限——而对于 quota 来说 您 可以 超出软界限。我建议为进程界限使用术语“当前界限”和“上限”(永远不要使用术语“软”和“硬”),那样就 没有任何迷惑了。
 

最小化特权的时间

只是当需要的时候才给予特权——片刻也不要多给。

只要可能,使用无论什么您立即需要的特权,然后 永久地 放弃它们。一旦它们被永久放弃,后来的攻击者 就不能以其他方式利用那些特权。例如,需要个别的 root 特权的程序可能以 root 身份启动(比如说,通过成为 setuid root)然后切换到以较少特权用户身份运行。这是很多 Internet 服务器(包括 Apache Web 服务器)所采用 的方法。类 UNIX 系统不允许任何程序打开 0 到 1024 TCP/IP 端口;您必须拥有 root 特权。但是大部分服务器只是 在启动的时候需要打开端口,以后就再也不需要特权了。一个方法是以 root 身份运行,尽可能快地打开需要特权的端 口,然后永久去除 root 特权(包括进程所属的任何有特权的组)。也要尝试去除所有其他继承而来的特权;例如,尽快关 闭需要特定的特权才能打开的文件。

如果您不能永久地放弃特权,那么您至少可以尽可能经常临时去除特权。这不如永久地去除特权好,因为如果攻击者可 以控制您的程序,攻击者就可以重新启用特权并利用它。尽管如此,还是值得去做。很多攻击只有在它们欺骗有特 权的程序做一些计划外的事情而且程序的特权被启用时才会成功(例如,通过创建不合常理的符号链接和硬链接)。 如果程序通常不启用它的特权,那么攻击者想利用这个程序就会更困难。

原文地址:https://www.cnblogs.com/tswcypy/p/4560869.html