维护一个完全安全的系统是不可能的。然而,只要勤奋,则有可能使 Linux 机器足够安全,并让大多数偶尔出现的骇客、脚本小子(script- kiddies)以及其它的“坏家伙”止步而去骚扰其他人。请记住:仅仅遵循本教程不会产生一个安全的系统。相反,我们希望您接触到主要主题的多个方面,并向您提供一些有关如何入门的有用示例。
Linux 系统安全性可分为两个部分:内部安全性和外部安全性。内部安全性指预防用户无意或恶意地破坏系统。外部安全性指防止未授权用户获得对系统的访问。
本章将首先介绍内部安全性,然后介绍外部安全性,最后介绍一些常规指导原则和技巧。
日志文件的文件权限
内部安全性可以是很大的任务,这要看您对用户的信任程度。这里介绍的指导原则是设计用来防止偶然用户访问敏感信息和防止不公平地使用系统资源。
至于文件权限,您可能希望修改以下三种情况的权限:
首先,/var/log 中的日志文件不需要是所有人都可以读取的。没有理由让非 root 用户窥视日志。为了创建具有适当权限的日志。
root 用户其它文件的文件权限
其次,root 用户的点文件对于普通用户应是不可读的。检查 root 用户主目录中的文件(ls -la)以确保它们受到适当的保护。甚至可以使整个目录仅对 root 用户可读:
# cd
# pwd
/root
# chmod 700 .
用户文件的文件权限
最后,用户文件在缺省情况下通常被创建为所有人可读。那可能不是用户所期望的,而且它当然不是最好的策略。应该使用与下面类似的命令在 /etc/profile 中设置缺省的 umask:
if [ "$UID" = 0 ]; then
# root user; set world-readable by default so that
# installed files can be read by normal users.
umask 022
else
# make user files secure unless they explicitly open them
# for reading by other users
umask 077
fi
应该查询 umask(2) 和 bash(1) 手册页以获取有关设置 umask 的更多信息。请注意:umask(2) 手册页涉及 C 函数,但它所包含的信息也适用于 bash 命令。
查找 SUID/SGID 程序
寻求 root 访问权的恶意用户总是会在系统上寻找设置了 SUID 或 SGID 位的程序。就象我们在 LPI 101 系列第 3 部分中讨论的那样,这些位使程序始终作为拥有该文件的用户或组运行。有时这是程序正确运行所必需的。问题是任何程序都可能包含允许用户在不正确地使用程序时获得特权的错误。
应该仔细考虑每个程序以确定是否需要将其 SUID 或 SGID 位打开。系统上有些 SUID/SGID 程序可能是根本不需要的。
要搜索具有这样性质的程序,可使用 find 命令。例如,可以在 /usr 目录中启动对 SUID/SGID 程序的搜索:
# cd /usr
# find . -type f -perm +6000 -xdev -exec ls {} \;
-rwsr-sr-x 1 root root 593972 11-09 12:47 ./bin/gpg
-r-xr-sr-x 1 root man 38460 01-27 22:13 ./bin/man
-rwsr-xr-x 1 root root 15576 09-29 22:51 ./bin/rcp
-rwsr-xr-x 1 root root 8256 09-29 22:51 ./bin/rsh
-rwsr-xr-x 1 root root 29520 01-17 19:42 ./bin/chfn
-rwsr-xr-x 1 root root 27500 01-17 19:42 ./bin/chsh
-rwsr-xr-x 1 lp root 8812 01-15 23:21 ./bin/lppasswd
-rwsr-x--- 1 root cron 10476 01-15 22:16 ./bin/crontab
在这个清单中,我已经发现了需要更仔细检查的侯选对象:lppasswd 是 CUPS 打印软件分发版的一部分。因为没有在系统上提供打印服务,所以我会考虑除去 CUPS,那也会除去 lppasswd 程序。lppasswd 中可能没有危及安全性的错误,但为什么要在不使用的程序上冒险呢?同样地,应该关闭所有不使用的服务。您总是可以在需要时再启用它们。
用 ulimit 设置用户限制
bash 中的 ulimit 命令提供了限制特定用户的资源使用情况的方法。一旦限制降低,则在进程的生命期内无法提高该限制。此外,该限制会被所有子进程继承。结果是:可以在 /etc/profile 中调用 ulimit,而限制将以不能撤消的方式应用于所有用户(假设用户正在运行 bash 或另一个 shell,该 shell 在登录时运行 /etc/profile)。
要检索当前限制,可使用 ulimit -a:
# ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
max locked memory (kbytes, -l) unlimited
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
stack size (kbytes, -s) unlimited
cpu time (seconds, -t) unlimited
max user processes (-u) 3071
virtual memory (kbytes, -v) unlimited
以一种能实际提高系统安全性而不会对合法用户造成麻烦的方式设置这些限制是相当复杂的,所以调整这些设置时要小心。
用 ulimit 设置 CPU 时间限制
作为 ulimit 的一个示例,我们尝试将一个进程的 CPU 时间设置为 1 秒钟,然后用一个忙循环使它超时。一定要确保启动新的 bash 进程(象我们在下面做的那样),以在其中进行尝试;否则将被注销!
# time bash
# ulimit -t 1
# while true; do true; done
Killed
real 0m28.941s
user 0m1.990s
sys 0m0.017s
在上面的示例中,“user”时间加上“sys”时间等于该进程所用的全部 CPU 时间。当 bash 进程到达 2 秒标记时,Linux 断定它超过 1 秒的限制,因此该进程被杀掉。酷吧?
注:一秒钟只是示例而已。不要对您的用户这样做!即使几小时也是不对的,因为 X 真地很消耗时间(我当前的会话已用掉了 69+ 小时的 CPU 时间)。在实际的实现中,您可能要对某些项而不是 CPU 时间执行 ulimit。
入侵预防
外部安全性可分为两类:入侵预防和入侵检测。采取入侵预防手段是为了防止未授权用户访问系统。如果这些手段失败,那么入侵检测在确定何时发生未授权访问以及造成什么损坏方面或许有用。
完全的 Linux 安装是巨大且复杂的系统。跟踪已安装的每一项是很困难的,而配置每个包的安全性特征就更困难了。安装的包越少,则问题就变得越简单。入侵预防的第一步是除去不需要的包。
关闭未使用的网络服务(超级服务器)
关闭未使用的网络服务一直是提高入侵预防能力的好方法。例如,如果正在运行因特网超级服务器(如本教程前面描述的 inetd 或 xinetd),那么 in.rshd、in.rlogind 和 in.telnetd 通常都在缺省情况下启用。这些网络服务几乎都已被更安全的替代项(如 ssh)所取代。
要在 inetd 中禁用服务,只需在 /etc/inetd.conf 中在适当的行前面加上“#”将其注释掉;然后重新启动 inetd 即可。(这在本教程前面已有描述,若需要复习,可返回几页快速浏览。)
要在 xinetd 中禁用服务,可以执行与 /etc/xinetd.d 中适当的代码片段相似的工作。例如,要禁用 telnet,可以将 /etc/xinetd.d/telnet 文件的整个内容注释掉,或简单地删除该文件。重新启动 xinetd 以完成此过程。
如果正在结合 inetd 使用 tcpd,或如果正在使用 xinetd,还可以选择限制与可信的主机进行的进入连接。对于 tcpd,可参阅本教程的前几章。对于 xinetd,可在 xinetd.conf(5) 手册页中搜索“only_from”。
关闭未使用的网络服务(独立服务器)
有些服务器并不由 inetd 或 xinetd 启动,但却作为“独立”服务器始终运行着。这样的服务器通常是 atd、lpd、sshd、 nfsd 和其它服务器。事实上,inetd 和 xinetd 本身都是独立服务器,如果在它们各自的配置文件中注释掉所有的服务,就选择了将它们完全关闭。
独立服务器通常在系统引导或更改运行级别时由 init 系统启动。如果不记得运行级别是如何工作的,可以看看 LPI 101 系列第 4 部分。
要使 init 系统不再启动服务器,在每个运行级别目录中找到指向该服务器启动脚本的符号链接,然后删除它。运行级别目录的名称通常为 /etc/rc3.d 或 /etc/rc.d/rc3.d(针对运行级别 3)。还需要检查其它运行级别。
除去服务的运行级别符号链接后,仍需要关闭当前运行的服务器。最好用服务的初始化脚本完成这一操作,通常可以在 /etc/init.d 或 /etc/rc.d/init.d 中找到这一脚本。例如,要关闭 sshd:
# /etc/init.d/sshd stop
* Stopping sshd... [ ok ]
测试更改
在修改 inetd 或 xinetd 配置以禁用或限制服务,或用服务器初始化脚本关闭该服务器后,应该对所做的更改加以测试。可以使用 telnet 客户机通过指定服务名称或号码来测试 tcp 端口。例如,要验证 rlogin 已被禁用:
# grep ^login /etc/services
login 513/tcp
# telnet localhost 513
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
除了标准 telnet 客户机以外,还应考虑使用实用程序以测试系统“开放程度”的可能性。我们推荐使用 netcat 和 nmap。
ncat 是“网络瑞士军刀”:它是使用 TCP 或 UDP 协议、跨越网络连接读写数据的简单 UNIX 实用程序。nmap 是用于网络探测或安全性审计的实用程序。具体而言,nmap 扫描端口以确定哪个端口打开了。