Security (简体中文)

From ArchWiki
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
翻译状态:本文是 Security翻译。上次翻译日期:2019-02-04。如果英文版本有所更改,则您可以帮助同步翻译。

本文包含了 加固 Arch Linux 系统的常用建议与最佳实践。

概念

  • 收紧安全措施有可能达到使系统无法使用的程度。安全性与便利性需要得到平衡。诀窍在于建立一个安全且有用的系统。
  • 最大的威胁是(并且一直都会是)用户。
  • 最小权限原则:系统的每一部分应该只能访问到它确实需要的东西,除此之外的则不可以。
  • 纵深防御:多个独立的层次能带来更好的安全性。当一层防护被攻破时,另一层应该能够阻止攻击。
  • 保持一点点的偏执和多疑。如果有件事看起来太好了,不像是真的,那可能确实如此。
  • 永远无法令系统 100% 安全,除非把机器从网络上断开,关掉电源,锁进保险柜,用混凝土封住并不再使用它。
  • 为失败做好准备。预先为安全措施被攻破的情况制定可供执行的计划。

密码

密码是一个安全 Linux 系统的关键。它可以保护你的用户账户加密的文件系统SSH/GPG 密钥。密码也是让计算机信任使用者的主要方式,所以安全问题的一大部分在于如何选择高强度的密码并保护它们不被泄露。

选择安全的密码

密码必须足够复杂,不能轻易地被猜中(比如和个人信息有关的密码),也不能轻易地被社会工程或暴力尝试等方法 破解。强密码的要点在于 长度随机性。在密码学中,密码的质量被称为它的 熵安全性

不安全的密码包括:

  • 个人可识别信息(如:狗的名字,出生日期,区号,最喜欢的视频游戏)
  • 对单词简单地替换一些字符(如:k1araj0hns0n),因为现代字典攻击可以轻松对付它们
  • 在基本单词或常见字符串的前后加上数字,符号或其他字符(如:DG091101%
  • 常见句子或词典中单词的序列(如:photocopyhauntbranchexpose),包括对其字符进行替换(如:Ph0toc0pyh4uN7br@nch3xp*se
  • 任何一个最常见的密码

最好的选择是由随机来源生成的长密码(越长越好)。使用长密码很重要。弱哈希算法会使得一个8字符密码的哈希值在几小时之内便被攻破。

有个方法可以产生安全性好的、看起来随机的密码,那就是从一句句子的每一个词中提炼出一个符号。 例如 “the girl is walking down the rainy street” 这句话可以转换为 t6!WdtR5 或是更加复杂的 t&6!RrlW@dtR,57。 这种方法可以更为简单地帮助记忆密码,但是请注意,不同字母出现在单词开头的概率不同 (Wikipedia:Letter frequency)。同时也要考虑 Diceware Passphrase[失效链接 2021-05-17 ⓘ] 中提到的方法,使用足够数量的单词。

更好的方法是使用 pwgenapgAUR 等工具生成伪随机密码:为了记住它们,一种方法(仅针对经常输入的密码)是生成一个长密码并记住一小段(这一小段要能保证最低限度的安全),暂时把完整的密码写下来。随着时间推移,输入次数增加,密码会随着肌肉记忆根深蒂固。这种方法很难,但是能保证密码不会出现在破解用的字典里,也可以抵御能“智能地”组合单词并替换部分字符的暴力破解。

将生成与记忆密码两者结合的 密码管理器 也很有用,它可以保存长而复杂的随机密码,同时被一个方便记忆的主密码保护着。该密码必须仅用于此密码管理器,特别注意要避免保存或通过任何网络传输这个密码。当然这个方法限制了只能从存有密码库的电脑上使用已保存的密码(另一方面,这也可以视为额外的安全特性)。一些密码管理器也提供智能手机应用,可以显示密码,以便在没有安装密码管理器的系统上手动输入。需要注意,一旦忘记主密码,密码管理器就引入了单点故障。

从前,使用一长串相互无关的单词作为密码是很有效的方法。原理在于,如果使用足够长的短语,密码长度所带来的熵就可以抵消使用字典单词所失去的熵。这个 XKCD 漫画描绘了此方法中对于熵的权衡。然而,密码破解者已经知道了这一技巧,所生成的单词表包含字典单词的数十亿种排列与变种,从而降低了这种密码的等效熵。

可以看下 Bruce Schneier 的文章 Choosing Secure PasswordsThe passphrase FAQWikipedia:Password strength 获取额外背景信息。

维护密码安全

一旦你选择了一个强密码,一定要保证它的安全。当心 键盘记录器(软件或硬件),屏幕记录器,社会工程肩窥,并避免重复使用密码,这样不安全的服务器就无法泄漏超出其范围的信息。密码管理器 可以帮助管理大量复杂密码:将密码从管理器复制粘贴到其他程序中时,请确保每次粘贴完都清除复制缓冲区,并确保它们不会保存在日志记录里面(例如,不要将它们粘贴在普通的终端命令中,因为这些命令会存到 .bash_history 等文件里)。

最好不要因为安全性强的密码难记而选择不安全的密码,密码是它们之间的一种平衡。与拥有许多相似的弱密码相比,更好的做法是建立一个加密的安全密码数据库,数据库由密钥和一个强主密码保护着。把密码写下来可能同样有效[1],这样在增加物理安全需求的同时也避开了软件中的潜在漏洞。

衡量密码强度的另一个指标是它不能够被轻易从其他地方恢复。

如果你的登录密码和用于磁盘加密的密码相同(这在登录时自动挂载加密分区或目录很有用),请确保 /etc/shadow 也在加密分区上,或者使用强哈希算法(即 sha512/bcrypt,而不是 md5)来存储密码(详细信息请参阅 SHA password hashes)。

如果要备份密码数据库,请勿将备份的副本存储在密码保护之下(比如存储在加密的驱动器或需要身份验证的远程存储服务),而解锁副本的密码又存储在副本中,这样在需要时将无法访问它(相当于把房间的钥匙锁在了房间里)。一个有用的技巧是,使用主密码的简单哈希来加密存储着密码数据库的驱动器或在线帐户。维护一份记录备份位置的列表:如果有一天觉得主密码被泄露,一是要更改所有数据库备份的密码,二是要使用从新主密码派生的新哈希来保护存有数据库的位置。

以安全的方式控制数据库的版本可能非常复杂:如果你这样做,那你必须有办法更新所有数据库版本的主密码。主密码泄露时情况可能并不能马上清楚:为了降低其他人在你意识到主密码泄露之前发现密码的风险,可以选择定期更改主密码。如果你觉得自己失去了对数据库副本的控制权,则需要在特定时间内更改副本中包括的所有密码,这一特定时间是暴力破解主密码所用的时间,取决于主密码的熵。

密码的散列值

Tango-view-fullscreen.pngThis article or section needs expansion.Tango-view-fullscreen.png

Reason: 提及密钥导出函数,特别是 PBKDF2、bcrypt 和 scrypt,应当提及用法、优缺点,基于定制硬件的暴力攻击应当特别提及。 (Discuss in Talk:Security (简体中文))

默认情况下,Arch 将用户密码散列值存储在仅 root 可读的 /etc/shadow 文件中,与存储在所有人可读的 /etc/passwd 文件中的其他用户参数分开,请参阅 Users and groups (简体中文)#用户信息存储。另请参阅 #限制 root 权限

密码使用 passwd 命令来设置,该命令使用 crypt 函数对密码进行 拉伸,然后将它们保存在 /etc/shadow 中。请参阅 SHA password hashes。密码也被 加盐(salted),以抵御 彩虹表 攻击。

另请参阅 在 Linux 中密码如何存储(理解使用 shadow 工具的散列值化)[失效链接 2021-11-19 ⓘ]

用 pam_pwquality 强制使用强密码

pam_pwquality 提供针对 字典攻击 的保护,并可用于配置在整个系统中实施的密码策略。它基于 pam_cracklib,故也向后兼容其选项。

安装 libpwquality 软件包。

警告: root 账户默认不会受此策略影响。
注意: 可以用 root 帐户来帮助想绕过策略的用户设置他们的密码。这在设置临时密码时很有用。

举个例子,假设要强制执行下面的策略:

  • 如果密码错误,请提示 2 次(retry 选项)
  • 最小长度为10个字符(minlen 选项)
  • 输入新密码时,新密码应至少有 6 个字符与旧密码不同(difok 选项)
  • 至少 1 个数字(dcredit 选项)
  • 至少 1 个大写字母(ucredit 选项)
  • 至少 1 个小写字母(lcredit 选项)
  • 至少 1 个除上述之外的其他字符(ocredit 选项)
  • 不能包含单词 "myservice" 和 "mydomain"
  • 为 root 应用此策略

编辑 /etc/pam.d/passwd 文件,把它改成:

#%PAM-1.0
password required pam_pwquality.so retry=2 minlen=10 difok=6 dcredit=-1 ucredit=-1 ocredit=-1 lcredit=-1 [badwords=myservice mydomain] enforce_for_root
password required pam_unix.so use_authtok sha512 shadow

password required pam_unix.so use_authtok 用来告诉 pam_unix 模块不要显示输入密码的提示符,而采用 pam_pwquality 所提供的。

更多信息可以参考 pam_pwquality(8)pam_unix(8) 手册页。

CPU

微码

关于如何为CPU微码安装重要安全更新的信息见微码

硬件漏洞

有些 CPU 存在硬件漏洞。这些漏洞的列表见关于硬件漏洞的 Linux 内核文档,其中也包含了修补方法选择指南,有助于针对特定使用场景自定义内核,从而修补这些漏洞。

要检查是否受到已知漏洞影响,请运行:

$ grep -r . /sys/devices/system/cpu/vulnerabilities/

大部分情况下,更新内核和微码能够修补漏洞。

同步多线程(超线程)

同步多线程(SMT),在英特尔 CPU 上又称超线程,这一硬件功能可能是 L1 Terminal Fault微架构数据采样(Microarchitectural Data Sampling) 漏洞的来源。 Linux 内核和微码更新含有针对已知漏洞的补丁,但是如果存在不受信任的虚拟化客户机,则对于某些 CPU 可能仍然需要禁用 SMT

SMT 往往可以在系统固件中关闭。更多信息见主板或系统文档。通过添加以下内核参数,也可以在内核中禁用 SMT:

l1tf=full,force mds=full,nosmt mitigations=auto,nosmt nosmt=force

存储

磁盘加密

进行磁盘加密时最好使用强密码进行全盘加密,这是保护数据免受物理恢复的唯一方法。这也可以在计算机关闭或相关硬盘卸载时充分保护数据安全。

当然,一旦计算机启动,磁盘挂载完毕,这些数据就像存储在未加密的磁盘上一样易受攻击。因此,最佳做法是在不需要用到数据分区时立即卸载它们。

部分程序,比如 dm-crypt,允许用户加密 Loop 文件并将其作为虚拟卷使用。当系统只有特定的部分需要加密时,这种方法可以替代全盘加密。

文件系统

如果用 sysctl 启用了内核的 fs.protected_hardlinksfs.protected_symlinks 选项,内核就可以防止出现硬链接和软链接(符号链接)相关的安全问题。因此将全局可写的目录独立出来不再具有安全方面的优势。

包含全局可写目录的文件系统仍然可以作为一种防止磁盘空间耗尽的粗略手段。但是,把 /var/tmp 所在分区塞满也足以使系统停止响应。处理这种问题的更灵活的机制是存在的(比如 磁盘配额),并且某些 文件系统 自身就带有相关功能(Btrfs 的子卷可以设置配额)。

挂载点

根据最小权限原则,挂载文件系统时应该采用最为严格的挂载选项(在不损失功能的情况下)。

相关的挂载选项有:

  • nodev: 文件系统中,禁止解释任何字符或屏蔽特殊设备。
  • nosuid: 禁止 set-user-identifier 或 set-group-identifier 标志位生效。
  • noexec: 禁止文件系统里的任何二进制文件直接运行。
    • /home 上设置 noexec 选项会禁用可执行脚本,影响 Wine* 、PyCharm 和 Steam 等正常运行。
    • 部分软件包(比如编译 nvidia-dkms)可能需要 /varexec 权限。
注意: Wine 运行 Windows 应用时不需要 exec (可执行)标识,仅在 Wine 自身安装在 /home 时需要。

用于存放数据的文件系统应该坚持使用 nodevnosuidnoexec 挂载。

可能的文件系统划分参考:

  • /var
  • /home
  • /dev/shm
  • /tmp
  • /boot

文件访问权限

默认的 文件权限 对几乎所有文件都赋予了读权限,修改文件权限可以在取得了非 root 账户(如httpnobody 账户)的攻击者面前隐藏有价值的信息。

例如:

# chmod 700 /boot /etc/{iptables,arptables}

可以修改默认的 Umask 0022 来为新建的文件提高安全性。NSA RHEL5 安全指南建议将 umask 设置为 0077 以获得最充分的安全性,这将使得新文件无法被创建者之外的用户读取。要修改 umask,参见 Umask#Set the mask value

账户设置

不要日常使用 root 账户

根据最小权限原则,不要日常使用 root 账户。给每个使用系统的人建立一个没有特权的用户账户。必要时使用 Sudo 临时以高权限访问。

在失败的登录尝试后强制延时一段时间

将下方的行添加至 /etc/pam.d/system-login 即可在失败的登录尝试后延时至少 4 秒:

/etc/pam.d/system-login
auth optional pam_faildelay.so delay=4000000

4000000 是延时的微秒数。

在三次登录尝试失败后封锁用户

pambase 20200721.1-2时,pam_faillock.so 默认启用,在15分钟内3次失败的登录尝试之后会封锁用户10分钟(见 FS#67644)。这一封锁只适用于密码认证(如登陆及 sudo),通过 SSH 的公钥认证仍然会被接受。为防止彻底拒绝服务,该封锁对于 root 禁用。

要解锁用户,执行:

$ faillock --reset --user username

默认情况下,封锁机制为每个用户一个文件,位于 /run/faillock/。删除或清空此文件及可解锁该用户——该目录是由 root 所有,但文件是由该用户所有,故 faillock 命令只会清空文件,因此并不需要 root。

pam_faillock.so 模块可通过文件 /etc/security/faillock.conf 配置。封锁参数:

  • unlock_time — 封锁时间(单位为秒,默认10分钟)。
  • fail_interval — 导致封锁的失败尝试时间范围(单位为秒,默认15分钟)。
  • deny — 封锁前允许的登录失败次数(默认为3)。
注意: deny = 0 会禁用封锁。

更改无需重启即可生效。更多配置选项见 faillock.conf(5) ,如启用 root 账户封锁、在中心化登录(如 LDAP)情况下禁用等。

限制进程数量

在有很多用户或存在不可信用户的系统上,限制每个用户同时可运行的进程数很重要,这样可以防止 fork bombs 以及其他拒绝服务攻击。/etc/security/limits.conf 决定了每个用户或组可以运行的进程数,默认情况下为空(除了有用的注释)。将以下行添加到此文件将限制所有用户每位最多运行 100 个活动进程,除非他们使用 prlimit 命令将此次会话的最大值显式地提高到 200。可以根据用户应当运行的进程数量或当前管理的系统的硬件条件来确定这些值。

* soft nproc 100
* hard nproc 200

当前每个用户运行的进程数量可以使用 ps --no-headers -Leo user | sort | uniq -c 查看。这可以帮助确定合适的进程限额。

非 root 运行 Xorg

由于其架构和过时的设计,Xorg 通常 被认为是不安全的。因此建议避免以 root 身份运行它。

有关如何在没有 root 权限的情况下运行 Xorg 的详细信息,请参阅 Xorg (简体中文)#没有 root 权限的 Xorg。或者使用 Wayland 代替 Xorg。

限制 root 权限

按照系统的设计,root 用户是系统中最强大的用户。因为这样,有许多方法可以既保持 root 用户的权限,同时限制其造成破坏的能力,或者至少可以追溯 root 用户的操作。

用 sudo 替代 su

Merge-arrows-2.pngThis article or section is a candidate for merging with sudo.Merge-arrows-2.png

Notes: 这是一篇专门说明 sudo 的文章。 (Discuss in Talk:Security (简体中文))

出于 多种原因,使用 sudo 进行特权访问比 su 更好。

  • sudo 记录了普通权限用户运行每个特权命令的日志。
  • root 用户的密码不需要告知每个请求 root 权限的用户。
  • sudo 可以防止用户意外地以 root 身份执行无需该权限的命令,因为 sudo 并没有为 root 创建完整的终端。这符合 最小权限原则

可以为单个用户启用单个程序的 root 权限,而不用为了运行一个程序启用该用户对 root 的完整访问权。例如,要授予用户 alice 对特定程序的访问权限:

# visudo
/etc/sudoers
alice ALL = NOPASSWD: /path/to/program

另外,也可以为所有用户开放单个程序。例如允许以普通用户身份从服务器挂载 Samba 共享:

%users ALL=/sbin/mount.cifs,/sbin/umount.cifs

这将允许 users 组中的所有用户从任何机器 (ALL) 运行此系统的 /sbin/mount.cifs/sbin/umount.cifs 命令。

提示:

visudo 使用指定版本的 nano 而不是 vi

/etc/sudoers
Defaults editor=/usr/bin/rnano

Export # EDITOR=nano visudo 被认为存在严重安全风险,因为任何程序都可以作为 EDITOR

使用 sudo 编辑文件

以 root 身份运行文本编辑器可能会变成安全漏洞,因为许多编辑器可以运行任意 shell 命令或更改正在编辑的文件以外的文件。要避免这一风险,请用 sudoedit filename(等同于 sudo -e filename)编辑文件。这将使用普通用户的权限来编辑文件的副本,在编辑器关闭后会使用 sudo 覆盖原始文件。可以通过设置 SUDO_EDITOR 环境变量来更改所使用的编辑器:

$ export SUDO_EDITOR=vim

也可以使用类似 rvim 这样的编辑器,它功能受限,以便以 root 用户身份安全运行。

限制 root 登录

正确配置 sudo 后,完全的 root 权限就可以被严格限制或停用,且不会损失太多可用性。要禁用 root 而允许使用 sudo,可以运行 passwd -l root

仅允许特定用户

PAMpam_wheel.so 模块可以做到仅允许 wheel 组中的用户使用 su 登录。编辑 /etc/pam.d/su/etc/pam.d/su-l 两份文件,去掉以下行的注释:

# Uncomment the following line to require a user to be in the "wheel" group.
auth		required	pam_wheel.so use_uid

这一行表示只有已经能够运行特权命令的用户才能以 root 用户身份登录。

拒绝 SSH 登录

即使你不想禁止 root 用户在本地登录,也最好 禁止 root 通过 SSH 登录。这样做的目的是在用户可以在远程完全破坏系统之前添加额外的一层安全保护。

强制访问控制

Mandatory access control(MAC, 强制访问控制)是一种安全策略,它与 Arch 以及大部分 Linux 发行版默认使用的 Discretionary access control (DAC, 自主访问控制)有很大的不同。MAC 本质上是对照着一个安全规则集,检查程序的每一个可能对系统造成影响的操作。与 DAC 方式相比,用户不能修改 MAC 的规则集。使用几乎任何强制访问控制系统都将显著提高计算机的安全性,尽管它们的实现方式存在差异。

基于路径的强制访问控制

基于路径的访问控制是一种简单的访问控制形式,它根据文件的路径提供相应的权限。这种方式有个缺点,就是当文件改变路径以后相应的权限并没有随着文件一起移动。从积极的方面来说,基于路径的 MAC 可以在更广泛的文件系统上实现,这与基于标签的另一种可选方案是不同的。

AppArmor 是一个由 Canonical 维护的 MAC 实现,它被看做是 SELinux 的简化版替代方案。

Tomoyo 是另一种提供访问控制的系统,简单而易用。它的使用方式和内部实现都被设计得足够简单,需要的依赖也很少。

基于标签的强制访问控制

基于标签的访问控制意味着每份文件都带有扩展属性用于决定它的安全权限。虽然这类系统应该比基于路径的控制更灵活,但它只适用于支持这些扩展属性的文件系统。

SELinux 是一个基于 NSA 的项目,用于提高 Linux 的安全性。它完整实现了 MAC,将系统用户与角色独立开来。它实现了一个非常强大的多级 MAC 策略,可以在系统扩大和改变得超出其原始配置时也能轻松控制系统。

访问控制表 (ACLs)

Access Control Lists(ACLs,访问控制表)是以某种方式将规则直接附加到文件系统的一种可选方法。ACLs 将程序的实际操作与允许的操作对照,来实现访问控制。

内核加固

内核自我保护 / 漏洞防护

linux-hardened 相较于 linux 使用了 基本内核加固补丁集 和更多安全相关的编译时配置选项。也可以使用自定义编译选项来把握安全性和性能之间的平衡,而不是使用强调安全性的默认选项。

如果你用了内核代码树以外的驱动,比如 NVIDIA,可能会需要切换到它的 DKMS 包。

用户空间 ASLR 比较

linux-hardened 包为用户空间进程提供了改进的 ASLR(Address Space Layout Randomization,地址空间布局随机化)实现。paxtest 命令可用于获取所提供熵的估计值:

64 位进程
linux-hardened
Anonymous mapping randomization test     : 32 quality bits (guessed)
Heap randomization test (ET_EXEC)        : 26 quality bits (guessed)
Heap randomization test (PIE)            : 40 quality bits (guessed)
Main executable randomization (ET_EXEC)  : No randomization
Main executable randomization (PIE)      : 32 quality bits (guessed)
Shared library randomization test        : 32 quality bits (guessed)
VDSO randomization test                  : 32 quality bits (guessed)
Stack randomization test (SEGMEXEC)      : 40 quality bits (guessed)
Stack randomization test (PAGEEXEC)      : 40 quality bits (guessed)
Arg/env randomization test (SEGMEXEC)    : 44 quality bits (guessed)
Arg/env randomization test (PAGEEXEC)    : 44 quality bits (guessed)
Offset to library randomisation (ET_EXEC): 32 quality bits (guessed)
Offset to library randomisation (ET_DYN) : 34 quality bits (guessed)
Randomization under memory exhaustion @~0: 32 bits (guessed)
Randomization under memory exhaustion @0 : 32 bits (guessed)
linux
Anonymous mapping randomization test     : 28 quality bits (guessed)
Heap randomization test (ET_EXEC)        : 13 quality bits (guessed)
Heap randomization test (PIE)            : 28 quality bits (guessed)
Main executable randomization (ET_EXEC)  : No randomization
Main executable randomization (PIE)      : 28 quality bits (guessed)
Shared library randomization test        : 28 quality bits (guessed)
VDSO randomization test                  : 20 quality bits (guessed)
Stack randomization test (SEGMEXEC)      : 30 quality bits (guessed)
Stack randomization test (PAGEEXEC)      : 30 quality bits (guessed)
Arg/env randomization test (SEGMEXEC)    : 22 quality bits (guessed)
Arg/env randomization test (PAGEEXEC)    : 22 quality bits (guessed)
Offset to library randomisation (ET_EXEC): 28 quality bits (guessed)
Offset to library randomisation (ET_DYN) : 28 quality bits (guessed)
Randomization under memory exhaustion @~0: 28 bits (guessed)
Randomization under memory exhaustion @0 : 28 bits (guessed)
32 位进程(运行在 x86_64 内核上)
linux-hardened
Anonymous mapping randomization test     : 16 quality bits (guessed)
Heap randomization test (ET_EXEC)        : 22 quality bits (guessed)
Heap randomization test (PIE)            : 27 quality bits (guessed)
Main executable randomization (ET_EXEC)  : No randomization
Main executable randomization (PIE)      : 18 quality bits (guessed)
Shared library randomization test        : 16 quality bits (guessed)
VDSO randomization test                  : 16 quality bits (guessed)
Stack randomization test (SEGMEXEC)      : 24 quality bits (guessed)
Stack randomization test (PAGEEXEC)      : 24 quality bits (guessed)
Arg/env randomization test (SEGMEXEC)    : 28 quality bits (guessed)
Arg/env randomization test (PAGEEXEC)    : 28 quality bits (guessed)
Offset to library randomisation (ET_EXEC): 18 quality bits (guessed)
Offset to library randomisation (ET_DYN) : 16 quality bits (guessed)
Randomization under memory exhaustion @~0: 18 bits (guessed)
Randomization under memory exhaustion @0 : 18 bits (guessed)
linux
Anonymous mapping randomization test     : 8 quality bits (guessed)
Heap randomization test (ET_EXEC)        : 13 quality bits (guessed)
Heap randomization test (PIE)            : 13 quality bits (guessed)
Main executable randomization (ET_EXEC)  : No randomization
Main executable randomization (PIE)      : 8 quality bits (guessed)
Shared library randomization test        : 8 quality bits (guessed)
VDSO randomization test                  : 8 quality bits (guessed)
Stack randomization test (SEGMEXEC)      : 19 quality bits (guessed)
Stack randomization test (PAGEEXEC)      : 19 quality bits (guessed)
Arg/env randomization test (SEGMEXEC)    : 11 quality bits (guessed)
Arg/env randomization test (PAGEEXEC)    : 11 quality bits (guessed)
Offset to library randomisation (ET_EXEC): 8 quality bits (guessed)
Offset to library randomisation (ET_DYN) : 13 quality bits (guessed)
Randomization under memory exhaustion @~0: No randomization
Randomization under memory exhaustion @0 : No randomization

限制访问内核日志

注意: 这个功能在 linux-hardened 中是默认打开的。

内核日志包含了那些试图利用内核漏洞(如敏感内存地址)的攻击者的有用信息。kernel.dmesg_restrict 标记可以禁止不带 CAP_SYS_ADMIN 能力的进程访问内核日志(默认只有 root 运行的进程带有该能力)。

/etc/sysctl.d/50-dmesg-restrict.conf
kernel.dmesg_restrict = 1

限制访问 proc 文件系统中的内核指针

注意: linux-hardened 默认设置是 kptr_restrict=2 而不是 0

kernel.kptr_restrict 设置为 1 将针对没有 CAP_SYSLOG 的普通用户隐藏 /proc/kallsyms 中的内核符号地址,这使得利用内核漏洞动态解析地址/符号变得更加困难。这对预编译好的 Arch Linux 内核没有多大帮助,因为攻击者可以直接下载到内核包并从那里手动获取符号,但如果你正在编译自己的内核,这可以帮助减轻本地根攻击。这样做以后会影响非 root 用户运行部分 perf 命令(虽然很多 perf 功能本身就需要 root 权限)。更多信息请参见 FS#34323

kernel.kptr_restrict 设置为 2 将隐藏 /proc/kallsyms 中的内核符号地址,而忽略用户的权限。

/etc/sysctl.d/50-kptr-restrict.conf
kernel.kptr_restrict = 1

禁用 BPF 即时编译

Linux 内核有一个功能,就是将 BPF/Seccomp 规则集编译为原生代码来优化性能。net.core.bpf_jit_enable 标志位应设置为 0 以获得最大安全性。

BPF/Seccomp 编译在特定领域中很有用,比如各类动态服务(类似 Mesos 和 Kubernetes 这样的集群管理平台),它通常不适用于桌面用户或静态服务。JIT 编译器为攻击者提供了进行堆喷射攻击 (Heap spraying attack) 的可能性。在这种攻击中,他们用恶意代码填充内核堆,然后利用另一个漏洞执行此代码,比如解除引用一个不正确的函数指针。2018 年早先公布的 幽灵 漏洞,是其最为突出的一次利用过程。

ptrace 的可调用范围

Arch 默认启用了 Yama LSM,提供了 kernel.yama.ptrace_scope 标志位作为开关。默认情况下这个开关是打开的,它可以使得没有 CAP_SYS_PTRACE 能力的进程无法对其作用域之外的其他进程执行 ptrace 调用。虽然许多调试工具需要 ptrace 来实现某些功能,但这一修改显著提高了安全性。如果没有此功能,且不使用命名空间等额外隔离层的情况下,同一用户运行的进程之间基本没有隔离。调试器可以附加到现有进程的能力证明了这个弱点确实存在。

示例:由于上述原因功能受限的程序

注意: 你仍然可以以 root 身份执行这些命令(例如允许某些用户使用 sudo,且无论是否需要密码)。
  • gdb -p $PID
  • strace -p $PID
  • perf trace -p $PID
  • reptyr $PID

隐藏进程

警告:
  • 这可能会导致某些应用程序出现问题,例如在沙盒和 Xorg 中运行的应用程序(请参阅解决方法)。
  • 当所使用的 systemd 版本大于 237.64-1 时,这可能会导致 D-BusPulseAudiobluetooth 出现问题。

其他用户的进程通常可以在 /proc 访问到,而内核有能力向非特权用户隐藏这些进程,按照 此处 记录的方法以 hidepid=gid= 选项挂载 proc 文件系统即可。

这使得入侵者收集正在运行的进程信息变得异常艰难,同样艰难的还包括判断是否存在特权运行的守护进程、其他用户是否正在运行敏感程序,甚至无法捕捉到其他用户运行的任何程序,更无法捕捉到特定的程序是否正在运行(假设该程序不会因为其自身行为暴露自己),并且作为额外的优势,那些通过外部参数传递敏感信息的、写得不那么好的程序现在可以防范本地窃听了。

filesystem 软件包提供的 proc 用户组 相当于一个白名单,包含了有权访问其他用户进程信息的用户。如果用户或服务需要访问除自身以外的 /proc/<pid> 目录,请 将他们加入该用户组

例如,把除了 proc 组中用户之外的其他用户的进程信息都隐藏起来:

/etc/fstab
proc	/proc	proc	nosuid,nodev,noexec,hidepid=2,gid=proc	0	0

要使用户会话正常工作,需要为 systemd-logind 添加例外:

/etc/systemd/system/systemd-logind.service.d/hidepid.conf
[Service]
SupplementaryGroups=proc

沙盒程序

另请参阅 Wikipedia:Sandbox (computer security)

注意: 用户命名空间配置项 CONFIG_USER_NS 当前在 linux(v4.14.5或更高版本)、linux-lts(v4.14.15或更高版本)和 linux-hardened 中启用。关闭它可能会导致程序无法开启某些沙盒功能。由于会增加本地提权的可能性,非特权用法默认是禁用的,启用它需要将 kernel.unprivileged_userns_clone sysctl 设置为 1

Firejail

Firejail 是一个易于使用的、简单的工具,用于沙盒化程序和服务器。建议将 Firejail 也用于浏览器以及其他网络应用程序,就像对待正在运行的服务器程序一样。

bubblewrap

bubblewrap 是一个由 Flatpak 开发的基于 setuid 的沙盒程序,其资源占用比 Firejail 更小。虽然它缺少某些功能,例如文件路径白名单,但 bubblewrap 确实提供了 bind mounts 的功能,能够创建 user/IPC/PID/network/cgroup 命名空间,并且可以支持简单和 复杂的沙盒

chroots

手动构造 chroot jail 也是可以的。

Linux containers

在不使用 KVM 和 VirtualBox 又需要更大程度隔离的情况下,Linux Containers(Linux 软件容器)是一个不错的选择。LXC 使用自己的虚拟硬件,在现有内核之上的 pseudo-chroot 内运行。

其他虚拟化技术

使用类似 VirtualBoxKVMXenQubes OS(基于 Xen)的完全虚拟化技术,可以在运行有风险的应用程序或浏览危险网站时提高隔离性和安全性。

网络与防火墙

防火墙

虽然源里面的 Arch 内核能够启用 Netfilteriptablesnftables,但它们默认是关闭的。因此强烈建议配置防火墙来保护系统上运行的服务。许多资料(包括 ArchWiki)没有明确说明哪些服务值得保护,因此启用防火墙是一个很好的预防措施。

内核参数

作用于网络的内核参数可以使用 Sysctl 来设置。要查询具体方法,请参阅 Sysctl#TCP/IP stack hardening

SSH

为了减轻 暴力攻击,建议强制使用基于密钥的身份验证。对于 OpenSSH,请参阅 OpenSSH#Force public key authentication。另外,Fail2banSshguard 通过监控日志并写入 iptables 规则 提供了较少形式的保护,但这样做可能会使服务器拒绝服务,因为攻击者可以伪装成管理员的地址并发送欺骗性的数据包。

你可以用双因素身份验证来进一步强化身份验证。Google Authenticator(Google 身份验证器)使用一次性密码 (OTP) 提供两步验证过程。

拒绝 root 登录也是一种很好的做法,既可以跟踪入侵,也可以在 root 访问之前添加额外的安全层。对于 OpenSSH,请参阅 OpenSSH#Deny

DNS

Tango-inaccurate.pngThe factual accuracy of this article or section is disputed.Tango-inaccurate.png

Reason: 由于 HSTS 技术,浏览器可能可以识别出 DNS 欺骗。 (Discuss in Talk:Security (简体中文))

默认情况下,多数系统上的 DNS 查询请求的发送和接收是不加密的,并且不验证数据是否来自规范的服务器,这可能导致 中间人攻击,攻击者拦截用户的 DNS 查询并修改响应数据为 钓鱼 网站的 IP 地址,导致钓鱼网站收集用户的宝贵信息。用户和浏览器/其他软件都不会知道发生了什么,因为 DNS 协议始终将查询结果视为合法的。

DNSSEC 是一套标准,要求 DNS 服务器向客户端出示 DNS 数据的原始验证证明、曾经的验证失败记录和数据完整性。然而这一标准尚未广泛使用。启用 DNSSEC 后,攻击者无法修改您的 DNS 查询请求和返回的结果,但仍可以读取它们。

DNSCrypt 以及后来的替代协议 DNS over TLSDNS over HTTPS,使用加密技术来保护与 DNS 服务器的通信,系统层面上通常只采用其中一种协议。有关实现这些协议的软件,请参阅 Domain name resolution#DNS servers

如果你有一个域名,请设置 Sender Policy Framework(发件人策略框架)来抵御电子邮件欺骗。

代理

代理通常用作应用程序和网络之间的附加层,拦截不受信任的来源的数据。从攻击面上看,以较低权限运行的小代理的攻击面明显小于使用最终用户权限运行的复杂应用程序。

例如,DNS 解析器是在 glibc 中实现的,它与应用程序链接(可能以root身份运行),因此 DNS 解析器中的 bug 可能导致本机执行远程代码。而这可以安装充当代理的 DNS 缓存服务器(例如 dnsmasq)来避免。[2]

管理 SSL 证书

Merge-arrows-2.pngThis article or section is a candidate for merging with Transport Layer Security.Merge-arrows-2.png

Notes: 有一篇专门介绍传输层安全协议的文章。 (Discuss in Talk:Security (简体中文))

请参阅 OpenSSLNetwork Security Services(NSS,网络安全服务)来管理各自的服务器端 SSL 证书。值得注意的是,与此相关的 Let’s Encrypt 项目也支持这些协议。

默认的 Internet SSL 证书信任链由 ca-certificates 包及其依赖项提供。请注意,Arch 依赖于信任源(例如 ca-certificates-mozilla)来提供受系统信任的证书。

有时你可能需要暂时更改默认设置。例如,当你读到这一 新闻 并希望手动解除证书信任,而不是等到信任源提供商这样做,在 Arch 的体系里非常简单:

  1. 以 .crt 格式获取相应的证书(示例:查看, 下载;如果是现有的受信任的根证书颁发机构,你也可以在系统路径中找到它)
  2. 将其复制到 /etc/ca-certificates/trust-source/blacklist/
  3. 以 root 身份运行 update-ca-trust

要检查黑名单是否按预期那样工作,请重新打开浏览器并通过其 GUI 执行此操作,现在浏览器应显示其为不受信任。

软件包验证

如果没有正确地对包进行签名,包管理器就有可能 受到攻击,甚至可能会影响原本具有 签名机制 的包管理器。Arch 默认采用软件包签名机制,并依赖来自 5 个可信主密钥的信任网络。详情请参阅 pacman/Package signing (简体中文)

订阅漏洞告警

订阅国家漏洞数据库 (National Vulnerability Database) 提供的常见漏洞和披露 (Common Vulnerabilities and Exposure, CVE) 安全警报更新,相关内容可以在 NVD 下载页 上找到。Arch Linux Security Tracker 是一个特别有用的资源,它结合了 Arch Linux 安全通报 (ASA),Arch Linux 漏洞组 (AVG) 以及 CVE 数据集,且以表格形式呈现。另请参阅 Arch Security Team(Arch 安全团队)。

警告: 不要试图进行 部分升级,因为 Arch Linux 不支持部分升级且可能导致系统不稳定,要升级组件时应升级整个系统。另外,系统更新不及时可能会使以后的更新过程更加复杂。

物理安全

理论上如果有足够的时间和计算资源,对计算机的物理访问都将会变成 root 权限的访问。但通过设置足够的障碍可以获得切实的安全保障。

攻击者只需连接恶意的 IEEE 1394(火线接口),Thunderbolt 或 PCI Express 设备即可在下次启动时完全控制计算机,因为它们可以完全访问内存。[3] 你无法阻止类似这样的操作,包括修改硬件本身的操作(比如将恶意固件刷到设备上)。但是,绝大多数攻击者都没有这样的知识和信心。

#磁盘加密 将在计算机被盗时保护数据,但经验丰富的攻击者可以给计算机安装恶意固件,在用户下次登录时获取加密的数据。

锁定 BIOS

向 BIOS 添加密码可防止其他人启动到可移动设备,否则这和其他人对计算机具有 root 访问权限基本相同。你应该确保你的磁盘在引导顺序中处于第一位,并且可以的话禁用其他引导设备。

引导加载程序 (Bootloader)

保护引导加载程序非常重要。因为有一个神奇的内核参数叫做 init=/bin/sh,它会使得任何用户的登录限制完全无用。

Syslinux

Syslinux 支持 用密码保护引导加载程序。它允许为每个菜单项设置密码或为整个引导程序设置密码。

GRUB

GRUB 也可以设置引导密码。详情请参阅 GRUB/Tips and tricks#Password protection of GRUB menu。它还支持 加密的 /boot,这样只会使引导程序的部分代码保持未加密状态。GRUB 的配置、内核initramfs 都是加密的。

启动分区置于可移动闪存上

一个较为流行的做法是将启动分区放在可移动闪存上,在没有它的情况下系统便无法启动。这个想法的支持者经常使用 全盘加密,有些还用到了放在启动分区上的 分离加密头

自动注销

如果你用的是 BashZsh,则可以设置 TMOUT 的值,使 shell 在超时后自动注销。

例如,下面的脚本内容将使用户自动从虚拟控制台(非 X11 中的终端模拟器)注销:

/etc/profile.d/shell-timeout.sh
TMOUT="$(( 60*10 ))";
[ -z "$DISPLAY" ] && export TMOUT;
case $( /usr/bin/tty ) in
	/dev/tty[0-9]*) export TMOUT;;
esac

如果确实想要所有 Bash/Zsh 提示符(包括 X 中的)都有超时,请使用:

$ export TMOUT="$(( 60*10 ))";

请注意,shell 中运行的某些命令(例如:SSH 会话或没有 TMOUT 支持的其他 shell)将使上述设置失效。但是如果你主要使用 VC 以 root 身份重新启动僵死的 GDM/Xorg,那么这非常有用。

防范恶意 USB 设备

请安装 USBGuard,这是一个软件框架,通过基于设备属性的基本白名单和黑名单功能,帮助保护计算机免受恶意 USB 设备(例如 BadUSB[失效链接 2021-11-19 ⓘ]PoisonTapLanTurtle)的侵害。

重新构建软件包

软件包可以去除不需要的功能并重新构建,这样可以缩小受攻击范围。例如,bzip2 可以在没有 bzip2recover 的情况下重新构建,以试图规避 CVE-2016-3189 漏洞。强化安全的自定义编译参数也可以手动或通过包装器在编译时加入。

参考资料