16.2.简介 ========= 安全是每个人的责任。任何系统中的弱入口点都可能允许入侵者并访问关键信息,并对整个网络造成严重破坏。信息安全的核心原则之一是 CIA 三位一体,它代表信息系统的机密性(Confidentiality),完整性(Integrity)和可用性(Availability)。 CIA 三位一体是计算机安全的基本概念,因为客户和用户希望他们的数据受到保护。例如,客户希望其信用卡信息被安全存储(机密性),他们的订单不会在幕后更改(完整性),并且他们可以随时访问其订单信息(可用性)。 为了保证 CIA,专业安全人员应用了纵深防御策略。纵深防御策略的思想是多增加几层安全层,以防止单一层失效导致整个安全系统崩溃。例如,系统管理员不能简单地打开防火墙就认为网络或系统是安全的。还必须审计帐户,检查二进制文件的完整性,并确保没有安装恶意工具。要实施有效的安全战略,必须了解威胁以及如何防范它们。 什么是与计算机安全有关的威胁?威胁不仅限于试图在未经许可的情况下从远程位置访问系统的远程攻击者。威胁还包括员工、恶意软件、未经授权的网络设备、自然灾害、安全漏洞,甚至是竞争对手。 系统和网络可能在未经许可的情况下被访问,有时是意外,有时则是被远程攻击者访问,在某些情况下,通过企业间谍活动或前雇员访问。作为用户,重要的是准备和承认当一个错误导致了安全漏洞时,并向安全团队报告可能存在的问题。作为管理员,重要的是了解威胁并准备好缓解它们。 在对系统进行安全防护时,建议从保护基本帐户和系统配置开始,然后保障网络层的安全,使其符合系统安全策略和组织的安全程序。许多组织已经制定了涵盖技术设备配置的安全策略。该策略应包括工作站、台式机、移动设备、电话、生产服务器和开发服务器的安全配置。在许多情况下,标准操作程序(SOP)已经存在。当有疑问时,请询问安全团队。 本节的其余部分介绍了如何在 FreeBSD 系统上执行这些基本安全配置。本章的其余部分介绍了在 FreeBSD 系统上实施安全策略时可以使用的一些具体工具。 16.2.1.阻止登录 --------------- 在确保系统安全方面,对账户进行审计是一个好的开始。确保 ``root`` 账户有一个健壮的密码,并且这个密码未被共享。禁用任何不需要登录权限的账户。 拒绝账户的登录访问有两种方法。第一种是锁定账户。以下是锁定 ``toor`` 账户的示例: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # pw lock toor 第二种方法是通过将其 shell 更改为 **/usr/sbin/nologin** 来阻止登录访问。只有使用超级账户可以为其他用户更改 shell: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # chsh -s /usr/sbin/nologin toor **/usr/sbin/nologin** 这个 shell 可以阻止系统在用户试图登录时为其分配 shell。 16.2.2.帐户升级权限 ------------------- 在某些情况下,需要与其他用户共享系统管理。FreeBSD 上有两种方法可以实现。第一种方法(不推荐使用)是采用 ``wheel`` 组成员共同使用 ``root`` 密码。使用此方法时,用户在需要超级用户访问时键入 ``su`` 并输入 ``wheel`` 的密码。在完成需要管理权限的命令后,用户应该键入 ``exit`` 来退出用户共享。如需将一个用户添加到这个组中,请编辑 **/etc/group** 并将该用户添加到 ``wheel`` 条目的末尾。该用户必须用逗号字符隔开,不能有空格。 第二种方法,也是推荐的方法是通过二进制包或 port 安装 `security/sudo `__\ 。该软件能提供额外的审计,更细粒度的进行用户控制,并且可以为锁定用户配置只能执行某个特定需要权限的命令。 安装后,使用 ``visudo`` 来编辑 **/usr/local/etc/sudoers**\ 。下面的示例创建了一个新的 ``webadmin`` 组,将 ``trhodes`` 账户加入该组,并配置该组的访问权限——可以重新启动 `apache24 `__\ : .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # pw groupadd webadmin -M trhodes -g 6000 # visudo %webadmin ALL=(ALL) /usr/sbin/service apache24 * 16.2.3.哈希密码 --------------- 密码是技术的必要之恶。当必须使用时,它们应该很复杂,并且应该使用强大的哈希机制来加密存储在密码数据库中的密码。FreeBSD 在其 ``crypt()`` 库中支持 DES、MD5、SHA256、SHA512 和 Blowfish 哈希算法。不应该将默认的 SHA512 改成安全性较低的哈希算法,但可以改成安全性更高的 Blowfish 算法。 **注意** **Blowfish 算法不是 AES 的一部分,通常被认为不符合联邦信息处理标准(FIPS)。在某些环境中可能不允许使用它。** 为了确定用来加密用户的密码使用了哪个哈希算法。超级用户可以在 FreeBSD 密码数据库中查看用户的哈希值。每个哈希值以一个符号开始,表示用于加密密码的哈希机制的类型。如果使用的是 DES,则没有开头符号。对于 MD5, 符号是 ``$``\ 。对于 SHA256 和 SHA512, 符号是 ``6$``\ 。对于 Blowfish,符号是 ``2a$``\ 。在下面的例子中,\ ``dru`` 的密码是用默认的 SHA512 算法散列的,因为哈希值以 ``$6$`` 开始。请注意,密码是以加密的哈希值的形式存储在密码数据库中。 .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # grep dru /etc/master.passwd dru:$6$pzIjSvCAn.PBYQBA$PXpSeWPx3g5kscj3IMiM7tUEUSPmGexxta.8Lt9TGSi2lNQqYGKszsBPuGME0:1001:1001::0:0:dru:/usr/home/dru:/bin/csh 哈希机制是在用户的登录分级中设置的。在下面的例子中,用户是在 ``default`` 登录分级中,哈希算法是通过 **/etc/login.conf** 中的下面的配置进行配置的: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session :passwd_format=sha512:\ 假如要将加密算法更改为 ``Blowfish``\ ,请将该行修改为如下所示: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session :passwd_format=blf:\ 然后按照\ `配置登录分级 `__ 中所述运行 ``cap_mkdb /etc/login.conf``\ 。注意,此更改不会改变任何现有的哈希密码。这意味着所有密码都应通过要求用户运行 ``passwd`` 来更改他们的密码散列值。 对于远程登录,应使用双重认证(2FA)。一个双重认证的示例是“你拥有的东西”(如密钥)和“你知道的内容”(如该密钥的密码)。由于 OpenSSH 是 FreeBSD 基础系统的一部分,因此所有网络登录都应该通过加密连接,并使用基于密钥的身份验证而非密码。有关更多信息,请参阅 `OpenSSH `__\ 。Kerberos 用户可能需要进行其他更改才能在其网络中实现 OpenSSH。在 `Kerberos `__ 中对有关的内容进行了说明。 16.2.4.密码策略实施 ------------------- 对本地帐户强制实施强密码策略是系统安全的一个基本方面。在 FreeBSD 中,密码长度、密码强度和密码复杂性可以通过内置的可插拔认证模块(PAM)来实现。 本节演示了如何使用 **pam_passwdqc.so** 模块进行最小和最大密码长度以及混合字符强制执行的配置。当用户更改其密码时,将强制执行此模块。 要配置此模块,请以超级用户权限取消 **/etc/pam.d/passwd** 中包含 ``pam_passwdqc.so`` 所在行的注释。然后,编辑该行以匹配密码策略: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session password requisite pam_passwdqc.so min=disabled,disabled,disabled,12,10 similar=deny retry=3 enforce=users 本示例为新密码设置了多个要求。\ ``min`` 设置控制最小密码长度。它有五个值,因为此模块根据其复杂性定义了五种不同类型的密码。复杂性由密码中必须存在的字符类型(如字母、数字、符号和大小写)定义。密码类型在 `pam_passwdqc(8) `__ 中进行了说明。在此示例中,前三种类型的密码被禁用,这意味着满足这些复杂性要求的密码将不被接受,无论其长度如何。\ ``12`` 设置了一个最小的密码策略,即如果密码也包含有三种类型的复杂性的字符,则至少要有 12 个字符。\ ``10`` 设置了密码策略,如果密码包含有四种类型的复杂性的字符,则也允许至少十个字符的密码。 ``similar`` 设置拒绝与用户之前的密码相似的密码。\ ``retry`` 设置为用户提供了三次输入新密码的机会。 保存此文件后,更改密码的用户将看到类似于以下内容的信息: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session % passwd Changing local password for trhodes Old Password: You can now choose the new password. A valid password should be a mix of upper and lower case letters, digits and other characters. You can use a 12 character long password with characters from at least 3 of these 4 classes, or a 10 character long password containing characters from all the classes. Characters that form a common pattern are discarded by the check. Alternatively, if no one else can see your terminal now, you can pick this as your password: "trait-useful&knob". Enter new password: 如果输入的密码与策略不匹配,将被拒绝并发出警告,用户可重试,重试次数不超过配置的次数。 大多数密码策略要求密码在多少天后失效。在 FreeBSD 中设置密码时间,在 **/etc/login.conf** 中为用户的登录分级设置 ``passwordtime``\ 。\ ``default`` 登录分级包含一个示例: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # :passwordtime=90d:\ 因此,要将此登录类的有效期设置为 90 天,请删除注释符号(#),保存编辑,然后运行 ``cap_mkdb /etc/login.conf``\ 。 要设置单个用户的过期时间,需要传递过期日期或过期天数以及用户名给 ``pw``\ : .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # pw usermod -p 30-apr-2015 -n trhodes 如此处所示,到期日期以日、月和年的形式设置。有关更多信息,请参见 `pw(8) `__\ 。 16.2.5.Rootkit 检测 ------------------- 任何未经授权的试图获得系统 ``root`` 权限的软件都是 *rootkit*\ 。在安装后,这种恶意软件通常会给攻击者开辟另一条进入途径。现实中,一旦系统被 rootkit 入侵并进行了踩点,该系统就应该从头开始重新安装。即使是最谨慎的安全或系统工程师,也会有极大的风险遗漏攻击者留下的东西。 rootkit 对管理员来说有一个作用:一旦发现,即表明某处已被渗透。但是,此类的应用程序往往隐藏得非常好。本节展示了一个可以用来检测 rootkit 的工具——`security/rkhunter `__\ 。 在通过二进制包或 port 安装此软件后,可使用以下命令检查系统。它将产生大量信息,并且需要手动按下\ ``回车键``\ : .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # rkhunter -c 该过程完成后,一条状态信息将被打印到屏幕上。该信息将包括检查的文件数量、可疑文件、可能的 rootkit 等等。在检查过程中,可能会产生一些关于隐藏文件、OpenSSH 协议选择和已安装软件的已知脆弱版本的通用安全警告。可以立即处理这些问题,也可以在进行了更详细的分析后处理。 每个管理员都应该知道他们所负责的系统上正在运行什么。第三方工具(如 rkhunter 和 `sysutils/lsof `__\ )以及本地命令如 ``netstat`` 和 ``ps``\ ,可以显示大量的系统信息。记下什么是正常的,当有什么东西看起来不对劲的时候要问清楚,并且要多疑。虽然预防入侵是理想的,但检测入侵是必须的。 16.2.6.二进制验证 ----------------- 对系统文件和二进制文件进行验证非常重要,因为它为系统管理和安全团队提供了有关系统变化的信息。监控系统变化的软件应用程序被称为入侵检测系统(IDS)。 FreeBSD 为基本的 IDS 系统提供了原生支持。虽然每晚的安全邮件会通知管理员更改的信息。但这些信息是存储在本地的。恶意用户有可能会修改这些信息以隐藏他们对系统的更改。因此,建议创建一套单独的二进制签名,并将其存储在一个只读的、root 拥有的目录下,或者最好是存储在可移动的优盘或远程 rsync 服务器上。 内置的 ``mtree`` 工具可以用来生成一个目录内容的规范。使用一个种子,或一个数字常数来生成规范,并被要求检查规范是否已经改变。这使得确定一个文件或二进制文件是否被修改成为可能。由于种子值对攻击者来说是未知的,伪造或检查文件的校验值将很难甚至不可能。下面的例子生成了一组 SHA256 哈希值,为 **/bin** 中的每个系统二进制文件都会生成一个,并将这些值保存在 ``root`` 的主目录下的一个隐藏文件中,即 **/root/.bin_chksum_mtree**\ 。 .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # mtree -s 3483151339707503 -c -K cksum,sha256digest -p /bin > /root/.bin_chksum_mtree # mtree: /bin checksum: 3427012225 *3483151339707503* 代表种子。应记住此值,但不要共享此值。 查看 **/root/.bin_cksum_mtree** 应生成类似于以下内容的输出: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # user: root # machine: dreadnaught # tree: /bin # date: Mon Feb 3 10:19:53 2014 # . /set type=file uid=0 gid=0 mode=0555 nlink=1 flags=none . type=dir mode=0755 nlink=2 size=1024 \ time=1380277977.000000000 \133 nlink=2 size=11704 time=1380277977.000000000 \ cksum=484492447 \ sha256digest=6207490fbdb5ed1904441fbfa941279055c3e24d3a4049aeb45094596400662a cat size=12096 time=1380277975.000000000 cksum=3909216944 \ sha256digest=65ea347b9418760b247ab10244f47a7ca2a569c9836d77f074e7a306900c1e69 chflags size=8168 time=1380277975.000000000 cksum=3949425175 \ sha256digest=c99eb6fc1c92cac335c08be004a0a5b4c24a0c0ef3712017b12c89a978b2dac3 chio size=18520 time=1380277975.000000000 cksum=2208263309 \ sha256digest=ddf7c8cb92a58750a675328345560d8cc7fe14fb3ccd3690c34954cbe69fc964 chmod size=8640 time=1380277975.000000000 cksum=2214429708 \ sha256digest=a435972263bf814ad8df082c0752aa2a7bdd8b74ff01431ccbd52ed1e490bbe7 此报告中包括计算机的主机名、创建规范的日期和时间以及创建规范的用户的名称。目录中的每个二进制文件都有一个校验和、大小、时间和 SHA256 摘要。 为了验证二进制签名没有变化,将目录中的当前内容与先前生成的规范进行比较,并将结果保存到文件中。这个命令需要用来生成原始规范的种子: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # mtree -s 3483151339707503 -p /bin < /root/.bin_chksum_mtree >> /root/.bin_chksum_output # mtree: /bin checksum: 3427012225 这应产生与创建规范时相同的 **/bin** 的校验和。如果这个目录中的二进制文件没有发生变化,那么 **/root/.bin_chksum_output** 输出文件将是空的。为了模拟变化,用 touch 改变 **/bin/cat** 的日期,然后再次运行验证命令。 .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # touch /bin/cat # mtree -s 3483151339707503 -p /bin < /root/.bin_chksum_mtree >> /root/.bin_chksum_output # more /root/.bin_chksum_output cat changed modification time expected Fri Sep 27 06:32:55 2013 found Mon Feb 3 10:28:43 2014 建议为包含二进制文件和配置文件的目录以及包含敏感数据的任何目录都创建规范。一般可为 **/bin、/sbin**\ 、\ **/usr/bin**\ 、\ **/usr/sbin、**/**usr/local/bin、/etc** 和 **/usr/local/etc** 创建规范。 还有更高级的 IDS 系统存在,例如 `security/aide `__\ 。在大多数情况下,\ ``mtree`` 提供了管理员需要的功能。保持种子值和校验输出不被恶意用户发现是很重要的。关于 ``mtree`` 的更多信息可以在 `mtree(8) `__ 中找到。 16.2.7.系统安全优化 ------------------- 在 FreeBSD 中,许多系统特性都可以使用 ``sysctl`` 进行调整。本节将介绍一些可以优化以阻止拒绝服务(DoS)攻击的安全功能。关于使用 ``sysctl`` 的更多信息,包括如何临时改变数值,以及如何在测试后使改变永久化,请参阅 `“使用 sysctl(8) 进行优化” `__\ 。 **注意** 任何时候用 ``sysctl`` 改变一个设置,都会使造成不想要的伤害的可能性上升,影响系统的可用性。应该监控所有的改变,如果可能的话,在生产系统上使用之前,应该在测试系统上进行测试。 默认情况下。FreeBSD 内核启动时的安全级别为 ``-1``\ 。这被称为“不安全模式”。因为不可变的文件标志可以被关闭,所有设备都可以被读出或写入。除非通过 ``sysctl`` 或启动脚本的设置来改变安全级别,否则安全级别将保持为 ``-1``\ 。通过在 **/etc/rc.conf** 中设置 ``kern_securelevel_enable`` 为 ``YES``\ ,并将 ``kern_securelevel`` 的值设为所需的安全级别,可以在系统启动时提高安全级别。参见 `security(7) `__ 和 `init(8) `__ 以了解更多关于这些设置和可用安全级别的信息。 **警告** 提升 ``securelevel`` 可能会破坏 Xorg 并造成其他问题。应该准备好做一些调试工作。 ``net.inet.tcp.blackhole`` 和 ``net.inet.udp.blackhole`` 设置可以用来在关闭的端口上丢弃传入的 SYN 数据包,而不发送返回的 RST 响应。默认行为是返回 RST 以显示一个端口已关闭。更改默认值可提供针对端口扫描的某种级别的保护,用于确定系统上运行的应用程序。将 ``net.inet.tcp.blackhole`` 设置为 ``2``\ ,将 ``net.inet.udp.blackhole`` 设置为 ``1``\ 。请参考 `blackhole(4) `__\ 以了解关于这些设置的更多信息。 ``et.inet.icmp.drop_redirect`` 和 ``net.inet.ip.redirect`` 设置有助于防止 *重定向攻击*\ 。重定向攻击是 DoS 的一种类型,它发送大量的 ICMP 类型 5 数据包。由于不需要这些数据包,请将 ``net.inet.icmp.drop_redirect`` 设置为 ``1``\ ,将 ``net.inet.ip.redirect`` 设置为 ``0``\ 。 源路由是一种检测和访问内部网络中不可路由的地址的方法。应该禁用他,因为不可路由的地址通常都是故意不可路由的。要禁用这个功能,请将 ``net.inet.ip.sourceroute`` 和 ``net.inet.ip.accept_sourceroute`` 设置为 ``0``\ 。 当网络上的一台机器需要向子网中的所有主机发送消息时,会向广播地址发送一个 ICMP 回声请求消息。然而,外部主机没有理由进行这样的操作。要拒绝所有的外部广播请求,把 ``net.inet.icmp.bmcastecho`` 设置为 ``0``\ 。 另外 `security(7) `__ 中记录了一些其他设置。