站内搜索

安全编程 HOWTO:文件

文件
对于所有类Unix系统,最主要的信息存放地点是根为“/”的文件树。文件树是一个目录的分级结构,每个目录都可以保护文件系统对象(FSO)。

在Linux中,文件系统对象(FSO)可以是普通文件、目录、符号连接、命名管道(FIFO)、套接字(参见下文说明)、特殊字符(设备)文件或特殊块(设备)文件(在Linux下可以用find(1)命令显示其列表)。其它类Unix系统有同样或相似的一组FSO类型。

文件系统对象由文件系统收集,可以在文件树的目录下安装和卸载。文件系统的类型(如ext2和FAT)是一组管理磁盘上数据以优化速度、可靠性等等的特殊规范集;很多人用“文件系统”作为文件系统类型的同义词。

文件系统对象的属性
不同的类Unix系统支持不同的文件系统类型。文件系统的访问控制属性可以稍有区别,在安装时选择的选项也会影响访问控制。在Linux下,ext2文件系统是目前最常用的文件系统,但Linux还支持大量的文件系统。绝大多数类Unix系统也都支持多个文件系统。

类Unix系统上的绝大多数文件系统至少都包含以下内容:


拥有UID和GID -- 标识文件系统对象的“所有者”。除非另加说明,只有所有者或root可以改变存取控制属性。

许可比特位 -- 每个用户(所有者)、群组及其他人的读、写和执行比特位。对于一般文件,读、写和执行就是相应的典型意义。对于目录,显示目录下内容需要“读”许可,而在实际进入目录以使用其内容时需要的“执行”许可有时被称为“查找”许可。一个目录的“写”许可是允许在目录内对文件进行增加、移动和改名操作;如果只想允许增加文件,设置下面说明的“sticky”比特位。注意,符号连接的许可值没有用;其对应的目录和连接文件的许可值才是真正有效的。

“sticky”比特位 -- 在目录被设置之后,只有root、文件所有者或目录所有者才能在该目录下解除连接(删除)和改变文件名。这是一个很常用的Unix扩展,在Open Group的单一Unix规格版本2中有其定义。老版本的Unix把它叫做“保存程序正文”比特位,并用它来标明需要保留在内存的可执行文件。系统这样做确保了只有root可以设置此比特位。(否则用户可以强制“所有内容”都保存在内存中来使系统崩溃)。在Linux下该比特位对普通文件没有影响,而且普通用户可以修改所拥有文件的该比特位;Linux的虚拟内存管理使这种老用途不再重要。

setuid, setgid -- 在对可执行文件设置后,执行该文件会(相应地)把进程的有效UID或有效GID设为文件拥有UID或GID。所有的类Unix系统都支持这一点。在Linux和System V系统中,在对没有执行权限的文件设置了setgid时,该文件在存取时将被强制锁定(如果安装的文件系统支持强制锁定的话);这种意义重载使很多人诧异,而且在类Unix系统中并不常见。事实上,如果这样的设置没有意义,在Open Group的单一Unix规格版本2中chmod(3)将允许系统忽略打开不可执行文件setgid的请求。在Linux和Solaris中,对目录设置setgid时,该目录下创建的文件会自动把自己的GID设置为目录的GID。这样做的目的是支持“工程目录”:用户可以把文件保存在如此特别设定的目录下,文件的群组所有者就自动改变。但是,对目录设置setgid比特位没有被单一Unix规格[Open Group 1997]之类的标准所定义。

时间戳 -- 保存每个文件系统对象存取和修改的时间。尽管如此,文件系统对象的所有者可以任意设置这些值(参见touch(1)),所以在信任该信息时要小心。所有的类Unix系统都支持这一点。


下面是对ext2文件系统inux独有的属性,虽然很多其它文件系统也有类似的功能:


不可改变的比特位 -- 不允许改变文件系统对象;只有root可以设置或清除该比特位。只有ext2支持它,不能在所有Unix系统中移植(甚至不能在所有Linux文件系统中移植)。

只附加比特位 -- 只允许对文件系统对象进行附加操作;只有root可以设置或清除该比特位。只有ext2支持它,不能在所有Unix系统中移植(甚至不能在所有Linux文件系统中移植)。


其它的常见扩展包括表明“不可删除此文件”的某种比特位。

很多这样的值在安装时会受影响,所以,诸如特定的比特位可以被当做具有某个特定值(无论在媒介上它们的值如何)来处理。参见mount(1)以了解更多的有关信息。有些文件系统不支持其中的某些存取控制值;也可参见mount(1)以了解这些文件系统是如何进行处理的。比较特别的是,很多类Unix系统支持MS-DOS磁盘,其缺省状态只支持其中的很少属性(而且没有标准方法来定义这些属性)。在这种情况下,类Unix系统仿效标准属性(可能通过特殊的磁盘文件来实现),而且这些属性一般会受mount(1)命令影响。

需要特别注意,除非类Unix系统支持更为复杂的规范(如POSIX的ACL),对于增加和移动文件,只有许可比特位和文件所在目录的拥有者确实有意义。除非系统有其它的扩展,而标准Linux 2.2没有扩展,如果所在目录允许,没有被许可比特位授予许可的文件还是可以被移开的。同样,如果上级目录允许其子目录被某些用户或群组改变,那么该目录的下级目录就可以被那些用户或群组更换。

IEEE有关安全的POSIX标准草案为支持用户和群组许可列表的真实ACL定义了一项技术。不幸的是这并未得到类Unix系统的广泛支持,而且类Unix系统支持的方式也不完全一样。例如,标准的Linux 2.2在文件系统中既没有ACL,也没有POSIX能力值。

Linux中的ext2文件系统缺省为root用户保留少量空间,这在Linux下算不了什么。这可以部分抵御拒绝服务攻击;即使某个用户占完了与root用户共享的磁盘,root用户还剩下少量空间(如用于关键函数)。该缺省值为文件系统空间的5%;参见mke2fs(8),特别是其中的“-m”选项。

创建时的初始值
在创建时,应用以下规则。在绝大多数Unix系统中,通过creat(2)或open(2)来创建一个新的文件系统对象(FSO)时,FSO的UID被设为进程的EUID,而FSO的GID被设为进程的EGID。Linux由于存在FSUID和setgid目录扩展,与此稍有区别;FSO的UID被设为进程的FSUID,而FSO的GID被设为进程的FSGID;如果所在目录的setgid比特位被设置,或者文件系统的“GRPID”标志被设置,FSO的GID实际上被设为所在目录的GID。这一特性支持“工程”目录:生成一个“工程”目录,为该工程创建一个特殊的群组,为该群组所拥有的工程创建一个目录,然后使该目录成为setgid:放入该目录下的文件自动被该工程所拥有。类似的,如果一个新的子目录创建在设置了setgid比特位(而文件系统的GRPID没有设置)的目录下,新的子目录的setgid比特位也被设置(这样工程的子目录也“工作正常”);在其它情况下,新文件的setgid被清除。FSO的基本存取控制值(读、写、执行)是计算得来的(请求值& ~进程的umask)。新文件开始总是具有一个清除了的sticky比特位和一个清除了的setuid比特位。

改变存取控制属性
可以用chmod(2)、fchmod(2)或chmod(1)来设置大多数这样的值,但请参考chown(1)和chgrp(1)。在Linux下,有些Linux独有的属性用chattr(1)来操作。

注意,在Linux下只有root可以改变一个给定文件的所有者。某些类Unix系统允许普通用户把自己文件的所有关系传递给其他人,但这使情况复杂化,在Linux中是禁止的。例如,如果要限制磁盘的使用,允许这样的操作就允许用户宣称大文件实际上属于某些其他的“受害者”。

使用存取控制属性
在Linux和大多数类Unix系统下,只有在打开文件时检查读和写属性的值;在每次读或写操作时不再检查这些值。因为文件系统是类Unix系统的中心,还有很多调用会检查这些属性。检查这些属性的调用包括open(2)、creat(2)、link(2)、unlink(2)、rename(2)、mknod(2)、symlink(2)和socket(2)。

文件系统分级结构
这些年来一直是在“什么文件放在哪里”的基础之上建立规则的。如果可能,请依照这些规则把信息放进分级结构里。例如,把全局配置信息放入/etc。文件系统分级结构标准(FHS)试图以一种合乎逻辑的方式定义这些规则,而且在Linux上得到了广泛应用。FHS是以前Linux的文件系统结构标准(FSSTND)的更新版本,包含了从Linux、BSD和System V等系统上得到的教训与实践。参见 http://www.pathname.com/fhs 以了解有关FHS的更多信息。有关这些规则的概要在Linux的hier(5)和Solaris的hier(7)中。有时,不同的规则相互冲突;如果可能,使这些情况在编译或安装时可以配置。

 

  • 上一篇:C语言安全特性概要:进程部分
  • 下一篇:内 存 问 题