16.7.OpenSSH ============ OpenSSH 是一组网络连接工具,用于提供对远程计算机的安全访问。此外,TCP/IP 连接可以通过 SSH 连接安全地进行隧道或转发。OpenSSH 对所有流量进行加密,以有效消除窃听、连接劫持和其他网络级攻击。 OpenSSH 由 OpenBSD 项目维护,并且被预装在 FreeBSD 中。 当数据以未加密的形式通过网络发送时,客户端和服务器之间任何位置的网络嗅探器都可以窃取用户/密码信息或在会话期间传输的数据。OpenSSH 提供了多种身份验证和加密方法来防止这种情况发生。有关 OpenSSH 的更多信息,请访问 http://www.openssh.com/\ 。 本节概述了内置的客户端实用程序,以安全地访问其他系统,并从 FreeBSD 系统安全地传输文件。然后它说明了如何在 FreeBSD 系统上配置 SSH 服务器。更多信息可在本章提及的手册页中找到。 16.7.1.使用 SSH 客户端工具 -------------------------- 要登录到 SSH 服务器,请使用 ``ssh`` 并指定该服务器上存在的用户名以及服务器的 IP 地址或主机名。如果这是第一次与指定的服务器建立连接,系统将提示用户首先验证服务器的指纹: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # ssh user@example.com The authenticity of host 'example.com (10.0.0.1)' can't be established. ECDSA key fingerprint is 25:cc:73:b5:b3:96:75:3d:56:19:49:d2:5c:1f:91:3b. Are you sure you want to continue connecting (yes/no)? yes Permanently added 'example.com' (ECDSA) to the list of known hosts. Password for user@example.com: user_password SSH 利用密钥指纹系统在客户端连接时验证服务器的真实性。当用户在首次连接时通过键入 ``yes`` 来接受密钥的指纹时,密钥的副本将保存到用户主目录中的 **.ssh/known_hosts**\ 。以后的登录尝试将根据保存的密钥进行验证,如果服务器的密钥与保存的密钥不匹配,\ ``ssh`` 则会显示警告信息。如果发生这种情况,用户应先验证密钥更改的原因,然后再继续连接。 最新版本的 OpenSSH 仅接受 SSHv2 连接。SSH 协议版本 1 已过时。 使用 `scp(1) `__ 可安全地将文件复制到远程计算机或从远程计算机复制文件。本示例将远程系统上的 **COPYRIGHT** 复制到本地系统的当前目录中: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # scp user@example.com:/COPYRIGHT COPYRIGHT Password for user@example.com: ******* COPYRIGHT 100% |*****************************| 4735 00:00 # 由于已针对此主机验证了指纹,因此在提示输入用户密码之前会自动检查服务器的密钥。 传递给 ``scp`` 的参数类似于 ``cp`` 命令。要复制的一个或多个文件是第一个参数,要复制到的目标变量是第二个参数。由于文件是通过网络获取的,因此一个或多个文件参数采用的形式如下:\ ``用户名@主机:<远程文件路径>``\ 。在以递归方式复制目录时异于 ``cp`` 使用的 ``-R``\ ,\ ``scp`` 使用 ``-r``\ 。 要打开用于复制文件的交互式会话,请使用 ``sftp``\ 。请参阅 `sftp(1) `__ 获取会话中 ``sftp`` 可用命令的列表。 16.7.1.1.基于密钥的身份验证 ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 可以将客户端配置为使用密钥连接到远程计算机,而非使用密码。要生成 RSA 身份验证密钥,请使用 ``ssh-keygen`` 来生成公钥和私钥对,请指定密钥类型并按照提示操作。建议使用不易忘记但难以被别人猜测出来的密码来保护密钥。 .. raw:: latex \diilbookstyleinputcell .. code:: shell-session % ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/user/.ssh/id_rsa): Enter passphrase (empty for no passphrase): ① Enter same passphrase again: ② Your identification has been saved in /home/user/.ssh/id_rsa. Your public key has been saved in /home/user/.ssh/id_rsa.pub. The key fingerprint is: SHA256:54Xm9Uvtv6H4NOo6yjP/YCfODryvUU7yWHzMqeXwhq8 user@host.example.com The key's randomart image is: +---[RSA 2048]----+ | | | | | | | . o.. | | .S*+*o | | . O=Oo . . | | = Oo= oo..| | .oB.* +.oo.| | =OE**.o..=| +----[SHA256]-----+ ① 在此处键入密码。它可以包含空格和符号。 ② 重新键入密码以进行验证。 私钥存储在 **~/.ssh/id_rsa** 中,公钥存储在 **~/.ssh/id_rsa.pub**\ 。必须将公钥复制到远程计算机上的 **~/.ssh/authorized_keys**\ ,才能确保基于密钥的身份验证正常工作。 **警告** 许多用户认为密钥在设计上是安全的,并且会使用没有密码的密钥,这是很危险的行为。管理员可以通过手动查看私钥来验证一个密钥对是否受到密码的保护。如果私钥文件包含 ``ENCRYPTED`` 字样,则说明密钥所有者使用了密码。此外,为了更好地保护最终用户,可以在公钥文件中加入 ``from``\ 。例如,在 ``ssh-rsa`` 前缀前面加上 ``from="192.168.10.5"`` 将只允许该特定用户从该 IP 地址登录。 选项和文件因不同版本的 OpenSSH 而异。为避免出现问题,请查阅 `ssh-keygen(1) `__\ 。 如果使用了认证密码,则每次与服务器建立连接时,系统都会提示用户输入认证密码。要将 SSH 密钥加载到内存中,并且每次都无需键入密码,请使用 `ssh-agent(1) `__ 和 `ssh-add(1) `__\ 。 认证由 ``ssh-agent`` 处理,使用加载到其中的私钥。\ ``ssh-agent`` 可用于启动另一个应用程序,如 shell 或窗口管理器。 若要在 shell 中使用 ``ssh-agent``\ ,请以 shell 作为参数开始,通过运行 ``ssh-add`` 并输入私钥的密码来添加标识。然后,用户就能够用 ``ssh`` 访问安装了相应公钥的任何主机。例如: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session % ssh-agent csh % ssh-add Enter passphrase for key '/usr/home/user/.ssh/id_rsa': ① Identity added: /usr/home/user/.ssh/id_rsa (/usr/home/user/.ssh/id_rsa) % ① 输入密钥的密码。 要在 Xorg 中使用 ``ssh-agent``\ ,请在 **~/.xinitrc** 中为其添加一个条目。这为在 Xorg 中启动 ``ssh-agent`` 的所有程序提供服务。示例 **~/.xinitrc** 如下所示: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session exec ssh-agent startxfce4 这会启动 ``ssh-agent``\ ,而 Xorg 在每次启动时都会启动 XFCE。重新启动 Xorg 以使更改生效后,请运行 ``ssh-add`` 以加载所有 SSH 密钥。 16.7.1.2.SSH 隧道 ~~~~~~~~~~~~~~~~~ OpenSSH 能够创建一个隧道,将另一个协议封装在加密会话中。 以下命令让 ``ssh`` 为 telnet 创建隧道: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session % ssh -N -f -L 5023:localhost:23 user@foo.example.com % 此示例使用以下选项: - **-N** 代表不执行命令,只建立隧道。如果省略,则 ``ssh`` 将会初始化一个正常的会话。 - **-f** 强制 ``ssh`` 在后台运行。 - **-L** 代表 *本地端口:远程主机:远程端口* 格式的本地隧道。 - **user@foo.example.com** 要在指定的远程 SSH 服务器上使用的登录名。 SSH 隧道的工作原理是在指定的 ``本地主机`` 的 ``本地端口`` 上创建一个监听套接字。然后,它把在 ``本地端口`` 上收到的任何连接通过 SSH 连接转发到指定的 ``远程主机:远程端口``\ 。在这个例子中,客户端的 ``5023`` 端口被转发到远程机器的 ``23`` 端口。由于端口 ``23`` 是由 ``telnet`` 使用的,这就通过 SSH 隧道创建了一个加密的 telnet 会话。 此方法可用于封装任意数量的不安全 TCP 协议,如 SMTP、POP3 和 FTP,如以下示例所示。 **例 29.为 SMTP 创建安全隧道** .. code:: shell-session % ssh -N -f -L 5025:localhost:25 user@mailserver.example.com user@mailserver.example.com's password: ***** % telnet localhost 5025 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220 mailserver.example.com ESMTP 可以与其他用户帐户结合使用 ``ssh-keygen``\ ,以创建更加无缝的 SSH 隧道环境。可以使用密钥代替键入密码,并且可以以单独的用户运行隧道。 .. **例 30.POP3 服务器的安全访问** 在此示例中,有一个 SSH 服务器接受来自外部的连接。在同一网络上驻留着运行 POP3 服务器的邮件服务器。要以安全的方式检查电子邮件,请创建与 SSH 服务器的 SSH 连接,并通过隧道连接到邮件服务器: .. code:: shell-session % ssh -N -f -L 2110:mail.example.com:110 user@ssh-server.example.com user@ssh-server.example.com's password: ****** 一旦隧道启动并运行,将电子邮件客户端指向 ``2110`` 端口的本地主机发送 ``POP3`` 请求。这个连接将被安全地通过隧道转发到 ``mail.example.com``\ 。 **例 31.绕过防火墙** 某些防火墙会过滤传入和传出连接。例如,防火墙可能会将从远程计算机到端口 22 和 80 的访问限制为仅允许 SSH 和浏览网页。这将阻止任何访问使用 22 或 80 以外的端口的其他服务。 解决方案是创建与网络防火墙外部的计算机的 SSH 连接,并使用它来通过隧道连接到所需的服务: .. code:: shell-session % ssh -N -f -L 8888:music.example.com:8000 user@unfirewalled-system.example.org user@unfirewalled-system.example.org's password: ******* 在此示例中,Ogg Vorbis 流媒体客户端现在可以指向 ``本地主机`` 端口 8888,该端口将被转发到 ``music.example.com`` 端口 8000 上,成功绕过防火墙。 16.7.2.启用 SSH 服务器 ---------------------- 除了提供内置的 SSH 客户端之外,FreeBSD 系统还可以配置为 SSH 服务器,接受来自其他 SSH 客户端的连接。 要查看 sshd 是否正在运行,请使用 `service(8) `__ 命令: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # service sshd status 如果服务未运行,请将以下行添加到 **/etc/rc.conf**\ : .. raw:: latex \diilbookstyleinputcell .. code:: shell-session sshd_enable="YES" 这将在下次系统启动时启动 sshd,即 OpenSSH 的守护程序。要立即启动: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # service sshd start 当首次在 FreeBSD 系统上启动 sshd 时,将自动创建系统的主机密钥,指纹将显示在控制台上。可为用户提供指纹,以便他们可以在首次连接到服务器时进行验证。 有关启动 sshd 时可用选项的列表,以及有关身份验证、登录过程和各种配置文件的更完整讨论,请参阅 `sshd(8) `__\ 。 此时,sshd 应可供系统上具有用户名和密码的所有用户使用。 16.7.3.SSH 服务器安全性 ----------------------- 虽然 sshd 是 FreeBSD 中使用最广泛的远程管理工具。但暴力破解和路过式攻击对于任何暴露在公共网络中的系统都是常见的。有几个其他参数可用于防止这些攻击的成功,本节将对此进行介绍。 使用 OpenSSH 服务器配置文件中的 ``AllowUsers`` 关键字来限制哪些用户可以登录 SSH 服务器以及从哪里登录是一个好主意。例如,要想只允许 ``root`` 从 ``192.168.1.32`` 登录,请在 **/etc/ssh/sshd_config** 中添加这一行: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session AllowUsers root@192.168.1.32 要允许 ``admin`` 从任何位置登录,请列出该用户而无需指定 IP 地址: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session AllowUsers admin 多个用户应列在同一行中,如下所示: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session AllowUsers root@192.168.1.32 admin 对 **/etc/ssh/sshd_config** 进行更改后,请执行以下内容以使 sshd 重新加载其配置文件: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # service sshd reload .. **注意** 使用此关键字时,列出所有需要登录此计算机的用户非常重要。任何未在该行中指定的用户都将被锁定。此外,OpenSSH 服务器配置文件中使用的关键字区分大小写。如果关键字拼写不正确(包括其大小写),则将忽略该关键字。要一直测试对此文件所做的更改,以确保编辑工作按预期进行。请参阅 `sshd_config(5) `__ 以验证可用关键字的拼写和用法。 此外,用户可能会被强制要求通过使用公钥和私钥使用双重认证。当需要时,用户可以通过使用 `ssh-keygen(1) `__ 生成密钥对,并向管理员发送公钥。如上面的客户端部分所述,此密钥文件将放置在 **authorized_keys**\ 。若要强制用户仅使用密钥,可以配置以下选项: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session AuthenticationMethods publickey .. **技巧** 不要将 ``/etc/ssh/sshd_config`` 与 ``/etc/ssh/ssh_config`` 相混淆(请注意第一个文件名中多出的 ``d``\ )。第一个文件用于配置服务器,第二个文件用于配置客户端。请参阅 `ssh_config(5) `__ 了解可用于客户端设置的详单。