更安全的 SSH 连接

如果您需要远程访问一台机器,您可能会使用 SSH,这是有充分理由的。安全外壳协议使用现代密码学方法来提供隐私和保密性,即使在不安全、不安全的网络(如互联网)上也是如此。然而,它的可用性也使其成为攻击者有吸引力的目标,因此您应该考虑加强其标准设置,以提供更具弹性的、难以攻破的连接。在本文中,我将介绍几种提供此类额外保护的方法,从简单的配置更改开始,然后使用 PAM 限制访问,最后使用受限的公钥证书进行无密码的受限登录。

SSH 敲门

如果潜在的入侵者甚至找不到可能的 SSH 入口,那么攻击您的机器将更加困难。本文中显示的方法与我在之前的一篇文章(“使用 knockd 实现端口敲门安全”,2010 年 1 月)中写的端口敲门技术兼容,因此我在此不再赘述 knockd 配置。通过将所有技术结合使用,攻击者将更难访问您的机器(本文中显示的所有其他措施将在那里等待),因为他们甚至无法开始尝试攻击您的盒子。

SSH 在哪里?

按照标准定义,SSH 默认使用端口 22。这意味着在标准的 SSH 配置下,您的机器已经有一个很好的攻击目标。要考虑的第一个方法非常简单——只需将端口更改为未使用的非标准端口,例如 22022。(1024 以上的数字通常是空闲且安全的,但请查看本文末尾的“资源”以避免可能的冲突。)此更改不会对您的远程用户产生太大影响。他们只需要在他们的连接中添加一个额外的参数,例如 ssh -p 22022 the.url.for.your.server。是的,这种更改完全属于所谓的“隐蔽式安全”——隐蔽地做事,希望没有人会识破您的方法——这通常只是自找麻烦。然而,它至少会对脚本小子有所帮助,他们的脚本只是试图通过端口 22 进入,而不是彻底到足以扫描您的机器上的所有开放端口。

为了实现此更改,您需要更改 /etc/ssh/sshd_config 文件。以 root 身份工作,使用编辑器打开它,查找读取“Port 22”的行,并将 22 更改为您选择的任何数字。如果该行以井号 (#) 开头,则将其删除,否则该行将被视为注释。保存文件,然后使用 /etc/init.d/sshd restart 重新启动 SSH。在某些发行版中,可能是 /etc/rc.d/init.d/sshd restart。最后,还要记住在您的防火墙中关闭端口 22,并打开所选端口,以便远程用户能够访问您的服务器。

当您进行此操作时,为了获得额外的安全性,您还可以添加或编辑 SSH 配置文件中的其他一些行(清单 1)。Protocol 行避免了较弱的旧版本 SSH 协议。LoginGraceTime 给用户 30 秒的时间来完成登录。MaxAuthTries 将用户输入密码的错误尝试次数限制为三次,超过三次将被拒绝。最后,PermitRootLogin 禁止用户以 root 身份远程登录(任何设法进入您机器的攻击者仍然必须能够攻破 root 帐户;这是一个额外的障碍),因此潜在的攻击者将更难获得您机器上的权限。

清单 1. 这些小的 SSH 配置更改可以增加一点安全性

Port            22022
Protocol            2
LoginGraceTime     30
MaxAuthTries        3
PermitRootLogin    no

请务必在这些更改后重新启动 SSH 服务守护程序(sudo /etc/init.d/sshd restart 可以做到这一点),目前,您已经设法增加了一点额外的安全性(但实际上不多),所以让我们开始增加更多限制。

谁可以使用 SSH?

您的机器可能安装了多个服务器,但您可能只想限制少数用户的远程访问。您可以进一步调整 sshd_config 文件,并使用 AllowUsersDenyUsersAllowGroupsDenyGroups 参数。第一个参数 AllowUsers 后面可以跟一个用户名列表(甚至可以使用常见的 * 和 ? 通配符的模式)或 user@host 对,进一步将访问限制为仅来自给定主机的用户。类似地,AllowGroups 提供一个组名模式列表,并且仅允许这些组的成员登录。最后,DenyUsersDenyGroups 的工作方式类似,但禁止特定用户和组的访问。注意:规则的优先级顺序是先 DenyUsers,然后是 AllowUsersDenyGroups,最后是 AllowGroups,因此如果您使用 DenyUsers 显式禁止用户连接,则任何其他规则都不能允许他们连接。

例如,一个常见的规则是,从内部网络,每个人都应该能够访问机器。(这听起来很合理;攻击通常来自网络外部。)然后,您可以说只有两个用户 fkereki 和 eguerrero 应该能够从外部连接,并且不应允许其他人连接。您可以通过在 SSH 配置文件中添加一行 AllowUsers *:192.168.1.*,fkereki,eguerrero 并重新启动服务来启用这些限制。如果您想禁止 jandrews 进行远程连接,则需要额外的 DenyUsers jandrews。可以添加更具体的规则(例如,也许 eguerrero 应该只能从家里登录),但是如果事情开始变得难以处理,规则太多,那么编辑 ssh 配置文件和重新启动服务器的想法开始显得不那么有吸引力,并且通过 PAM 有更好的解决方案,PAM 对安全规则使用单独的文件。

PAM 方式

如果您在 Google 上搜索 PAM 的含义,您可以找到几个定义,从食用油喷雾剂到几个首字母缩略词(例如功率幅度调制或正有源质量),但在这种情况下,您感兴趣的是可插拔身份验证模块,这是一种提供额外身份验证规则并加强对服务器访问的方式。让我们使用 PAM 作为指定哪些用户可以访问您的服务器的替代解决方案。

从软件工程的角度来看,如果每个程序都必须发明、定义和实现自己的身份验证逻辑,那将非常糟糕。您如何确定所有应用程序都以相同的方式、没有任何差异地实现了完全相同的检查?PAM 提供了一种解决方法;如果程序需要(例如)验证用户身份,它可以调用 PAM 例程,这将运行您可能在其配置文件中指定的所有检查。使用 PAM,您甚至可以通过简单地更新其配置来动态更改身份验证规则。而且,即使这不是您在此处的主要兴趣,如果您要包含新的生物识别安全硬件(例如指纹读取器、虹膜扫描仪或面部识别),并带有适当的 PAM,您的设备将立即可供所有应用程序使用。

PAM 可以用于四个安全问题:帐户限制(允许用户做什么)、授权(用户如何识别自己)、密码和会话。PAM 检查可以标记为可选(可能成功或失败)、必需(必须成功)、必要条件(必须成功,如果失败,则立即停止,不再尝试任何其他检查)和充分条件(如果成功,则不再运行任何其他检查),因此您可以更改您的策略。我在这里不介绍所有这些细节,而是继续讨论指定谁可以(或不可以)登录到您的服务器的具体需求。有关一些可用模块的列表,请参阅“PAM,无处不在的 PAM”侧边栏。

PAM,无处不在的 PAM

虽然没有“官方”的 PAM 列表,但大多数发行版都可能包含以下内容

  • pam_access:根据文件 /etc/security/access.conf 允许或拒绝访问。

  • pam_cracklib:根据字典检查密码。

  • pam_debug:仅用于测试。

  • pam_deny:始终拒绝访问。

  • pam_echo:显示文件的内容。

  • pam_env:设置或取消设置环境变量。

  • pam_exec:允许您运行外部命令。

  • pam_group:授予用户组成员资格。

  • pam_lastlog:显示用户上次登录的日期和时间。

  • pam_ldap:允许针对 LDAP 服务器进行身份验证。

  • pam_limits:允许您通过文件 /etc/security/limits.conf 设置系统资源限制。

  • pam_listfile:pam_access 的替代方案,具有一些额外的选项。

  • pam_mail:检查用户是否有待处理的邮件。

  • pam_make:在给定目录中运行 make

  • pam_motd:显示“每日消息”文件,通常是 /etc/motd。

  • pam_nologin:如果文件 /etc/nologin 存在,则阻止所有登录。

  • pam_permit:始终允许访问。

  • pam_pwcheck:检查密码强度。

  • pam_pwhistory:根据最近使用的密码检查新密码,以避免重复。

  • pam_rootok:通常包含在 /etc/pam.d/su 中作为“充分”测试,以便 root 可以像任何其他用户一样操作,而无需提供密码。

  • pam_selinux:为 SELinux 设置默认安全上下文。

  • pam_sepermit:根据 SELinux 状态允许或拒绝登录。

  • pam_shells:仅当用户的 shell 列在文件 /etc/shells 中时才允许访问。

  • pam_succeed_if:检查帐户特征,例如是否属于给定组。

  • pam_tally:仅记录尝试访问的次数,如果失败次数过多,则可以拒绝访问。

  • pam_time:根据文件 /etc/security/time.conf 中的规则限制访问。

  • pam_umask:允许您为新创建的文件设置文件模式创建掩码(考虑 umask)。

  • pam_unix(或 pam_unix2):根据 /etc/passwd 和 /etc/shadow 文件提供经典的 UNIX 风格的身份验证。

  • pam_userdb:针对 Berkeley 数据库验证用户身份。

  • pam_warn:在系统日志中记录日志。

  • pam_wheel:仅向 wheel 组成员提供 root 访问权限。

文件位置各不相同,但您可以检查 /usr/lib/security 或 /lib/security(或读取 lib64 for lib,用于 64 位 Linux)以查看您实际拥有的模块。有关每个模块的更多信息,请尝试 man name.of.the.module,但不要尝试从命令行执行它们,因为它们无法以这种方式运行。

PAM 配置存储在 /etc/pam.d 中,每个文件对应于它们应用到的每个命令。以 root 身份,编辑 /etc/pam.d/sshd,并在所有 account 行之后添加一行 account required pam_access.so,使其最终看起来像清单 2。(您的特定文件版本可能有一些不同的选项;只需将单行添加到其中即可。)您还需要修改 sshd 配置文件(您之前修改过的那个),以便它使用 PAM;在其中添加一行 UsePAM yes,然后重新启动 sshd 守护程序。

清单 2. 将 pam_access.so 添加到帐户 PAM 检查中,可以让您指定哪些用户有权 SSH 访问您的机器。

account  required    pam_unix2.so
account  required    pam_access.so

auth     required    pam_env.so
auth     required    pam_unix2.so
auth     required    pam_nologin.so

password requisite   pam_pwcheck.so nullok cracklib
password required    pam_unix2.so use_authtok nullok

session  required    pam_limits.so
session  required    pam_unix2.so
session  optional    pam_umask.so

account 部分在这里很重要。在使用标准的 UNIX 方法检查您的密码(通常是针对文件 /etc/passwd 和 /etc/shadow)之后,它使用模块 pam_access.so 来检查用户是否在列表中,如清单 3 所示。两个 account 模块都是 required,这意味着用户必须通过两个检查才能继续。对于额外的限制,您可能需要查看 pam_listfile,它类似于 pam_access,但提供了更多选项,以及 pam_time,它允许您设置时间限制。您还需要将额外的 account 行添加到 /etc/pam.d/sshd 文件中。

您需要编辑 /etc/security/access.conf 以指定哪些用户可以访问机器(清单 3)。列表中的每一行都以加号(允许登录)或减号(禁用登录)开头,后跟一个冒号、一个用户名(或 ALL)、另一个冒号和一个主机(或 ALL)。pam_access.so 模块按顺序向下遍历列表,并根据用户的第一个匹配项,它要么允许要么禁止连接。规则的顺序很重要。首先,禁止 jandrews 访问,然后允许内部网络中的每个人登录服务器。然后,允许用户 fkereki 和 eguerrero 从任何机器访问。最后的 -:ALL:ALL 行是一个包罗万象的规则,它拒绝任何未在前面几行中明确允许登录的人的访问,它应该始终存在。

清单 3. 文件 /etc/security/access.conf 指定哪些用户有权访问以及从哪些主机访问。

-:jandrews:ALL
+:ALL:192.168.1.
+:fkereki:ALL
+:eguerrero:ALL
-:ALL:ALL

请注意,您可以将此配置用于其他程序和服务(FTP,也许?),并且可以应用相同的规则。这是 PAM 的一个优点。第二个优点是您可以动态更改规则,而无需重新启动 SSH 服务。不干扰正在运行的服务始终是一个好主意!使用 PAM 为 SSH 增加了一点安全性,以限制谁可以登录。现在,让我们看看一种更安全的方式,通过使用证书来说明谁可以访问您的机器。

无密码连接

密码可能相当安全,但您不会将它们写在计算机旁边的便利贴上,对吗?但是,如果您使用不太复杂的密码(因此可以通过暴力破解或字典攻击确定),那么您的站点将在攻击者希望的时间内被入侵。有一种更安全的方法,即使用公钥/私钥登录,它还有一个额外的好处,即远程站点上不需要密码。相反,您将在远程机器上拥有密钥的一部分(“私钥”部分),而在远程服务器上拥有另一部分(“公钥”部分)。除非其他人拥有您的私钥,否则他们将无法冒充您,并且在计算上无法计算。在不深入研究密钥对是如何创建的情况下,让我们继续使用它。

首先,确保您的 sshd 配置文件允许私钥登录。您应该在其中包含 RSAAuthentication yesPubkeyAuthentication yes 行。(如果没有,请添加它们,并如上所述重新启动服务。)如果没有这些行,我下面解释的所有内容都不会起作用。然后,使用 ssh-keygen 创建公钥/私钥对。通过直接使用它而不使用任何其他参数(清单 4),系统将询问您将密钥保存在哪个文件中(接受标准),是否使用密码短语以获得额外的安全性(下面会详细介绍,但您最好这样做),并且将生成密钥对。注意保存密钥的文件名。您稍后会用到它。

清单 4. 使用 ssh-keygen 生成公钥/私钥对非常简单。选择使用密码短语以获得额外的安全性。

$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/fkereki/.ssh/id_rsa):
Created directory '/home/fkereki/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/fkereki/.ssh/id_rsa.
Your public key has been saved in /home/fkereki/.ssh/id_rsa.pub.
The key fingerprint is:
84:13:e6:07:a3:b1:b4:c6:9f:29:b8:40:58:f5:23:26 fkereki@fedoraxfce
The key's randomart image is:
+--[ RSA 2048]----+
|  ..+ =          |
|.. o O =         |
|..E O * o        |
|.  = o B         |
|. . . + S        |
| . . .           |
|  .              |
|                 |
|                 |
+-----------------+

现在,为了能够连接到远程服务器,您需要将其复制过去。如果您在 Internet 上搜索,许多站点建议直接编辑某些文件以完成此操作,但使用 ssh-copy-id 容易得多。您只需键入 ssh-copy-id -i the.file.where.the.key.was.saved remote.user@remote.host,指定公钥保存的文件名(如您在上面看到的)以及您将要连接的远程用户和主机(清单 5)。您就完成了。

清单 5. 生成公钥/私钥对后,您需要使用 ssh-copy-id 将公钥部分复制到远程服务器。

$ ssh-copy-id -i /home/fkereki/.ssh/id_rsa.pub fkereki@192.168.1.107
The authenticity of host '192.168.1.107 (192.168.1.107)' 
 ↪can't be established.
RSA key fingerprint is 16:a4:d8:6a:ee:e0:8d:f4:72:a8:af:42:75:1d:28:3b.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.1.107' (RSA) to the list 
 ↪of known hosts.
fkereki@192.168.1.107's password:

为了测试您的新无密码连接,只需执行 ssh remote.user@remote.host。如果您使用了密码短语,系统现在会要求您输入它。在任何一种情况下,连接都将建立,您无需为远程站点输入密码(清单 6)。

清单 6. 将公钥复制过去后,您无需密码即可登录到远程服务器。但是,如果您在生成公钥/私钥对时使用了密码短语,则必须输入密码短语。

$ ssh fkereki@192.168.1.107
Enter passphrase for key '/home/fkereki/.ssh/id_rsa':
Last login: Mon Jan 10 18:40:11 2011

6.0 Light Final built on March 31, 2009 on Linux 2.6.27.12
You are working as fkereki
Frequently used programs:
Configuration  : vasm
File manager   : mc (press F2 for useful menu)
Editor         : mcedit, nano, vi
Multimedia     : alsamixer, play
vector:/~
$ logout
Connection to 192.168.1.107 closed.

现在,密码短语怎么样?如果您创建公钥/私钥对而不使用密码短语,那么任何可以访问您的机器和私钥的人都将立即可以访问您有权访问的所有远程服务器。使用密码短语为您的登录过程增加了另一层安全性。但是,不得不一遍又一遍地输入它很麻烦。因此,您最好使用 ssh-agent,它可以“记住”您的密码短语,并在您尝试登录到远程服务器时自动输入它。运行 ssh-agent 后,运行 ssh-add 以添加您的密码短语。(如果您有多个密码短语,您可以多次运行它。)之后,远程连接将不再需要密码短语(清单 7)。如果您想结束会话,请使用 ssh-agent -k,如果您想进行远程登录,则必须重新输入密码短语。

清单 7. 使用 ssh-agent 可以让您免于重复输入密码短语。

$ ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-Rvhhx30943/agent.30943; export SSH_AUTH_SOCK;
SSH_AGENT_PID=30944; export SSH_AGENT_PID;
echo Agent pid 30944;

$ ssh-add
Enter passphrase for /home/fkereki/.ssh/id_rsa:
Identity added: /home/fkereki/.ssh/id_rsa (/home/fkereki/.ssh/id_rsa)

$ ssh fkereki@192.168.1.107
Last login: Mon Jun 10 18:44:15 2013 from 192.168.1.108
6.0 Light Final built on March 31, 2009 on Linux 2.6.27.12
You are working as fkereki
Frequently used programs:
Configuration  : vasm
File manager   : mc (press F2 for useful menu)
Editor         : mcedit, nano, vi
Multimedia     : alsamixer, play

您可能还需要查看 keychain,它允许您在登录之间重用 ssh-agent。(并非所有发行版都包含此命令;您可能必须使用您的软件包管理器来安装它。)只需执行 keychain the.path.to.your.private.key,输入您的密码短语(图 1),并且在您重新启动服务器或专门运行 keychain -k all 以停止 keychain 之前,您的密码短语将被存储,您将不必重新输入它。注意:您甚至可以注销并再次登录,您的密钥仍然可用。如果您只想清除所有缓存的密钥,请使用 keychain --clear

图 1. 通过使用 keychain 输入一次密码短语,即使您注销,它也会被记住。

如果您使用密码短语,您可以将您的私钥随身携带在 USB 闪存盘或类似设备上,并从任何其他机器使用它来登录到您的远程服务器。如果不使用密码短语这样做,那就太危险了。丢失您的 USB 闪存盘将意味着自动危及您可以登录的所有远程服务器。此外,使用密码短语是一种额外的安全措施。如果其他人获得了您的私钥,他们也无法在不首先确定您的密码短语的情况下使用它。

最后,如果您非常确信所有需要的用户都设置了无密码登录,您可以完全放心地编辑 sshd 配置文件并设置 PasswordAuthentication noUsePAM no 来禁用常用密码,但您最好非常确定一切正常,否则您将遇到问题。

使用 SSH 和 PuTTY

您可以将 SSH 公钥/私钥对与常用的 PuTTY 程序一起使用,但不能直接使用,因为它需要特定的、不同的密钥文件。为了转换您的 SSH 密钥,您需要执行 puttygen $HOME/.ssh/your.private.key -o your.private.key.file.for.putty。之后,您可以简单地打开 PuTTY,转到“连接”、“SSH”、“Auth”,然后浏览您新生成的“用于身份验证的私钥文件”。

结论

没有一套明确的安全措施可以 100% 保证没有攻击者能够访问您的服务器,但添加额外的层可以加强您的设置,并降低攻击成功的可能性。在本文中,我描述了几种方法,包括修改 SSH 配置、使用 PAM 进行访问控制以及使用公钥/私钥密码学进行无密码登录,所有这些都将增强您的安全性。然而,即使这些方法确实使您的服务器更难受到攻击,也要记住您始终需要保持警惕,并为攻击者设置尽可能多的障碍。

资源

SSH 协议在许多 RFC(请求评论)文档中定义;查看 http://en.wikipedia.org/wiki/Secure_Shell#Internet_standard_documentation 获取列表。

端口号由 IANA(互联网号码分配机构)分配,您可以访问 http://www.iana.org/assignments/port-numbers 获取列表。

PAM 的主要分发站点位于 http://www.linux-pam.org,开发人员站点位于 https://fedorahosted.org/linux-pam

阅读 http://www.funtoo.org/wiki/Keychain 以获取有关 keychain 的更多信息,作者是 Daniel Robbins。

您可以在 http://www.google.com/patents?vid=4405829 查看 RSA 原始专利,在 http://www.emc.com/emc-plus/rsa-labs/pkcs/files/h11300-wp-pkcs-1v2-2-rsa-cryptography-standard.pdf 查看 RSA 密码学标准。

有关额外的安全措施,请阅读 Linux Journal 2010 年 1 月刊中的“使用 knockd 实现端口敲门安全”,或在线查看 https://linuxjournal.cn/article/10600

加载 Disqus 评论