保护 OpenSSH
如果您是一位或多位 Linux/UNIX 系统的系统管理员,OpenSSH 很可能是您工具箱中最重要的工具之一。OpenSSH 可以交互使用,也可以嵌入到脚本中,以提供系统之间安全的远程访问和文件传输。但是,唉,危险潜伏在前。使用 OpenSSH,非常容易创建马虎的信任关系,或者更糟糕的是,让自己暴露于常见的自动化攻击之下。
系统安全的基本原则之一始终是仅运行最少需要的服务,并将其访问权限限制在需要它的人员范围内。Linux 系统使这很容易实现,并且像 *nix 世界中的大多数事物一样,您可以通过多种方式来实现。如果您仍在阅读本文,我们假设您需要运行 OpenSSH。让我们着手限制访问。
在大多数 Linux 发行版中,您可以选择在内核防火墙级别处理此问题,或者使用 TCP Wrappers(/etc/hosts.{allow|deny} 文件)。
一个简单的 iptables 防火墙规则,将 OpenSSH 限制为仅限您的本地子网,可以是
iptables -A INPUT -s ! 192.168.0.0/255.255.0.0 ↪-p tcp -m tcp --dport 22 -j REJECT --reject-with ↪icmp-port-unreachable
这告诉内核拒绝任何来自特定子网并指向端口 22 的 TCP/IP 数据包。(根据需要替换您自己的数字。)在所有可能性中,您将有额外的 iptables 规则来保护此系统上的其他应用程序,因此请将上述内容集成到您的整体防火墙设计中。
TCP Wrappers 是大多数 Linux 发行版上的常见功能,而 OpenSSH 具有内置支持。要使用 TCP Wrappers 实现上述相同的规则,请将以下行添加到您的 /etc/hosts.deny 文件中
sshd: ALL EXCEPT 192.168.0.0/255.255.0.0
在大多数情况下,OpenSSH 很可能不需要暴露在广阔的互联网上供人窥探。此外,OpenSSH 甚至不太可能需要对您的整个组织可用。我强烈建议使用上述任何一种方法将访问权限限制在尽可能小的受众范围内。一种常见的方法是专门指定一个或多个系统用于集中管理的目的。将您的其余系统配置为仅接受来自这些专用且高度安全的系统的 OpenSSH 连接。
要测试您是否已成功限制对 OpenSSH 的访问,您可以尝试使用 ssh 客户端连接,或者只是使用命令行 telnet 客户端连接到系统,例如
$ telnet mylinuxbox 22
其中 mylinuxbox 是主机名,22 是端口。
如果 OpenSSH 正在响应并且已打开,您应该看到类似以下内容
SSH-1.99-OpenSSH_3.9p1
如果它被成功阻止,连接将被拒绝。从多个位置尝试此操作,并确认连接已按您的预期被阻止。
多年来,由于漏洞,OpenSSH 曾出现过一些可远程利用的漏洞。这些漏洞总是很快得到修复,并及时分发更新版本。不幸的是,许多联网系统没有更新。此外,许多系统只是安全性很差。使用简单或空白密码的标准帐户令人沮丧地司空见惯。
所有这些都是黑客和蠕虫作者垂涎的目标。存在许多恶意蠕虫,它们扫描任何 SSH 服务器,然后尝试常见的漏洞和密码。如果您必须将 OpenSSH 端口向全世界开放,请考虑更改其 TCP 端口号。这可以通过更改 sshd_config 文件中的 Port 指令来完成,该文件通常位于 /etc/ssh/ 中。尽管任何试图破解您系统的活人可能都很难检测到这一点,但这通常足以逃脱大规模自动化攻击和蠕虫的注意。
此外,您可能需要考虑在修改版本字符串后从源代码重新构建 OpenSSH。这也可能有助于迷惑自动化攻击,因为许多漏洞都依赖于特定版本的 OpenSSH。这通过修改 OpenSSH 发行版中的 version.h 文件并重新编译来完成。将 SSH_VERSION 和 SSH_PORTABLE #define 行更改为您喜欢的任何内容,例如
#define SSH_VERSION "MyCompany_Vers00001" #define SSH_PORTABLE "foo"
更改源代码后,构建并安装。这将更改上述 telnet 测试中显示的版本横幅。
更改端口和版本字符串 并不能 提高安全性;它们只是降低了成为常见漏洞或蠕虫受害者的风险。没有什么可以替代保护帐户并确保您的系统运行最新补丁级别的软件。如果您使用的是 Linux,请使用最新的发行版。使用 yum、apt 或 up2date 等自动化更新工具,使您的系统保持运行所有软件和库(包括 OpenSSH)的最新版本。
您可以使用像 John the Ripper 这样的破解工具(请参阅在线资源)来确认用户是否选择了好的密码。John the Ripper (JTR) 使用 /etc/shadow 中的单向加密密码来尝试破解密码。一般来说,JTR 破解的较容易的密码更可能出现在某些蠕虫常用的暴力字典攻击中。对于使用 LDAP、NIS、AFS Kerberos 和其他身份验证服务的用户,JTR 支持各种输入文件格式。
如果可能,请停止使用密码进行远程登录。您可以通过使用公钥身份验证设置信任关系来实现此目的。这些信任关系可以在同一系统上或跨网络的任何两个用户帐户之间设置。
设置这些关系之一的第一步是创建私钥和公钥,称为密钥对。每个密钥都存储在一个单独的文件中。按照惯例,文件名相同,但公钥文件有一个额外的 .pub 扩展名。私钥保持秘密,通常保留在将发起连接的帐户的主目录中。
OpenSSH 将拒绝使用任何文件权限宽松的私钥文件。要形成信任关系,公钥将附加到信任关系目标端的 ~/.ssh/authorized_keys 文件(大多数 Linux 构建的 OpenSSH 上的常用位置)。authorized_keys 文件包含所有由所有者帐户信任的公钥。可以通过提供用于加密私钥的密码短语来进一步保护这些密钥。如果指定了密码短语,则需要在使用私钥建立连接之前提供它。在下面的示例中,我们在两个帐户之间创建信任关系,一个是在名为 localbox 的系统上的 account1,另一个是在名为 remotebox 的系统上的 account2。
创建 account1 的密钥对(我们将在被询问时指定密码短语)。密码短语在您键入时实际上不显示,但为了演示,它显示在下方。我们指定该密钥对应基于 2048 位私钥(默认值为 1024 位,最近已被证明更容易破解)
[account1@localbox account1]$ ssh-keygen -t rsa -b 2048 Generating public/private rsa key pair. Enter file in which to save the key (/home/account1/.ssh/id_rsa): <ENTER> Created directory '/home/account1/.ssh'. Enter passphrase (empty for no passphrase): This%%%Is%%%My%%%Passphrase<ENTER> Enter same passphrase again: This%%%Is%%%My%%%Passphrase<ENTER> Your identification has been saved in /home/account1/.ssh/id_rsa. Your public key has been saved in /home/account1/.ssh/id_rsa.pub. The key fingerprint is: 63:9f:75:d5:80:93:67:5e:d8:69:5a:69:69:4f:a0:76 account1@localbox [account1@localbox account1]$ cat /home/account1/.ssh/id_rsa -----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,9668032A1B3D23DA 2IKH5Xt+LR2/nftd8aPi1KPZ4Fn20upJKU1NUAK82HXBb59TPyzmr/05i56ZiPhO UHJCScF+G/k44zheUnyWu+/65iVuzTaa+6q4eYaTna8ElA+PetmfwQF08L780NkU +2VJeEyizXcro9J6oYYGhS+qWfHalmbX6w6IWuAh6jjEhCn+LTlZs1yjGFu5NHDr sWSMNgounPS/ay8ZlNIV+iQB5l/v+bNWiC92ICYbZW0C+o2XKpNvACdUDpA/gfqk b20utNOzBfGAGgmU2EJ5HGq8YQMCjVk0ZN/NVjGqUuACQmW0nB5jYrGE/ka/20xN X4jZWxXGxNeS0PMdxlB5XXXXXXBMwCWx0AZ0SVYdoSbapZJKMsOdEolFU4IFEewm NlgFXfe7vsdFseFsaSdfEkCHaHaMadeYouLooktoqz+mfkbwDpC8msnKcuRJShR9 09rZnoKW/ddvrJv5oIQYFqu7LYJr5ygpW3T3oiFgzsIg//1hAW4h0sTCBWUIGSkk IWTxKFooQ3ABarsIzCHqPBazXnSJ5IVXXXXlglmH9ce5Z6YMNoUdfWBn4Mgc2gNB xCk4KINXMJ7MJsmLxkwuABqcTq4SBCiipr6PLL5G2BKK6ljXLdJe4olDdb/GtxlH mOXNuAWLD1eE5FfAOUSQLGDkeUThisIsNotARealPrivateKeycOBrhdykHI5Sh7 /hVyTVr9t6r6lRBEsMi1T+P2uBAuahNGCyDs+5F1P14y2RJ5GAlDVdM8bXOfnfsO pHiXerStpKw6j85wxoKryzSAGs2eWXtrQKk8IMkDQug= -----END RSA PRIVATE KEY----- [account1@localbox account1]$ cat /home/account1/.ssh/id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA54Q3QZLkpRaNN83WUMBGBE+/xZ88ud +SlM74awZa8P6H3TNcEnrb3Lti58bsgjl3z0W5DXWvNRgszoQeBJYNVHlsVIUCp0Vj Vr7aDUn0PiUVI2y658XBlbup5+isgMNuyB7BskVKs9aWYQNCbJVoNo+3wcvA9x+De5 Z7yBapi6E= account1@localbox
这创建了两个密钥文件 /home/account1/.ssh/id_rsa 和 /home/account1/.ssh/id_rsa.pub。现在,我们将公钥复制到 account2@remotebox。您可以使用任何您认为方便的方法来执行此操作。我们使用 scp 复制文件,然后使用 cat 将其附加到
[account1@localbox account1]$ scp /home/account1/.ssh/id_rsa.pub ↪account2@remotebox:./account1.id_rsa.pub account2@remotebox's password: id_rsa.pub 100% 243 538.1KB/s 00:00
现在我们将 account1 的公钥附加到 account2 的 authorized_key 文件,并设置文件的正确权限
[account2@remotebox account2]$ mkdir ~/.ssh [account2@remotebox account2]$ chmod 700 ~/.ssh [account2@remotebox account2]$ cat account1.id_rsa.pub >> ↪~/.ssh/authorized_keys [account2@remotebox account2]$ chmod 600 ~/.ssh/authorized_keys [account2@remotebox account2]$ rm account1.id_rsa.pub [account2@remotebox account2]$ ls -l ~/.ssh/ -rw------- 1 account2 account2 243 Dec 9 09:42 authorized_keys
通过将公钥放置在目标帐户 account2 上,我们在 account1 尝试连接时证明了其身份。正如您在下面看到的,当我们建立连接时,系统会提示我们输入密码短语
[account1@localbox account1]$ ssh account2@remotebox Enter passphrase for key '/home/account1/.ssh/id_rsa': This%%%Is%%%My%%%Passphrase<ENTER> [account2@remotebox account2]$
在基本信任关系设置完成后,您可以使用 passwd 命令和 -l 选项锁定密码来禁用密码身份验证。
您可以通过向 authorized_keys 文件添加选项来进一步限制此信任。在下面的示例中,我们包含 from= 选项以添加基于主机的检查,因此私钥将仅从预定义的网络地址接受。我们还添加了 command= 选项,该选项指定身份验证到远程帐户后将执行的唯一命令。此功能在脚本内部最有用,用于创建特殊用途的信任关系以自动化系统或帐户之间的任务
[account2@kettle account2]$ cat .ssh/authorized_keys from="localbox",command="/bin/df -k" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA54Q3QZLkpRaNN83WUMBGBE+ /xZ88ud+SlM74awZa8P6H3TNcEnrb3Lti58bsgjl3z0W5DXWvNRgszo QeBJYNVHlsVIUCp0VjVr7aDUn0PiUVI2y658XBlbup5+isgMNuyB7Bs kVKs9aWYQNCbJVoNo+3wcvA9x+De5Z7yBapi6E= account1@localbox [account1@localbox account1]$ ssh account2@remotebox Enter passphrase for key '/home/account1/.ssh/id_rsa': This%%%Is%%%My%%%Passphrase<ENTER> 10:32:15 up 8 days, 15:13, 16 users, load average: 0.15, 0.12, 0.09 Connection to remotebox closed. [account1@localbox account1]$
在 uptime 命令执行后,我们立即返回到 account1。此关系现在被锁定为仅执行一项操作。这可以是单个命令、脚本或受限 shell。command= 选项可用于允许某些用户以受控方式执行选定的提升权限操作。可以使用 sudo 等工具获得类似的功能,但 OpenSSH 允许通过网络进行这些操作,这在某些情况下很有用。如果您在这些示例中遇到问题,可以使用 -vvv 命令行选项运行启用调试的 ssh。这通常有助于找出问题所在;最常见的是,文件权限导致 OpenSSH 忽略密钥文件。
为了方便在脚本中使用公钥身份验证,您可以为每个远程操作创建一个密钥对,然后通过使用 -i 选项和私钥文件名调用 ssh 来指定要使用的密钥对。
对于交互式会话,您可以使用名为 ssh-agent 的程序将您解密的私钥缓存在内存中,这样您只需提供一次密码短语。在某些 Linux 发行版上,ssh-agent 已经连接到登录进程以自动启动。如果是这样,您只需使用 ssh-add 缓存您的私钥即可。如果您对 ssh-agent 感兴趣,请查看 ssh-agent 和 ssh-add 手册页,以详细了解它们的用途。
关于公钥身份验证的最后一点评论:随着现代 USB 闪存驱动器的价格和易用性,您可以考虑将受密码短语保护的私钥保存在可移动介质上,而不是保存在您的主目录中。这使您可以从多个位置使用它们,同时只维护一份副本。
OpenSSH 有许多配置选项可用于降低风险。大多数 Linux 发行版都带有良好的折衷设置。在某些情况下,可以调整这些设置以获得更好的安全性。这些包括
日志记录:将日志记录级别提高到 INFO 或 DEBUG。定期检查您的日志,或者更好地是,实施许多可用的日志分析工具之一,以通知您异常情况
LogLevel INFO
权限分离:确保启用 UsePrivilegeSeparation 选项
UsePrivilegeSeparation yes
协议:限制 OpenSSH 仅接受协议版本 2
Protocol 2
Root 登录:阻止使用密码进行 root 登录。这会将 root 访问权限限制为仅限非密码方法,如公钥身份验证。如果您从不直接以 root 身份登录,请将其设置为 no。您始终可以以普通用户身份登录,然后su切换到 root 用户或使用 sudo。将其设置为 without-password 仅允许非密码方法,例如公钥身份验证
PermitRootLogin without-password
文件权限:确保启用 StrictModes 以防止使用不安全的主目录和密钥文件权限
StrictModes yes
反向名称检查:要求 OpenSSH 检查正确的反向主机名查找。请注意,您必须具有正常工作的名称查找(即 DNS 或 /etc/hosts)
VerifyReverseMapping yes
防止端口转发:这两个选项阻止 OpenSSH 设置 TCP 端口和 X11 转发;如果您不需要这些功能,请禁用它们
AllowTcpForwarding no X11Forwarding no
禁用所有基于主机的身份验证:始终确保禁用这些方法。这些方法假设网络可以信任,并允许基于主机名或 IP 的 .rhosts 样式身份验证。永远不要将这些方法用作主要身份验证
IgnoreRhosts yes HostbasedAuthentication no RhostsAuthentication no RhostsRSAAuthentication no
使用上述建议,您将能够加强访问控制并消除马虎的信任关系。正如我之前提到的,及时更新或打补丁对于系统安全至关重要。为了保持最新状态,您需要了解更新发布的时间,因此我建议采用多管齐下的方法。首先,自动化 apt、yum 或 up2date 以每晚检查并报告缺少的更新。其次,订阅您的 Linux 发行版的安全邮件列表。第三,订阅众多安全讨论组之一,例如 SecurityFocus。如果您从源代码构建 OpenSSH,请加入 OpenSSH 邮件列表以关注更新。
系统安全需要一种整体方法。本文中提供的方法构成了保护 OpenSSH 的基础,OpenSSH 是现代复杂 Linux 系统的一个小组件。
在您认为已保护系统安全之后,请使用 Nessus 漏洞扫描程序(免费,请参阅“资源”)等扫描工具以及同事的同行评审来检查您的工作。
本文资源: /article/9023。
Matthew E. Hoskins 是新泽西理工学院的高级 UNIX 系统管理员,他在那里维护着许多公司管理系统。他喜欢尝试让截然不同的系统和软件协同工作,通常使用薄薄的一层 Perl(在本地称为“MattGlue”)。当不进行系统破解时,他经常可以在厨房里进行烹饪。Matt 是专业记者协会的成员,可以通过 matt@njit.edu 联系到他。