让 Linux 更安全

一、安全的定义

安全是当今 IT 相关头条新闻的一个重要话题。经常出现的系统漏洞和安全补丁以及病毒和蠕虫是每个使用 计算机的人都耳熟能详的名词。因为几乎每台计算机系统都连接到另外的计算机或者连接到 Internet,因此确保这些计算机的安全,对于减少入侵、 数据窃取或丢失、误用甚至对第三方的责任而言是至关重要的。

确保安全即使对于没有连接到网络的独立的计算机也是很重要的。必须自可信赖的来源安装应用程序,比如 经过验证的并检查过病毒的光盘。对应用程序数据也必须同样小心。例如,对于可以执行强大的宏语言 或者引入非法数据的软件程序包(office 套件等等),其软件缺陷可能会被利用来执行任意的代码。因此, 应用程序数据在拷贝到计算机之前必须经过完整性检查。可以通过将数据放置在一个安全的地方来控制对 系统的访问(当然,不考虑来自已授权人员的攻击)。

当系统连接到网络并向其他计算机提供服务(有意地或无意地)时,事情会变得更为棘手。在那种情况下, 数据可能不只是来自系统管理员,因为客户机程序要使用所提供的服务,而系统漏洞可能会让入侵者控制 计算机。

这就是为什么安全是从开始计划直到拆除系统的整个系统生命周期中最基本的问题。但是,安全的 确切含义是什么?

通常,数据安全和系统安全可以分开来考虑。 数据安全通常被认为是确保以下方面的所有努力:

  • 机密性(Confidentiality)。
  • 完整性(Integrity)。
  • 可用性(Availability)。

综合起来,这些被称作是存储在计算机上的数据的“CIA”。对 /etc/passwd 等配置 数据的保护可以归类为数据安全。 系统安全 指的是计算机平台本身。美国 National Information Systems Security Glossary 对系统安全 的定义如下:

系统安全。对信息系统的保护,防止未授权的访问及对信息(不论是存储中的、正在处理的还是正在传输的)的修改, 并防止对授权用户服务的拒绝或对未授权用户服务的允许,包括那些检测、记录和反击此类威胁的措施。

重要的是要认识到系统安全强调的是一个反复的过程,这个过程包括应用安全补丁、经常审计、控制,同时最起码要有 一个安全的系统配置。就此而言,不可能保证绝对的安全,也不可能提供百分之百安全的服务。目标更应该是在安全性、系统可用性和 维护这个安全层级所需要的努力这三者之间找到一个折衷点。这个折衷取决于安全对于存储在计算机中的数据来说的重要性以及 这些数据预期的使用情形 。

完整性

具备 完整性 的数据是指合法的而且没有经过偶然的或恶意的修改。当进行数据存储或交换时应该考虑其完整性。 目标接收到的数据必须是源数据的原样拷贝。这就是说,一方面,物理传输和存储媒介必须是可靠的,以使得数据可以 正确地传输而不发生位错误。另一方面,数据必须不能被未经授权的实体不加检测地访问而修改。完整性的范围是从用户 —— 最终的权威 —— 将数据委托给系统后开始的。因此用户错误不在完整性范围之内。

对网络连接而言,要尤其注意确保完整性,不管网络是否安全(例如,通过加密传输)。在传输过程中,可以访问 传输媒介的第三方可能会重新路由或者修改数据。涉及网络的物理环境和互联的计算机的完整性的方面并不特定于 Linux, 而是对所有计算机安装来说都是如此;因而这也超出了本文的范围。无论如何,除了其他方法之外,在物理层上 采取的保护数据的措施包括,限制对计算机的访问、保持对传输媒介(比如电缆和连接器)的保护,以及避免停电和 静电释放 。

机密性

当受保护的数据只能被授权的人或系统读取或者修改时,要保持其 机密性。这是一个与完整性截然不同的 概念:当数据在网络上传输时,它可能是被毫无修改地正确传输,因此确保了其完整性,但是如果被第三方中途截取的 话就再也不是机密的了。当未被授权的人可以访问数据传输并从中获取有价值的信息时,只有完整性是不够的。 数据的机密性引出了三个更深入的问题:

  • 谁希望访问数据?(认证)
  • 哪些数据可以被访问?(授权)
  • 如何保护数据不受未授权的访问?

Linux 有若干方法可以确保试图访问数据的实体是其所宣称的那一个。通过 Pluggable Authentication Modules(PAM),您可以 实现一些认证策略,从存储在本地机器上一个集中目录(NIS、Kerberos、LDAP 等等)中简单的用户名/口令组合,到 硬件标识或生物特征扫描不等。文件访问的授权可以使用传统的(粗糙的)UNIX 文件权限来解决:用户、组或全体级别的读、写和 执行权限。较新的细粒度的(fine-grained)方法 —— 访问控制列表(Access Control Lists)—— 让您可以为具体的用户授予 或拒绝具体的权限。

标准 Linux 安全概念是在软件中实现的,依赖于内核不接受没有被授权的用户对资源的使用。不过, 内核缺陷(特权提升/自动调整、未经检查的参数,等等)可能会使用户可以访问先前不能访问的内存 区域、磁盘空间、网络或者其他资源。通过安装击键记录器(keyloggers)、取走硬盘驱动器并在其他 机器中读取、嗅探网络传输等等,对硬件物理上的访问可以让用户绕过软件检查。这样,必须采取 更进一步的努力来保护机密的数据,比如文件系统、单个文件、网络传输的加密,和/或应用程序级别 的加密。此外,物理上的措施也需要考虑,比如安全区域、数据的安全删除,以及机密信息的 会计程序,不过本文并不涉及这些。

可用性

即使完整性和机密性都得到了保证,如果数据不能被访问,那么它是没有用处的,即不可用的。 可用性 措施确保数据永远不会丢失,而且当被请求时,可以以预定义的性能级别被访问。 可用性可能会受到不同方式的威胁:

  • 破坏性攻击 —— 称为拒绝服务(Denial-of-Service,DoS)攻击 —— 这类攻击的目标是可用性。 它们通过消耗所有可用的网络、CPU、存储或操作系统资源(比如文件句柄),使得一台计算机 或一个服务不可用或不能用。
  • 目标是数据本身的攻击,试图删除或覆盖数据。
  • 数据的意外破坏。在大部分情况下,不可能避免对数据的意外破坏,因为拥有适当权限的用户被 认为是最终的权威。您只能通过在适当的位置使用一个备份/转储基础设施来预先做好准备。
  • 最后,但不是最不重要的,缺陷、配置错误、物理环境、硬件失败、停电、不必要的系统重新引导等等, 也都可能影响可用性。这个列表中的软件相关话题更应该归入 系统安全。 
  • 解决上面列表中的前两个问题的特定 Linux 措施包括,网络数据包的防御(firewalling)/过滤 (filtering ),对文件系统完整性 的保护,以及计划可根据需要进行添加的额外的资源 。

Linux 系统安全

Linux 是一个现代的、开放源代码的操作系统,可以自由地发行和拷贝。每个用户都有权限修改它的源代码, 易于为您自己的环境定制 Linux、向操作系统添加新部件、发现缺陷和提供补丁,以及检查源代码中的安全 漏洞。

尽管数据安全和系统安全是分开来考虑的,但是系统安全会对数据安全产生主要的影响。这就是为什么 Linux 具有很多解决机密性、完整性、可用性以及系统安全本身的问题的集成部件的原因。其中有 IP 防御、 认证机制、系统日志和审计、加密协议和 API、内核级 VPN 支持,等等。另外,系统安全可以由 (开放源代码)软件应用程序来支持,这些应用程序提供安全服务、加固和/或控制 Linux 系统、 防止并检测入侵、检查系统和数据的完整性,并提供防止不同攻击的屏障。

安全的一个值得关注的主要因素是,Linux 与不开放源代码的操作系统之间的区别在于开放源代码开发 过程本身。由于软件的每个用户和开发都可以访问其源代码,因而有很多人都在控制和审视源代码中 可能的安全漏洞。软件缺陷很快会被发现。一方面,这会导致这些缺陷更早被利用;另一方面,很快 就会有可用的安全补丁。

二、计划安装

安全计划

第一步 —— 在插入发行版本 CD 并启动安装程序之前 —— 是制定一个安全计划:确定系统将要提供什么服务, 要使用什么硬件,需要什么软件,如何组织安装。通过在实际安装前认真地制定这样一个计划,在非常早 的阶段就可以确定并排除很多可能的安全问题。这样做是有益处的,因为它有助于最小化系统入侵或者断电 的风险。而且,它为发生攻击或者发布软件漏洞和补丁时进行快速反应提供了一个坚实的基础。

当考虑安全策略时,重要的是要注意计算机系统的安全性与可用性之间总是会有一个折衷。如果因为复杂的设置和 维护以及可用性的缺乏而无法使用,那么最完善的安全特性也没有意义。另外,极度复杂的、极其耗费处理能力的 加密算法实际上会锁住系统,几乎不留下任何计算能力给真正的任务使用,那么它又有什么用呢?

要制定安全计划,您应该执行下面的步骤,收集所有相关信息:

进行清单评估时要回答的问题

  • 使用什么硬件?

    指定硬件,它的位置,以及任何可能的特定安全特性(比如加锁的而且防火的房间)。 列出网络接口、协议、地址以及相关的名称。

  • 应该安装什么软件和操作系统?

    指定应用程序及它们的数量,检查每个软件的许可证。

  • 存储什么类型的数据,它的危险程度如何?

    确定数据的种类。对于每一个确定的种类,根据其机密性和稳私考虑数据的危险程度。

  • 谁对系统负责?

    为系统指定负责人(例如,一个单独的系统管理员,一个专门的 IT 服务部门,或者一个支持提供商)。

完成清单评估

获得安全计划的第一个步骤是,评估清单以了解哪些是必须要保证安全的(参见右面的侧栏)。 这样的清单集中关注计算机的物理硬件、网络连接、接口,并定义其职责。所有从清单评估得 到的信息都应记入文档。记录文档的一个合适的方法可以是一个包含有每台计算机所有相关信息的 电子数据表。

定义网络服务和软件

对于每一台计算机,重要的是要定义它使用或者提供哪些网络服务,以及使用或提供服务的软件应用程序。网络 服务(除了其他内容以外,可能包括 DNS、文件传输、打印机和文件共享、Web/Internet、电子邮件和数据库) 应该记录在部署计划之中,这个计划还包括所使用的软件程序包以及此计算机是配置为客户机、服务器还是同时 具备两个角色。稍后,基于软件和服务的列表,您应该安装一个只包含必需软件的绝对最小化的系统,这样可以 使得具有隐藏安全漏洞的可能性最低。

除了定义软件服务以外,您还需要确定用于通信的协议,这也会带来一些安全问题。网络传输是否需要通过基于 SSL 的 HTTP(https)进行加密,还是普通的 HTTP 就足够了?文件传输协议是否强制用户进行认证(比如使用 sftp),或者 对必需的安全层级来说匿名的、不加密的访问是否合适?

通常,客户机工作站被配置为使用多个网络服务。不过,服务器应该专门提供一种单一的服务,因为这样会 简化配置并降低发生配置错误的可能性。应该由有限数目用户使用的服务应该通过防火墙保护起来以防止 不必要的访问。防火墙可以有效地实现管理两个或多个网络之间网络传输的安全策略。

完成风险分析

要在系统的安全性与可用性之间找到适当的折衷,重要的是要针对存储在计算上的数据的类型进行风险分析。 要弄清楚需要采取哪种类型的安全措施来保护资源的机密性、完整性和可用性,第一个步骤就是进行风险分析。

风险分析基于清单评估 —— 它声明了存储的是什么类型的数据 —— 集中关注系统受到安全威胁的可能性以及 相继而来的后果。换句话说,对于清单评估中定义的每一类数据,您都需要对此数据受到非授权访问的可能性 以及这种事件的影响进行评估。这种评估量化为三个级别:高、中、低。所必需的安全级别是事件的概率及其影响的平均水平。

确定用户种类和访问特权

您应该根据其特权和访问权限列出计算机系统的主要用户,或者用户的种类。对于桌面计算机而言,这可能是 相当简单的,因为用户的数目通常较少。不过,基于类似的工作分工或对数据资源和应用程序的类似需要来 定义用户分类是有意义的。

对服务器来说,确定用户种类通常非常复杂。管理员通常可以访问服务和操作系统工具的配置。 除此以外,还有根据需要使用相应服务的不同用户(本地的和远程的用户)。连接到因特网上的公共 服务器基本上是任何人都可以访问的,而内部服务器的用户可能会根据工作角色、部门或者办公室 位置进行分类。所以,如果需要,您应该区分本地和远程用户以及临时和来宾用户。对于已经确认的用户 种类,定义他们需要访问和操作(例如,读、创建、修改或删除数据)哪些数据资源。

详细行动计划

既然安装的总体环境和目标都已经完善地记入文档,您现在可以深入细节了 —— 使用什么软件, 如何安装和配置它,等等。您编写的计划应该详细到能回答出在安装过程中出现的任何问题的程度。

检查源代码

Ken Thompson 是 UNIX 的创始人之一,他在 Relections on trusting trust 中 讨论了为了设法使源代码不能揭示安全问题而采取的很多步骤。

首先,他为 login 命令打上补丁,使其包含一个后门,这样使他可以使用一个特定的密码 登录进入任何 UNIX 系统。

然后,他给 C 编译器打上补丁,使其当编译 login 命令时进行检测。C 编译器将自动把后门插入到 login 程序中,所以,不需要在 login 命令的源代码中保留后门。

然后,他对 C 编译器进行修改,使其在通过源代码编译 C 编译器本身时进行检测,并自动添加 login-detection-and-patching 代码和 C-compiler-detection-and-patching 代码。

结果得到一个源代码中不包含任何后门痕迹的系统。

选择 Linux 发行版本和服务器软件程序包

这实际上是两个单独的步骤,不过先做什么要取决于您的情况。在很多情况下,由于组织的政策、 企业许可证协议或者可用的技术,要使用的发行版本已经确定。有时,您会先关注可以满足安装 用途的软件程序包的选择;然后,根据程序包的先决条件、哪个发行版本包含立即可用的程序包、或者 发行版本的价格,来选择发行版本。不过,通常两者是结合在一起的,您必须反复缩小选择范围。 不过,您永远不应该仅仅因为您手边有某个安装媒体而选择安装那个发行版本。

对于每一种使用情形(邮件服务器、文件服务器、Web 服务器、字处理等等)都有多种软件程序包可以 满足其用途。尤其当用户不直接与软件程序包打交道时(比如由专门团队管理的服务器软件),您 选择更为安全的软件程序包时所受的限制就会更少。要对各种 Web 服务器、邮件传输代理、数据库 管理系统等,或者甚至是整个发行版本的安全方面进行评价,最好首先搜索 BugTraq 或 Full Disclosure 等邮件列表 。

基于软件程序包的历史问题来判断其安全性,这实际上相当于看着后窗玻璃驾驶汽车 —— 您不知道将要遇到的是 什么,但是您可以得知您是在直路上还是在弯路上。另一个应该谨记的问题是,相对于很少用到的, 经常用的软件程序包受到的检查更多。仅仅因为“Tom's HyperWeb Server v0.0.2”在这些邮件列表上没有 任何已知的 bug,并不意味着它就没有 bug。

能在源代码层次上对任何软件程序包进行审计,经常被列举为开放源代码软件的优势之一。不过, 可用时间、技术和预算等现实的约束使得这种方法在几乎所有情形下都是不切实际的,所以您不得 不依赖于程序员 和/或 程序包维护者和发行者的诚实。

您还应该将打算如何运行一个服务记入文档。需要考虑的一些事情:

  • 使用 xinetd 让您可以调整哪个服务可以提供给谁,可以强制限制防止拒绝服务(denial-of-service)攻击, 可以将服务调用日志记录到一个集中的位置。
  • TCP 包装器 提供了一种方法,以将服务限制在特定范围的请求地址内,并将请求记录到日志。
  • chroot jails 创建一个环境,这个环境是您实际安装的一个子集。即使服务受到攻击, 被影响的也只是这个子集环境。由于它基于目录树的隐藏部分,所以它最适用于那些操作在可以方便地包括到那个树中的小的而且独立的文件集上的服务器。

附加的软件程序包

除了计划的使用情形所需要的软件之外,安装过程很可能还会安装其他软件。您需要的软件 (实际的操作系统:Linux 内核、共享库、基本的实用程序等等),您想要的软件(增强安全性 的软件,比如配额、防火墙和审计),以及您不想要的软件(不必需的程序包)。

为了方便,发行版本通常向默认安装添加保持系统运行和满足其用途所不必要的软件程序包。在运行期没有用户 交互的系统中,图形用户界面、多媒体软件和游戏都属于这种不必要的软件。

任何安装到机器上的软件都必然会占用资源并降低机器的安全性,引入可能被利用的潜在的 bug:

  • 外部攻击者可以利用不必要的服务在服务器上执行代码,比如通过缓存溢出 。
  • 管理员也是人,所以容易犯错误。没有安装的软件不可能被错误地配置,这样就封住了另外的潜在安全 漏洞。
  • 即使软件不是一直在运行,也没有暴露在网络上,也会增加管理员的负担,因为在发现 bug 时管理员要 进行安全修订。假定某个服务中的一个瑕疵被发现,而且发生了入侵。攻击者现在可以在用户的 安全上下文中在服务器上执行程序。现在,机器上任何可用的程序都可能被攻击者利用,或者是 提升他/她的特权,获取安全相关的信息,或者攻击可能深藏在组织的防火墙之后的其他系统。
  • 社交工程技巧(social engineering techniques)经常欺骗合法用户(乃至管理员)去运行最终 影响安全的程序,这是为什么要尽可能少地安装程序的另一个原因。

关于增强安全性的程序包,您应该考虑安装下面这些:

  • 配额: 应该使用配额来限制用户(包括 ftpd 或 httpd 等后台进程的用户)可用的资源。 这样可以挫败本地拒绝服务(DoS)攻击,那种攻击可能通过“fork bomb”用光所有可用的进程 ID,启动 很多极其消耗内存的程序,或者消耗分区的全部空闲空间。大部分当前发行版本都包含配额,在大部分情况 下其程序包称为“quota”。通过 PAM 可以实现除了磁盘配额以外的其他限制,它默认也会安装。在本系列 的下一篇文章中将描述那些限制的配制。
  • 防火墙: 通常,防火墙会根据定义的规则集合制止网络通信。所以,它的基本任务是通过 阻塞不必要的传输来避免网络入侵。网络防火墙工作于 TCP/IP 栈层次之上,决定数据包是否可以通过 (取决于规则集合)。
  • 入侵检测: 入侵检测系统(intrusion detection system,IDS)的主要任务是, 通过识别到来的 shellcode、病毒、恶意软件(malware)或者特洛伊木马等安全缺口,检测 进入网络或者计算机的攻击或入侵。
  • 审计: 审计指的是通过建立数据处于其期望状态的基线来检测敏感数据或配置文件 的改变。当发生意外改变时,对基线的改变会被报告,使得管理员可以快速反应并进行恢复。

使用安全的工具程序版本

当前仍然有很多早期 Internet 应用程序存在,并且在使用中。开发它们时,安全还不是个大问题,因为 那时 Internet 参与者很少。近些年,随着因特网的发展和迅速成长,安全性的缺乏使得那些应用程序不 适于当前的应用。这就是开发它们的代替者的原因,这些代替者可以以安全的方式执行相同的任务 —— 现在的任务还是像在早期时一样重要。在这里,“安全的方式”的基本意思是:

  • 对传输的数据(包括用户凭证和其他用户相关数据)加密,防止第三方可以理解传输的信息。
  • 使用用户名和密码或者数字签名等凭证来识别用户和系统。

常见工具的安全代替者

任务/使用情形 老的不安全的应用程序 推荐的安全代替者
远程访问命令行
  • telnet
  • rsh(远程 shell)
  • ssh(安全 Shell)
图形方式访问远程系统
  • X Window
  • VNC
  • 基于 ssh 的 X Window
  • 基于 ssh 的 VNC
  • rdesktop
文件传输
  • ftp
  • rcp(远程拷贝)
  • sftp
  • scp(安全拷贝)
镜像/备份
  • rsync
  • 基于 ssh 的隧道 rsync

尽管这些代替者通常被称为“安全的标准的应用程序”,但是它们并不是绝对不会受攻击。这表示, 虽然您经过深入考虑使用了安全的版本而不是不安全的版本,您仍需要建立另外的观念和步骤来保护您 的系统。 

分区

选择的应用程序以及安装所使用的源代码并不是安全性的惟一因素。要减少那种试图填满可用 磁盘空间的 DoS 攻击带来的影响,请确保您至少为下面这些目录计划专门的分区:

  • /home: 使用户数据与系统无关。当您执行备份和恢复操作、升级或切换操作系统、或者在 系统中迁移用户时,这非常有用。
  • /var: 保存服务器的日志和运行时数据。通过将其安放于一个单独的文件系统,如果您成为某 个 DoS 攻击的目标,则数据不会填满您全部的空闲空间。
  • /tmp: 类似于 /var,这个目录对用户进程来说是可写的,使得它成为 DoS 攻击的一个目标。 比使用单独的文件系统更好的办法是使用 tmpfs,它加速了文件的访问速度,并在重新引导时自动清空 文件系统的内容。
  • /boot: 容纳有 Linux 内核、初始驱动程序以及引导加载器数据。不必为了引导过程而挂载 这个分区,因为引导加载器将内核加载为一系列扇区,以从硬盘读取数据。如果在正常的操作中没有挂载它,那 么您就不会意外地覆盖这些文件。

获取发行版本

可以通过很多不同的途径获得 Linux 发行版本:热缩塑料包包装的 CD/DVD 发行版本、从其他人那里拷贝、 下载,等等。如果系统在安装的时候就已经被破坏,那么它根本是没有价值的,因此您必须确保基于“干净”的 来源进行安装 —— 确认代码没有后门。实际上,这一负担转嫁给了那些编制包含安装文件的 CD/DVD 组的 发行者。虽然您可以信任发行者,不过,根据发行者公布的校验和来校验安装媒体的校验和以确定媒体是正品, 仍不失为一个良好的习惯做法。

如何校验安装媒体

要校验 MD5 校验和,您可以使用

$ md5sum /path/to/iso/image.iso

$ md5sum /dev/cdrom

来分别校验 ISO 映象或者 CD。计算出的校验和必须与发行者公开的相匹配。如果您通过 Web 得到发布的 校验和,那么要确保使用 https,并查看连接中使用的凭证,以确保校验和的发布者是真实的。

不推荐通过网络或者因特网进行安装 —— 尽管技术上可行。一个站点可能(比如,通过欺骗)将自己伪装为一个 可信任的安装源,并提供加入了后门的修改过的软件程序包,使得在安装后入侵者可以不费力地接管系统。当然, 可**以通过内部网络服务器进行安装,例如当来源已知而且合法时。

刚刚安装的操作系统通常不能马上使用,可能没有安装最新安全补丁。此时是最容易受到攻击的 (参见 参考资料 中一篇关于未打补丁的系统预期生存期的文章的链接), 在从安装过程直到完成配置步骤期间,应该从 Internet 上隔离出来,或者至少是在一个安全的网段。 在本系列的下一篇文章中将讨论这些步骤。

安装后,应该通过第二台(有适当保护的)计算机从 Internet 上下载最新的安全补丁和更新。同样,必须 选择可信任的安装来源来下载补丁。可以通过严肃的提供者所给出的校验和或者散列来检验下载的安装文件 的完整性。

三、加固系统

关于加固

要让加固行动更为成功,您应该:

  • 在系统连接到网络之前进行加固,以避免攻击。
  • 基于 最小权限原则(least-privilege model) 进行配置:系统应该为特定的功能只赋予其所需要的权限。类似地, 用户应该只拥有他们所需要的最小限度的权限。

在完成初步计划并准备和执行了最小化安装后 ,您需要进行一些配置步骤。这些步骤通常被称作是 加固 Linux。

  • 保护引导过程
  • 保护服务和后台进程
  • 保护本地文件
  • 强制实行配额和限制
  • 启用强制访问控制
  • 更新和添加安全补丁

保护引导过程

配置引导加载器(LILO 或者 Grub),以令其在引导时不被任何用户干涉;这样就防止了用户在引导提示时 向内核传递参数。除非您需要远程引导(比如在远程的数据中心),不然就配置它让它要求输入密码。这是 对有可能物理上接触机器的人的进一步防范;它可以防止某些事件的偶然攻击,比如使用参数 single 或者 init=/bin/sh 来获得 root shell, 等等。不过,要注意,稍加努力就可以避开此防范机制(比如拆下硬盘驱动器并将其挂载到另一个系统上), 除非您对文件系统也进行了加密。

对 LILO 而言,在 lilo.conf 配置文件(通常在 /etc 下)中使用参数 password 替换 prompt。对于 Grub,相应的参数是 Grub 配置文件(通常在 /boot/grub/grub/conf 下)中的 hiddenmenudefault 0 和 password

在 /etc/inittab 中添加 sp:S:respawn:/sbin/sulogin,以确保当切换到单用户模式时 运行级的配置要求输入 root 密码。

防止用户使用 Ctrl-Alt-Del 进行重新引导:在 /etc/inittab 中注释掉 ctrlaltdel 行, 禁用 ctrlaltdel。通过向类似这样一行( #ca::ctrlaltdel:/sbin/shutdown -t5 -rf now)添加一个井号(#),您就可以防止 那个组合键触发重新引导。

保护服务和后台进程

服务的安全配置的第一个步骤是,禁用所有不需要的服务。不提供的服务不会为潜在的入侵者所利用,有效地降低了风险。

为了找出所有启用的服务,需要检查若干个位置。另外,要禁用不安全的服务,并使用更为安全的选择来取代它们。例如,telnet 不是加密的,所以,使用加密的 ssh 服务来取代 telnet(见第 2 部分)。

当保护服务时,考虑这些方面:

  • /etc/inittab
  • /etc/init.d 中的引导脚本
  • inetd/xinetd 后台进程
  • TCP 封装器(wrappers)
  • 防火墙

/etc/inittab

在引导过程中,init 进程会去读取 /etc/inittab 文件中的条目。 每一个条目 —— 每一行 —— 都定义了在特定的条件下运行哪个程序。这些程序或者本身是服务, 或者是用于启动和停止服务。

init 进程能识别若干个称为 运行级(run levels) (由一个字母标识) 的状态。当输入了运行级或者发生特定的事件(比如电源故障)时,就会考察那些条目,并执行适当的命令。

/etc/inittab 中条目的格式是,前面是条目的标签,随后是在哪些运行级下此条目要执行,然后是动作关键字以及 包括命令行参数的需要执行的命令。所有这些域都由冒号隔开,典型的条目应该类似这样:

my_service:35:once:/usr/local/bin/my_service someparameter

(在 inittab 手册中可以找到动作关键字的完全列表。)

在这个示例中,条目的标签是 my_service。当输入的运行级为 3 或 5 时, 它将使用参数 someparameter 来运行程序/usr/local/bin/my_service。一旦这个程序被终止,它将不会再重新启动 (动作关键字“once”)。

为了保护 Linux 系统,您应该理解 /etc/inittab 中所有条目的功能,并禁用潜在不必要的服务,方法是 删除那个条目,或者在那一行的开头使用井号注释掉它。

在所有 Linux 系统中,都会有以下两类条目。第一类用来启动名为 /sbin/getty (或者类似的)的程序,这些通常是用来允许通过 Linux 虚拟控制台或者串行线登录。第二类会运行 /etc/rc.d 目录中通常名为 rc 的脚本,并将当前运行级作为参数给出。 这个脚本控制服务的启动和停止(接下来会介绍)。

/etc/init.d 中的引导脚本

/etc/init.d 中的引导脚本用来启动或者停止系统服务。对于每一个运行级,都有一个 /etc/rcN.d 目录 (“N”是运行级的标识),其中包含了指向那些在运行级改变时需要调用的脚本的软链接。

如果链接名以“S”开头,则脚本在进入那个运行级时执行,启动相应的服务;如果以“K”开头,则 脚本在退出那个运行级时执行,停止那个服务。

大部分情况下,引导脚本的名称会暗示它所控制的服务。要防止在特定的运行级中会启动某个服务, 则删除运行级目录中指向相应引导脚本的链接,或者使用一个不做任何事情的虚脚本取代 /etc/init.d 中原来的引导脚本。

inetd/xinetd 后台进程

也可以在客户机请求时根据需要调用服务。这些请求被转交给超级后台进程 inetd 或者 xinetd。然后超级后台 进程确定要启动哪个服务,并将请求传递到相应的后台进程。通常,telnet、ftp、rlogin 等服务 使用 inetd 或者 xinetd 启动。

inetd 后台进程在 /etc/inetd.conf 配置,那个文件中包含了关于每一个超级后台 进程需要提供的服务的条目。配置 FTP 服务器的条目应该类似这样 —— ftp stream tcp nowait root /usr/bin/ftpd in.ftpd -el —— 使用井号注释掉它, 就可以禁用它。

为了安全起见,建议使用 xinetd。与 inetd 相比, xinetd 能够启动基于 rpc 的服务,并支持访问控制。xinetd 可以限制进入连接的速度、来自特定主机的进入连接的数目,或者某个服务的总连接数。

通过用于每个从属后台进程的独立配置文件来配置 xinetd 。 这些文件位于 /etc/xinetd.d/ 目录中。前面 FTP 服务器的示例配置文件应该称为 called /etc/xinetd.d/ftp, 类似这样:

清单 1. 配置文件,/etc/xinetd.d/ftp

1

2

3

4

5

6

7

8

9

10

service ftp

    {

        socket_type       = stream

        protocol         = tcp

        wait           = no

        user           = root

        server           = /usr/bin/ftpd

        server_args       = -el

        disable          = yes

    }

为了禁用这个服务,参数 disable 被设置为 yes,如上面示例所示。

为了更详细的访问控制,xinetd 支持以下三个另外的参数:

  • only_from
  • no_access
  • access_time

为了限制访问,但不完全禁用 ftp 后台进程,您可以如下修改配置文件 /etc/xinetd.d/ftp:

清单 2. 为限制访问而修改过的配置文件,/etc/xinetd.d/ftp

1

2

3

4

5

6

7

8

9

10

11

12

13

14

service ftp

    {

        socket_type       = stream

        protocol         = tcp

        wait           = no

        user           = root

        server          = /usr/bin/ftpd

        server_args       = -el

        disable           = no

        only-from          = 192.168.200.3 192.168.200.7 192.168.200.9

        only-from        += 192.168.200.10 192.168.200.12 172.16.0.0

        no_access        = 172.16.{1,2,3,10}

        access_times        = 07:00-21:00

    }

only-from 和 no_access 可以接受数字 IP 地址 (最右边的零作为任意数值处理)、IP 地址/网络掩码 范围、主机名以及 /etc/networks 中的网络名。 如果组合使用 only-from 和 no_access, xinetd 会为每个主机连接寻找最接近的匹配。

在前面的代码示例中,表示 IP 地址为 172.16.x.x 的主机可以连接到此主机,但地址属于 172.16.1.x、 172.16.2.x、172.16.3.x 和 172.16.10.x 的则不能连接。可见,当使用 no_access 所用的因数符号时,不需要指定地址的所有四个部分。因数部分必须是地址最右边的部分。 参阅下面的 参考资料 部分,以获得关于 xinetd 及其配置 的文章。

TCP 封装器

如果您决定不使用 xinetd,而是使用 inted, 那么您可以使用 TCP 封装器来记录请求和具体的对特定网络的 允许/拒绝。TCP 封装器会为了认证和记录日志而 去检查 /etc/hosts.allow 和 /etc/hosts.deny, 并将客户机请求封装起来,不直接回应它们。一旦认证成功,请求就会被转发到原来请求的服务。

相对于使用普通的 inetd,使用 TCP 封装器有两个主要的好处:

  • 发出请求的客户机不会察觉到 TCP 封装器;因此,没有异心的人不会发现任何区别,而心怀不轨的人也得不到 关于他们的请求失败的任何信息。
  • TCP 封装器的工作不会理会任何已经被封装的服务,让应用程序能够共享它们的配置文件,从而简化管理。

要获得关于 TCP 封装器配置文件的详细文档,请参阅 参考资料 中列出的 Red Hat Linux Reference Guide

如何找到所有人都可写的(world-writable)文件

要找出所有人都可写的文件,使用此命令:

find / -perm -002 \( -type f -o -type d \) -ls

其中:

  • / 是搜索的起始位置。
  • -perm 检查权限。
  • 002 表示(八进制符号)“other”设置了写位。
  • 模式 002 之前的 - 表示设置了所有权限位 (没有考虑模式中的 zero-bits)。
  • -type f 或者 -type d 搜索常规的文件和目录。
  • -ls 以 ls 格式列出找到的文件。

防火墙

为了防范与不应该运行的服务或者不应该被 Internet 等特定网络所访问的服务的通信,建议安装一个防火墙。 防火墙提供网络间基于信任级别的受控通信,并权衡使用基于角色的安全策略和最小权限原则允许或者拒绝对特定服务 的访问。

防火墙的安装与配置是一个非常复杂的话题,不在本系列文章的讨论范围之内。

保护本地文件系统

保护本地文件系统涉及的是文件和目录的所有者及访问它们的权限。要保护文件系统,文件和目录的保护位必须 设置为只授予最小限度的权限。

要特别注意关于所有人可写的文件和系统目录的不适当权限,以及所谓的 setuid 或者 setgid 命令。这些命令运行时的用户权限比运行此命令的用户实际拥有的权限 更高。对访问只有 root 才可以访问的文件来说这可能是必需的(比如 /bin/passwd 需要访问 /etc/passwd)。 对于这些命令,要确保它们每一个都确实需要设置 setuid/setgid 位。 如果不是这样,那么禁用它。

当某个分区上的所有文件确实都不需要 setuid/setgid 位时, /etc/fstab 中的 nosuid 选项可以为相应文件系统中的每个文件都禁用它 (下面的示例中的 /dev/hdc1):

1

2

3

4

#device     mountpoint  filesystemtype  options     dump    fsckorder

/dev/hda1   /       ext2        defaults    1   1

...

/dev/hdc1   /mnt/cdrom  iso9660     nosuid,user 1   2

此外,对于所有敏感的数据,都有必要对其进行加密并使用密码保护它。为此,GnuPG 提供了一个合适的软件包。

强制实行配额和限制

Linux PAM(插入式认证模块,Pluggable Authentication Modules)可以强制实行一些实用的限制,在 /etc/security/limits.conf 文件中对此进行配置。谨记,这些限制适用于单个对话。您可以使用 maxlogins 来控制总额限制。limits.conf 中的条目有如下结构: username|@groupname type resource limit

为了与 username 区别,groupname 之前必须加 @。类型必须是 soft 或者 hard。软限制(soft-limit)可以 被超出,通常只是警戒线,而硬限制(hard-limit)不能被超出。resource 可以 是下面的关键字之一:

  • core - 限制内核文件的大小(KB)。
  • data - 最大数据大小(KB)。
  • fsize - 最大文件大小(KB)。
  • memlock - 最大锁定内存地址空间(KB)。
  • nofile - 打开文件的最大数目。
  • rss - 最大持久设置大小(KB)。
  • stack - 最大栈大小(KB)。
  • cpu - 以分钟为单位的最多 CPU 时间。
  • nproc - 进程的最大数目。
  • as - 地址空间限制。
  • maxlogins - 此用户允许登录的最大数目。

在下面的代码示例中,所有用户每个会话都限制在 10 MB,并允许同时有四个登录。第三行禁用了每个人的内核 转储。第四行除去了用户 bin 的所有限制。ftp 允许 有 10 个并发会话(对匿名 ftp 帐号尤其实用);managers 组的成员的进程数目限制 为 40 个。developers 有 64 MB 的 memlock 限制,wwwusers 的成员不能创建大于 50 MB 的文件。

清单 3. 设置配额和限制最佳的配额经验

您应该为允许用户写入的每一个分区启用配额。也要考虑到您的系统中有一些属于应用程序的用户 ID,而 不是个人用户。那些 ID 可能会拥有对某些目录的写权限,而人没有这种权限。

向 cronjobs 添加 /sbin/quotacheck -avug,以自动更新内核当前所使用的 配额文件和表。

要激活这些限制,您需要在 /etc/pam.d/login 底部添加下面一行: session required /lib/security/pam_limits.so

配额让您能够限制用户和组的 inode 数目和可用空间。注意,配额是在每个加载点上定义的,所以,如果 用户在若干个分区上有写权限,那么要确保为它们每个都定义配额。

配额是管理员最小化 DoS 攻击的一种方式,这类攻击以填满硬盘驱动器上所有可用空间为手段(这会使其他进程 不能创建临时文件而使它们失败)。根据您正在使用的发行版本,您可以安装自带的配额工具,也可以自己下载、 编译并安装它们(参见 参考资料)。

必须在内核中启用配额。当前大部分发行版本都支持配额。如果您的发行版本没有启用配额,那么参考 参考资料 中的 mini-howto 来获得启用它们的说明。

要为文件系统启用配额,您必须在 /etc/fstab 中为相应的那行添加一个选项。 使用 usrquota 和 grpquota 来启用 用户配额和组配额,如清单 4 所示:

清单 4. 启用用户配额和组配额

1

2

3

4

5

/dev/hda1    /           ext3    defaults                     1 1

/dev/hda2    /home       ext3    defaults,usrquota            1 1

/dev/hda3    /tmp        ext3    defaults,usrquota,grpquota   1 1

/dev/hda4    /shared     ext3    defaults,grpquota            1 1

/dev/hdc1    /mnt/cdrom  iso9660 nosuid,user                  1 2

然后,使用 mount -a -o remount 重新挂载相应的文件系统,来激活刚才添加 的选项;然后使用 quotacheck -cugvm 创建一个二进制配额文件,其中包含了机器 可读格式的配额配置。这是配额子系统要操作的文件。

使用工具 edquota 完成配额的指派。要为用户 alice 定义限制,则使用 edquota -u alice 来调用它。环境变量 EDITOR 中定义的编辑器(默认是 vi)会打开,其中有类似如下的内容:

1

2

3

Quotas for user alice:

/dev/hda2: blocks in use: 3567, limits (soft = 5500, hard = 6500)

         inodes in use: 412, limits (soft = 1000, hard = 1500)

“in use”值只是为您提供信息,不能被修改 —— 您能修改的只是软限制和硬限制。保存并退出编辑器后, edquota 会读取您刚才编辑的临时文件,并将那些值传递到二进制配额文件,以 使您的修改生效。对组配额的编辑与此相同,只是必须使用 -g 选项而不是 -u

软限制是警告级别,可以被超出,而硬限制是严格强制的。软限制有一个 宽限期(grace period) (有时也称为 软性时间限制(soft time limits));这是允许用户超出软限制直到被系统强制执行之前的 时间间隔。

您可以使用 edquota -t 来设置宽限期。可以使用的单位是秒、分、小时、天、周和月。 其他管理配额的实用工具包括 repquota(总结某个文件系统的配额)、 quotaon 和 quotaoff(打开和关闭配额)。

启用强制访问控制

通过 SELinux 所实现的强制访问控制(或者说是 MAC),您可以获得进一步的安全性。使用 MAC, 操作系统中的许可由进程所属的 用户/组 ID 以及正要被访问的对象(文件)所属的 用户/组 ID 来管理。 另外,使用 MAC,Linux 会强制为每个单独的进程执行这些策略,它们会控制进程可以做什么事情。

那样,在使用 MAC 进行适当配置的系统中,被外来控制或攻击的服务不能够接管系统。就算是进程运行 所属的用户或组 ID(最坏的情形:root)可能会与 /etc/passwd 等关键系统文件权限相匹配,那个策略也会及时 地禁止对它们的访问。

Internet 上的测试系统可以展现出 SELinux 的有效性,它允许任何人登录;控制机制防止了所有的恶意 行为,即使用户能够以 root 身份登录!

添加提供商 GnuPG 密钥

发行版本提供商 GnuPG 密钥应该已经是基本配置的一部分。您可以使用这个命令添加您所信任的第三方提供商的密钥: $ rpm -import <keyfile>

您应该确保是以安全的方式获得密钥文件,例如,通过 HTTPS 从提供商的 Web 站点上下载,这样您 可以校验连接的证书。

不过,使用 SELinux 也有一些问题。首先,如果发行版本提供商不支持 MAC,那么其配置是相当困难的。 可能需要打补丁和重新编译内核,并替换特定的系统管理工具(所有这些都可能影响发行版本提供商的支持 策略)。第二,定义一个适当的策略是非常复杂的任务。如果没有可用的策略定义供您的应用程序选择, 那么在 MAC 环境中制定并实施这个策略会非常艰难。这就使得对某些使用情形来说这样做比较困难, 比如需要支持种类很多的软件包的桌面工作站。

更新和添加安全补丁

为了让系统尽可能保持安全,您需要及时了解用于您的软件的新修订和补丁。这些信息可以通过若干个渠道得到,不过,通常软件 提供商和 Linux 发行商应该为您及时地提供这些信息。您也可以使用(几乎永远免费)CERT(Computer Emergency Response Team) 的服务。他们通常会维持传达关于最新的建议、漏洞等信息的邮件列表。

当有新的更新可用时,您应该去查看它是否适用于您的系统以及您的安全需要。安装更新本身可能会导致安全问题。 另外,要考虑到每个更新都可能会引入新的漏洞,或者如果更新失败,您的系统可能会停留在不可用的状态。

当在大范围的系统中安装某个更新时,您通常不能同时对它们全部进行更新 —— 这可能会导致您的多个系统在更新期间 互相不兼容。

可见,更新系统会涉及到很多风险。这里是降低这些风险的一些建议:

  • 初始安装后,不要将您的系统立即连接到网络。将所有相关的更新下载到一台单独的机器,然后手工地传输它们, 以确保系统在暴露在网络上之前已经处于当前状态(current state)。
  • 始终拥有可用的近期系统备份。
  • 对于业务中每一个关键的系统,您都应该有一个与产品环境的硬件和软件相同的独立测试环境。 首先在测试环境中获得关于更新的经验,以防止在管理产品系统时出现意外。
  • 理想情况下,您应该已经准备好一套回归测试,在更新包括系统在内的所有程序之前和之后对适当的功能和性能进行对比。 至少,要确保拥有可重复的而且文档化的质量控制检查,以保证在修改产品环境之前测试环境中的主要功能和服务不会 受到影响。
  • 对于小型网络来说,手工安装更新或许可行,但规模较大时很快就难以处理了。这经常会导致更新不能被安装。 使用商业的或者开放源代码的系统管理或者软件分发工作来简化更新的部署。
  • 我们是不是提醒过您最好在手边准备一个备份?我们还要再提醒一次。
  • 制定一个安装更新的计划,并考虑:
    • 更新系统的次序
    • 对您的业务来说关键的系统
    • 系统如何互相依赖
    • 哪个系统包含机密数据
  • 当使用完整性检查工具时(强烈建议至少对服务器使用),为了能识别出意外的更改,要记得更新系统 在已知安全状态下占用内存的基线。
  • 在安装任何修订之前,要使用密码检验和工具检查软件的完全性和真实性(尤其是从 Web 站点或者 ftp 服务器 上下载时)。在 Linux 领域中,通常使用 MD5 和/或 SHA-1 检验和。如果软件以 RPM 包的形式提供,那么提供 商应该已经提供了一个 GnuPG 签名。您可以运行 $ rpm -v --checksig <name>.rpm 命令来检查它。成功的响应应该是 "<name>.rpm: md5 gpg OK"; 不成功的会是 "<name>.rpm: md5 GPG NOT OK"。 您可以使用 $ md5sum <name>.rpm 或 $ sha1sum <name>.rpm 来确认 MD5 或 SHA-1 检验和。 如果您下载的某个文件中包含的检验和可用于多个文件(大部分情况下称为 md5sum.asc 或 <name>.md5), 那么您可以使用 $ md5sum -c md5sum.asc
  • 最后,但不是最不重要的是,要备份您的系统。

将您的安全计划付诸实行

如本系列 第 2 部分 中所讨论的, 现在来将文档化的安全计划应用到已经安装的系统。弄清楚哪些进程正在您的系统中实际地运行,并禁用不需要的那些。 要定期地检查不正常的行为;未知的进程可能会提供不必要的服务,预示着系统的受损。

本节向您介绍如何找出并禁用那些不必要的(潜在危险)进程,以及如何为系统准备定期审计。

找出并禁用不必要的进程

理想情况下,您应该明白在您的系统中运行的每一个进程。要获得所有进程的列表,可以执行命令 ps -ef(POSIX 风格)或 ps ax(BSD 风格)。 进程名有方括号的是内核级的进程,执行辅助功能(比如将缓存写入到磁盘);所有其他进程都是使用者进程。 您会注意到,就算是在您新安装的(最小化的)系统中,也会有很多进程在运行。熟悉它们,并把它们记录到 文档中。

现在让我们来看那些开放网络连接的进程;它们受到攻击的潜在可能最大。要获得所有 TCP 或 UDP 连接的列表,执行命令netstat -atu(附带名字解析,易读)或者 netstat -atun (没有名字解析,更快)。在这个列表中,特别要注意状态为 LISTEN 的 TCP 连接和 所有的 UDP 连接,因为服务器通过这些连接来接收到来的连接。

如果服务器侦听 127.0.0.1/localhost,那么它只能由系统本身(环回接口)访问到。因此它的暴露程度要远 低于侦听外部可达接口甚至 0.0.0.0(= *,如果打开名字解析)的服务器,后者可以由任意网络接口所访问。

如果您使用过 netstat -atun,那么您需要自己翻译端口号。 可以在 /etc/services 中去查找它们。使用附加的参数 -p 来显示 相应的进程,如 下 所示。

使用 netstat 来显示进程在这个示例中,您可以推断出 portmapper 和 graphical user interface(X)是特定的服务器所不需要的。portmapper 为 NFS 等各种基于 RPC 的服务提供标准端点(endpoint);系统并不提供 NFS 共享。当系统用作工作站时 X 窗口是 有用的,但在服务器上的使用受限。

确定这些进程是如何被启动的(通过 /etc/inittab,通过引导脚本,等等)并如前所述的那样禁用它们。 如果程序是由另一个程序启动的,那么这项任务可能会更具挑战性:X 服务器很有可能是由显示管理器 启动的,比如 xdm、kdm 或 gdm,其本身并不会出现在 inittab 或引导脚本目录中。

netstat 所列出的连接并不是自动都可以由网络上的所有计算机来使用。在任何数据包到达开放的连接之前, 基于 Linux 内置功能的防火墙可以进一步控制访问。

审计准备

安装了基本的系统并安全地配置后,您的最终目标是保持系统的安全。为了识别出对系统的不必要修改,使用审计工具来 记录处于希望是已知且安全的状态的系统的内存占用,并检测对它的修改。

猜你喜欢

转载自blog.csdn.net/wz_cow/article/details/82050648