我们口中的操作系统,一般指的是:一个操作系统核心+各种扩展应用程序。但从专业的角度来讲,操作系统就是那个核心(通常称之为内核),就是将底层硬件进行抽象和虚拟化,并向使用者提供各种功能接口的软件程序。这是一种非常特殊的软件程序,它的特殊之处就在于:操作系统是使用者运行其他应用程序的底层软件基础,也是硬件功能被集中管理和调用的统一接口。它向上层隐藏了硬件结构的丑陋和不易操作,使得使用者在使用计算机时变得更加简单;向下层屏蔽了底层硬件无法理解的使用者发出的复杂指令,将其翻译成二进制序列,使得硬件可以更加快捷的予以执行。

Linux内核,从它诞生的那天开始,变表现出极强的生命力,源自于UNIX的很多的哲学思想被沿用在Linux中。一切皆文件!多么简单但却又复杂的一句话。说它简单,是因为对于用户来讲,每一个系统的资源,包括各种硬件(磁盘、内存、网络等)和软件都是以一种可访问甚至是可编辑可修改的文件的方式来展现,用户不必再去思考底层的技术了;说它复杂,是因为这种抽象和虚拟是在大量的驱动程序和数以百计的接口函数的支撑下得以完成的。

在这样的一套系统中,使用者可以用自己掌握的自然语言向计算机发号施令,而计算机也会非常忠诚地予以执行,无论成功与否。这种简化给使用者带来了极大的便利,但也同时会给计算机带来很多的安全问题。比如说:谁能在什么时间对什么文件进行什么操作?结果如何,成功还是失败?如果成功会有怎样的影响?如果失败,是否会予以记录?……等等。

 安全秘笈第一式——自主访问控制(DAC

要知道,在操作系统出现之初,是没有用户的概念的,那个时候每个使用者都会在获得计算机使用权时,将自己所携带的键盘及显示器等设备连接到计算机所提供的某个接口上,这些设备被统一的称为“终端设备”。只要使用者将这些设备接入,即可使用计算机的各种资源。而且计算机的资源是公共的,不属于任何人的。一开始,资源充足,大家相安无事;但是随着使用者数量的增加,资源却没有本质的变化,从而必然会导致资源危机。这个时候,就会出现资源竞争的问题了。每个人都企图占用更多的CPU计算时间,占用更多的内存空间,设置后来磁盘存储介质发明之后,这样的外部存储空间也成为竞争极为激烈的一种资源。甚至到了后来,这种竞争变得极其的残酷。那么,会不会有某些使用者在不经其他使用者同意的情况下,将其他使用者的数据修改或删除,或者将其他使用者正在运行的程序强行终止呢?因为通过这种方式可以很直接的获取到很多的可用资源。而在整个过程中,操作者是这个操作的主体,即使其操作不当也不会有任何的惩罚,全靠其自身的道德规范来约束,但有时这种约束显得螳臂挡车,毫无力度可言。操作系统的开发和维护人员很显然想到了这个问题,所以,为了防止这样的恶性事件的发生,他们在操作系统中给每个用户定义了一个身份,只有使用以这个身份来接受系统的认证,已确定使用者的合法性。在文件系统出现之后,定义了使用者所对应的用户身份对于各种资源的访问权限,只有满足权限要求才能继续使用计算机的资源。于是这样一来,用户能否完成某个操作,不取决于使用者本身是怎么样的社会角色,而是使用者在计算机中的身份映射——用户,能不能完成对资源的访问以及后续的如删除、修改等操作。后来我们把这种资源管理的机制称为自主访问控制(DACDiscretionary Access Control)。那么,什么是DAC呢?

DAC主要的内容包括以下几个概念:主体、客体、权限(rwx)、所有权(ugo)。

在这个模型中,主体是用户的身份,客体是资源或者说是文件(切记:一切皆文件)。由客体的属主对自己的客体进行管理,由主体自己决定是否将自己的客体访问权限或部分访问权限授予其他主体,这种控制方式是自主的。也就是说,在自主访问控制下,用户可以按自己的意愿,有选择地与其他用户共享他的文件。

DAC是一种相对比较宽松但是却很有效的保护资源不被非法访问和使用的手段。说它宽松,是因为他是自主控制的,在保护资源的时候是以个人意志为转移的;说它有效,是因为可以明确的显式的指出主体在访问或使用某个客体时究竟是以何种权限来实施的,任何超越规定权限的访问行为都会被访问控制列表判定后而被阻止。

接下来我们来看看DAC到底是怎么工作的。但是,我们需要了解一个前提,我们需要知道这样的一个问题:在访问客体资源的时候,并不是使用者进入到计算机中,以主体的身份来完成这样的访问工作。每当我们需要使用计算机系统资源的时候,我们都需要去打开一个应用程序,在操作系统中,我们可以把这样的已经被启动并加载至内存中的应用程序称为进程。但是,不管是应用程序还是要访问的文件资源,都是存储在外部存储设备中的数据,想要定位和查找他们,就必须依靠文件系统才能实现。这个时候,文件系统所规定的权限就会生效了。

因此,我们所定义的DAC系统有两个至关重要的标准:

  1.文件的所有权:系统中的每个文件(一些特殊文件可能没有,如块设备文件等)都有所有者。在DAC系统中,文件的所有者是创建这个文件的计算机的使用者(或事件,或另一个文件)。那么此文件的自主访问控制权限由它的创建者来决定如何设置和分配;

  2.访问权限:文件的所有者拥有访问权限,并且可以将访问权限分配给自己及其他用户。

  上述两个标准说明:

  1.文件的所有权的优先级高于访问权限

   1)文件的所有者即便没有任何权限,也可以在为自己分配权限之后获得访问文件的能力。

   2)非文件的所有者即便已经获得了访问权限,也可能会被所有者随时收回,从而导致无权访问该文件。

 2.权限是文件访问的关键

   1)无论是不是文件的所有者,关系到使用者能否访问文件的最直接的因素是其所对应的用户是否获得了可访问该文件的权限

   2)使用者被分配的何种权限,就只能以该权限所规定的操作来访问文件,无法越权。

那么所有权和权限是如何规定和标识的呢?

  Linux所支持的默认的文件系统(早期的是ext系列,后来是xfs)中,所有权被分成三类,即:文件的拥有者,文件的所属组,其他人

  1.文件的拥有者:也称为属主,标记为u,默认情况下,创建文件的用户就是其属主;

  2.文件的所属组:也称为属组,标记为g,除了属主之外,还可以被哪些用户共同拥有。由于这样的用户可能不止一个,所以不方便用某个用户名来标识,因此以组的方式来标识。

  3.其他人:标记为o,除了文件的属主和属组之外的其他所有使用者的统称。

  在在Linux所支持的默认的文件系统(早期的是ext系列,后来是xfs)中,权限被分成三种,即:读权限,写权限,执行权限

  1.读权限:

   1)对于目录来说,拥有读权限的用户可以浏览该目录中的文件名;如果同时拥有执行权限,则该用户可以查看目录的元数据,目录中的文件名及这些文件的元数据信息。

   2)对于非目录文件来说,拥有读权限的用户在对存放该文件的目录有读权限和执行权限的前提下可以查看该文件的内容。

  2.写权限:

   1)对于目录来说,拥有写权限的用户必须要同时拥有执行权限,才可以在该目录中新建、修改和删除文件名

   2)对于非目录文件来说,拥有写权限的用户在对存放该文件的目录有读权限和执行权限的前提下可以在该文件的末尾追加内容;如果想要修改和删除该文件内容,必须同时拥有读权限

  3.执行权限:

   1)对于目录来说,执行权限是最最基本的权限了。拥有执行权限的用户可以在路径表示中引用此目录,并且如果该用户同时拥有读权限,便可以进入到此目录中,可以查看目录的元数据。

   2)对于非目录的文件来说,拥有执行权限的用户可以将此文件当作命令来执行,也就是说可以把这个文件直接载入内存,让其运行起来成为进程或者通过其他的解释工具将他里面保存的命令、语句解释出来并执行。在ext系列和xfs文件系统中,对于非目录文件的执行权限限制还是非常大的。除非用户明确为之分配,否则系统绝不会为这些非目录文件添加执行权限的。

  请看下面的例子:

[root@localhost ~]# mkdir /test
[root@localhost ~]# chmod 744 /test
[root@localhost ~]# echo "I amroot" > /test/a.txt

root用户的身份在根目录下创建名为test的目录,将其权限设置为744,并在目录中创建名为a.txt的空文件,查看其权限如下:

[root@localhost ~]# ls -ld /test
drwxr--r-- 2 root root 18 Jun 15 17:14/test
[root@localhost ~]# ls -l /test
total 0
-rw-r--r-- 1 root root 0 Jun 15 16:53 a.txt

下面换用一个非root组的普通用户zhao来进行测试(注意/test目录的其他人位置没有执行权限):

[zhao@localhost ~]$ ls /test
ls: cannot access /test/a.txt: Permissiondenied
a.txt
[zhao@localhost ~]$ stat /test
 File: ‘/test’
 Size: 18                 Blocks: 0          IO Block: 4096   directory
Device: 802h/2050d         Inode: 550        Links: 2
Access: (0744/drwxr--r--)  Uid: (   0/    root)   Gid: (   0/    root)
Access: 2016-07-02 16:23:04.786001145 +0800
Modify: 2016-07-02 16:23:17.265001996 +0800
Change: 2016-07-02 16:23:17.265001996 +0800
 Birth: -
[zhao@localhost ~]$ ls /test/a.txt
ls: cannot access /test/a.txt: Permission denied
[zhao@localhost ~]$ stat /test/a.txt
stat: cannot stat ‘/test/a.txt’: Permissiondenied
[zhao@localhost ~]$ ls -l /test
ls: cannot access /test/a.txt: Permissiondenied
total 0
?????????? ? ? ? ?            ? a.txt

之所以会有这样的结果,完全和/test目录上对其他人没有执行权限有关。如果加上执行权限,其结果为:

[root@localhost ~]# chmod 745 /test
[root@localhost ~]# su - zhao
Last login: Wed Jun 15 17:17:19 CST 2016 onpts/0
[zhao@localhost ~]$ ls /test
a.txt
[zhao@localhost ~]$ ls -l /test
total 0
-rw-r--r-- 1 root root 0 Jun 15 16:53 a.txt
[zhao@localhost ~]$ stat /test
 File: ‘/test’
 Size: 18                 Blocks: 0          IO Block: 4096   directory
Device: 802h/2050d         Inode: 550        Links: 2
Access: (0745/drwxr--r-x)  Uid: (   0/    root)   Gid: (   0/    root)
Access: 2016-07-02 16:23:04.786001145 +0800
Modify: 2016-07-02 16:23:17.265001996 +0800
Change: 2016-07-02 16:24:16.761006056 +0800
 Birth:-
[zhao@localhost ~]$ stat /test/a.txt
 File: ‘/test/a.txt’
 Size: 0                  Blocks: 0          IO Block: 4096   regular empty file
Device: 802h/2050d         Inode: 34455      Links: 1
Access: (0644/-rw-r--r--)  Uid: (   0/    root)   Gid: (   0/    root)
Access: 2016-07-02 16:23:17.265001996 +0800
Modify: 2016-07-02 16:23:17.265001996 +0800
Change: 2016-07-02 16:23:17.265001996 +0800
 Birth: -

这样设置以后,就不会再有错误报告了。

 

  同样的,我们再来一组实验:

[root@localhost ~]# chmod 752 /test
[root@localhost ~]# su - zhao
Last login: Sat Jul  2 16:24:18 CST 2016 on pts/0
[zhao@localhost ~]$ > /test/zhao.txt
-bash: /test/zhao.txt: Permission denied

按照大家的理解,只有有写权限就能创建文件的,但是事实确是这样的。原因很简单,/test目录上对其他人没有执行权限,因此/test目录的文件名就不能被zhao用户在使用路径时引用。即使有写权限,又能怎样!

[root@localhost ~]# chmod 753 /test
[root@localhost ~]# su - zhao
Last login: Sat Jul  2 16:31:02 CST 2016 on pts/0
[zhao@localhost ~]$ > /test/zhao.txt

  在其他人的权限位上增加了执行权限之后,结果成功了,原因如上。我们继续实验:

[zhao@localhost ~]$ ls /test
ls: cannot open directory /test: Permissiondenied
[zhao@localhost ~]$ stat /test
 File: ‘/test’
 Size: 33                 Blocks: 0          IO Block: 4096   directory
Device: 802h/2050d         Inode: 550        Links: 2
Access: (0753/drwxr-x-wx)  Uid: (   0/    root)   Gid: (   0/    root)
Access: 2016-07-02 16:23:04.786001145 +0800
Modify: 2016-07-02 16:32:24.216039314 +0800
Change: 2016-07-02 16:32:24.216039314 +0800
 Birth: -

有趣的事情来了,我们无法看到/test目录中的内容,但是却能看到它的元数据哦。下面还有其他有趣的事情:

[zhao@localhost ~]$ ls /test
ls: cannot open directory /test: Permissiondenied
[zhao@localhost ~]$ ls -l /test
ls: cannot open directory /test: Permissiondenied
[zhao@localhost ~]$ echo zhao >/test/zhao.txt
[zhao@localhost ~]$ cat /test/zhao.txt
zhao
[zhao@localhost ~]$ ls -l /test/zhao.txt
-rw-r--r-- 1 zhao zhao 5 Jul  2 16:34 /test/zhao.txt
[zhao@localhost ~]$ stat /test/zhao.txt
 File: ‘/test/zhao.txt’
 Size: 5                  Blocks: 8          IO Block: 4096   regular file
Device: 802h/2050d         Inode: 11282      Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/    zhao)  Gid: ( 1000/ zhao)
Access: 2016-07-02 16:32:24.216039314 +0800
Modify: 2016-07-02 16:34:42.186048728 +0800
Change: 2016-07-02 16:34:42.186048728 +0800
 Birth: -

对目录没有读权限,所以无法看到其中的文件名;但是可以看到其中zhao用户自己创建的文件的中写入数据,并且能够查看其内容及元数据。

 

相信看了这些例子以后,大家应该可以明白一点这些权限的在文件系统中的作用了。那我们接下来继续。

[root@localhost ~]# chmod 756 /test
[root@localhost ~]# ls -ld /test
drwxr-xrw- 2 root root 33 Jul  2 16:32 /test
[root@localhost ~]# su - zhao
Last login: Sat Jul  2 16:32:22 CST 2016 on pts/0
[zhao@localhost ~]$ cd /test
-bash: cd: /test: Permission denied
[zhao@localhost ~]$ ls -l /test
ls: cannot access /test/a.txt: Permissiondenied
ls: cannot access /test/zhao.txt:Permission denied
total 0
?????????? ? ? ? ?            ? a.txt
?????????? ? ? ? ?            ? zhao.txt
[zhao@localhost ~]$ rm -f /test/zhao.txt
rm: cannot remove ‘/test/zhao.txt’:Permission denied
[zhao@localhost ~]$ > /test/zhao2.txt
-bash: /test/zhao2.txt: Permission denied

  看到了么?其他人的位置上除了一个执行权限,其他都有了,然而,结果是无法查看文件的一般属性,无法删除目录中已有的文件,也无法在其中创建新的文件。诚然,拥有写权限的用户确实能够完成文件名的创建、删除、和修改,但用户既不能进入到目录中,也不允许在书写路径时引用这个目录名称,因此即便你有写权限又当如何。

  总的来说,执行权限是目录的最基本权限,所以,大家在ext系列或者xfs文件系统中创建出来的新目录,一般都会有执行权限的。大多数都是755的权限,有些是700的权限,但不管如何,确保目录的权限中有执行权限是访问目录和使用目录的基础。

  接下来,我们继续说权限。假设有一个目录的权限被设置为:

[root@localhost ~]# chmod 777 /test
[root@localhost ~]# ls -ld /test
drwxrwxrwx 3 root root 44 Jul  2 17:00 /test
[root@localhost ~]# ls -l /test
total 8
-rw-r--r-- 1 root root 10 Jul  2 17:00 a.txt
drwxr-xr-x 2 root root  6 Jul 2 17:00 root
-rw-r--r-- 1 zhao zhao  5 Jul 2 16:34 zhao.txt

小伙伴们对这样的权限设置作何感想呢?

请大家思考一个问题:作为一个普通的用户wang来讲,能不能在a.txt文件中添加内容?能不能把a.txt的内容清空或者酌情添加些内容呢?答案就是看情况咯。

请大家再思考要给问题:作为一个普通的用户wang来讲,能不能把a.txt这个文件名给删除了?能不能把a.txt这个文件的名字改为wang.txt?先别着急回答,仔细想一想再说。好了,现在公布答案,那就是:当然可以。

如下例子所示:

[wang@localhost ~]$ echo wang >/test/a.txt
-bash: /test/a.txt: Permission denied
[wang@localhost ~]$ vim /test/a.txt
I am root
~
~
~
~
~
"/test/a.txt" [readonly] 1L, 10C

  请注意扩展编辑模式(有人称之为末行模式,我以前也这么叫)中显示的“readonly”,明确的告诉你那是只读的。如果你很任性的进入了插入模式则会有这样的信息:

I am root
~
~
~
~
~
-- INSERT -- W10: Warning: Changing areadonly file

当然,接下来你仍然可以很任性的去修改,只是在你保存的时候,回事这样的提示:

I am wang
~
~
~
~
~
E45: 'readonly' option is set (add ! tooverride)

  而事实上,如果你在保存的时候缀加了“!”以表示你要强制保存的决心,那么操作的最终结果是:成功!这个操作大家可以自行测试。

我们再来试试改名和删除文件的操作:

[wang@localhost ~]$ mv /test/a.txt/test/wang.txt
[wang@localhost ~]$ ls -l /test
total 8
drwxr-xr-x 2 root root  6 Jul 2 17:00 root
-rw-r--r-- 1 wang wang 10 Jul  2 17:24 wang.txt
-rw-r--r-- 1 zhao zhao  5 Jul 2 16:34 zhao.txt
[wang@localhost ~]$ rm -rf /test/root
[wang@localhost ~]$ ls -l /test
total 8
-rw-r--r-- 1 wang wang 10 Jul  2 17:24 wang.txt
-rw-r--r-- 1 zhao zhao  5 Jul 2 16:34 zhao.txt

  看起来非常的顺利就完成了。即便是root用户创建的目录和文件,说改就改,说删就删,完全不去理会root受得了受不了。

  以上的操作能够成功,说明对其他人来讲,在目录上有rwx的权限还是非常危险的,所以大家切记,目录上的权限默认就是除了属主之外的权限保持为r-x就好,如果再此基础上增加了w权限,会带来很多莫名其妙的结果,徒增烦恼啊。

  为了免除这样的烦恼,我们有提出了很多的补救措施。比如,给其他人的权限位上加上一个粘滞位“t”,那么每个用户就只能修改和删除那些属主为自己的文件了,甚至连刚刚的强制保存都无法做到了。至于其他的两个特殊权限SUIDSGID,相信大家也能够搞明白了,那个并不复杂。

然而,在众多的主体中,有一个主体是个例外,他就是大名鼎鼎的root,作为系统管理员,可以凌驾于DAC之上。它是唯一一个不受DAC权限控制的用户。看下面的例子:

[root@localhost ~]# chmod -R 000 /test
[root@localhost ~]# mkdir /test/root
[root@localhost ~]# echo "I amroot" > /test/a.txt
[root@localhost ~]# ls -l /test
total 4
---------- 1 root root 10 Jul  2 17:00 a.txt
drwxr-xr-x 2 root root  6 Jul 2 17:00 root
---------- 1 zhao zhao  5 Jul 2 16:34 zhao.txt

  看到了吧,这个就是无敌的root,强大的root。以至于被大家认为它就是系统中的神一样的存在!所以一大波有计划有组织的破解root的行动就此展开。如果成功,瞬间封王;如果不成,那就继续呗。

  我们举一个例子来说明一下:

  假如我们在传统的DAC的控制模式下,使用普通用户zhao登录到系统,以这样的普通用户的身份想要使用下面的命令来创建一个文件

[zhao@localhost ~]$ id
uid=1000(zhao)  gid=1000(zhao)  groups=1000(zhao)
[zhao@localhost ~]$ mkdir /test/test

  那么请大家思考一下,这样的操作是如何完成的呢?使用者进入到计算机中亲自完成的么?显然不可能是。使用者仅仅是完成了这个命令中的字符串的键入而已。剩下的就是等待结果罢了。

  那么这个创建目录的过程到底是怎么完成的呢?

  首先,shell将命令行展开,根据空白字符,将整行分割成单个字,识别出mkdir并欲将其作为命令来处理;接下来就是判断这个命令是shell内置的命令还是外部命令了。

[zhao@localhost ~]$ type mkdir
mkdir is /bin/mkdir
[zhao@localhost ~]$ ls -l /bin/mkdir
-rwxr-xr-x. 1 root root 79720 Nov 20  2015 /bin/mkdir

  经过判断,mkdir并非内置命令,于是通过在用户登录时定义好的PATH变量来定位mkdir命令所对应的二进制文件的路径,而后需要在外部存储器上找到并尝试将以mkdir为名的可执行的二进制文件启动为进程。在真正的执行该文件之前,文件系统会参照/bin/mkdir文件的访问权限来判断zhao用户是否有启动执行此文件的权限。幸运的是在该文件的其他人的权限位上,明显有一个执行权限,而对于这个文件来讲,zhao用户也属于其他人的范围。但这没关系,因为zhao用户已经具备了启动mkdir进程的基本条件,于是文件/bin/mkdir被加载到内存中,系统进一步将mkdir进程的属主和数组标识为zhao用户及zhao用户的主要组zhao组。

  然后,由mkdir进程继续后面的工作。依靠内核中的文件系统,在指定的路径(也就是/test目录)中查找是否有一个名为test的目录文件,如果已经存在,mkdir进程报告错误并退出执行;如果不存在,再检查/test目录的权限设置,查看zhao用户在此目录中是否具有写权限和执行权限,如下所示:

[zhao@localhost ~]$ ls -ld /test
drwxr-xr-x 2 root root 6 Jun 15 14:52 /test

  从该目录的权限设定来看,属于其他认的zhao用户是不具有写操作的权限的,因此zhao用户不管使用哪个进程发起的写操作,都会被拒绝。

[zhao@localhost ~]$ touch /test/zhao
touch: cannot touch ‘/test/zhao’:Permission denied

  如果想要zhao用户可以创建这个目录文件,必须给予zhao用户对目录/test的写权限和执行权限,可以修改其他人位置的权限,也可以实用facl单独为zhao用户设置权限。

  方案一:

[root@localhost ~]# chmod 757 /test
[root@localhost ~]# ls -ld /test
drwxr-xrwx 2 root root 6 Jun 15 14:52 /test

  方案二:

[root@localhost ~]# getfacl /test
getfacl: Removing leading '/' from absolutepath names
# file: test
# owner: root
# group: root
user::rwx
user:zhao:rwx
group::r-x
mask::rwx
other::r-x

  这样就可以让zhao用户获得在此目录中创建、修改、删除文件名等写操作了,并且在创建该目录的同时设置这个目录文件的所有权和访问权限。所有权的设定很简单,创建这个目录文件的用户账户zhao即为此目录文件的属主;创建这个目录文件的用户账户zhao的基本组zhao即为此目录文件的属组。访问权限的设定要根据系统中设置的umask(权限遮罩码)进行设定即可,即:从rwx的权限中删除在umask中明确排除的权限。

DAC的内容就写这么多吧。


待续……