# 16.7.OpenSSH

OpenSSH 是一组网络连接工具，用于提供对远程机器的安全访问。此外，TCP/IP 连接还可以通过 SSH 连接进行安全地隧道传输或转发。OpenSSH 对所有流量进行加密，以消除窃听、连接劫持和其他网络层攻击。

OpenSSH 由 OpenBSD 项目维护，并在 FreeBSD 中默认安装。

当数据以未加密的形式通过网络发送时，任何位于客户端和服务器之间的网络嗅探器都可能窃取用户/密码信息或会话中传输的数据。OpenSSH 提供多种身份验证和加密方法，以防止这种情况发生。

关于 OpenSSH 的更多信息，请访问 [官方网站](https://www.openssh.com/)。

本节概述了内置的客户端实用程序，用于安全访问其他系统并安全传输文件。然后描述了如何在 FreeBSD 系统上配置 SSH 服务器。

> **技巧**
>
> 如前所述，本章将介绍 OpenSSH 的基本系统版本。OpenSSH 的另一个版本可以在 [security/openssh-portable](https://cgit.freebsd.org/ports/tree/security/openssh-portable/) 中找到，它提供了更多的配置选项，并且会更频繁地更新新功能。

## 16.7.1. 使用 SSH 客户端实用程序

要登录到 SSH 服务器，可以使用 [ssh(1)](https://man.freebsd.org/cgi/man.cgi?query=ssh\&sektion=1\&format=html)，并指定该服务器上存在的用户名以及服务器的 IP 地址或主机名。如果这是首次连接到指定的服务器，用户将被提示先验证服务器的指纹：

```sh
# ssh user@example.com
```

输出类似于以下内容：

```sh
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(1)](https://man.freebsd.org/cgi/man.cgi?query=ssh\&sektion=1\&format=html) 将显示警告。如果发生这种情况，用户应首先验证为何密钥发生了更改，然后再继续连接。

> **注意**
>
> 如何进行此检查超出了本章的范围。

使用 [scp(1)](https://man.freebsd.org/cgi/man.cgi?query=scp\&sektion=1\&format=html) 来安全地复制文件到远程机器或从远程机器复制文件。

以下示例将远程系统上的 `COPYRIGHT` 复制到本地系统当前目录中的同名文件：

```sh
# scp user@example.com:/COPYRIGHT COPYRIGHT
```

输出应该类似于以下内容：

```sh
Password for user@example.com: *******
COPYRIGHT            100% |*****************************|  4735
```

由于之前已验证该主机的指纹，因此在提示输入用户密码之前，服务器的密钥会自动进行检查。

传递给 [scp(1)](https://man.freebsd.org/cgi/man.cgi?query=scp\&sektion=1\&format=html) 的参数类似于 [cp(1)](https://man.freebsd.org/cgi/man.cgi?query=cp\&sektion=1\&format=html)。要复制的文件或文件是第一个参数，复制到的目标是第二个参数。由于文件是通过网络获取的，因此一个或多个文件参数采用 `user@host:<path_to_remote_file>` 的形式。请注意，在递归复制目录时，[scp(1)](https://man.freebsd.org/cgi/man.cgi?query=scp\&sektion=1\&format=html) 使用 `-r`，而 [cp(1)](https://man.freebsd.org/cgi/man.cgi?query=cp\&sektion=1\&format=html) 使用 `-R`。

要打开一个交互式会话以复制文件，请使用 [sftp(1)](https://man.freebsd.org/cgi/man.cgi?query=sftp\&sektion=1\&format=html)。

有关在 [sftp(1)](https://man.freebsd.org/cgi/man.cgi?query=sftp\&sektion=1\&format=html) 会话中可用命令的列表，请参阅 [sftp(1)](https://man.freebsd.org/cgi/man.cgi?query=sftp\&sektion=1\&format=html)。

## 16.7.2. 基于密钥的身份验证

与使用密码不同，客户端可以配置为使用密钥连接到远程机器。出于安全原因，这是首选方法。

可以使用 [ssh-keygen(1)](https://man.freebsd.org/cgi/man.cgi?query=ssh-keygen\&sektion=1\&format=html) 来生成身份验证密钥。要生成公钥和私钥对，请指定密钥类型并按照提示进行操作。建议使用易于记住但难以猜测的密码短语来保护密钥。

```sh
% ssh-keygen -t rsa -b 4096
```

输出应类似于以下内容：

```sh
Generating public/private rsa key pair.
Enter file in which to save the key (/home/user/.ssh/id_rsa):
Created directory '/home/user/.ssh/.ssh'.
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** 中，以使基于密钥的身份验证能够正常工作。

> **警告**
>
> 使用 OpenSSH 密钥的密码短语是一个关键的安全实践，提供了一层额外的保护，以防止未经授权的访问，并增强整体网络安全性。
>
> 如果密码丢失或被窃取，这增加了额外的安全保障。

## 16.7.3. SSH 隧道

OpenSSH 具有创建隧道以将另一个协议封装在加密会话中的能力。

以下命令让 [ssh(1)](https://man.freebsd.org/cgi/man.cgi?query=ssh\&sektion=1\&format=html) 创建隧道：

```sh
% ssh -D 8080 user@example.com
```

此示例使用以下选项：

* **-D**：指定本地“动态”应用程序级别的端口转发。

`user@foo.example.com` 是指定的远程 SSH 服务器上使用的登录用户名。

SSH 隧道通过在指定的 `localport` 上创建一个监听套接字在 `localhost` 上工作。

这种方法可以用来包装任何不安全的 TCP 协议，如 SMTP、POP3 和 FTP。

## 16.7.4. 启用 SSH 服务器

除了提供内置的 SSH 客户端工具外，FreeBSD 系统还可以配置为 SSH 服务器，接受来自其他 SSH 客户端的连接。

> **技巧**
>
> 如前所述，本章将介绍 FreeBSD 系统中内置的 OpenSSH 版本。请**不要**与 [security/openssh-portable](https://cgit.freebsd.org/ports/tree/security/openssh-portable/) 混淆，后者是 FreeBSD ports 提供的 OpenSSH 版本。

要使 SSH 服务器在重启后仍然启用，请执行以下命令：

```sh
# sysrc sshd_enable="YES"
```

然后执行以下命令启用服务：

```sh
# service sshd start
```

第一次在 FreeBSD 系统上启动 sshd 时，系统将自动创建主机密钥，并在控制台上显示指纹。请将指纹提供给用户，以便他们在第一次连接到服务器时进行验证。

有关启动 sshd 时可用选项的更多信息以及关于身份验证、登录过程和各种配置文件的完整讨论，请参考 [sshd(8)](https://man.freebsd.org/cgi/man.cgi?query=sshd\&sektion=8\&format=html)。

此时，所有具有用户名和密码的用户应该能够访问 sshd。

## 16.7.5. 配置公钥认证方法

配置 OpenSSH 使用公钥认证增强了安全性，利用非对称加密进行身份验证。此方法消除了与密码相关的风险，例如弱密码或传输过程中被拦截的风险，同时抵御了各种基于密码的攻击。然而，确保私钥的安全非常重要，以防止未经授权的访问。

第一步是配置 [sshd(8)](https://man.freebsd.org/cgi/man.cgi?query=sshd\&sektion=8\&format=html) 使用所需的认证方法。

编辑 **/etc/ssh/sshd\_config** 文件，取消注释以下配置：

```sh
PubkeyAuthentication yes
```

完成配置后，用户必须将他们的 **公钥** 发送给系统管理员，这些密钥将被添加到 **.ssh/authorized\_keys** 文件中。生成密钥的过程在 [基于密钥的身份验证](https://docs.freebsd.org/en/books/handbook/security/#security-ssh-keygen) 中进行了描述。

然后，执行以下命令重新启动服务器：

```sh
# service sshd reload
```

强烈建议按照 [SSH 服务器安全选项](https://docs.freebsd.org/en/books/handbook/security/#security-sshd-security-options) 中的安全改进建议进行操作。

## 16.7.6. SSH 服务器安全选项

虽然 sshd 是 FreeBSD 最常用的远程管理工具，但暴力破解和随机攻击是任何暴露在公共网络中的系统常见的攻击方式。

为了防止这些攻击的成功，提供了一些额外的参数，以下部分将进行描述。所有配置都将在 **/etc/ssh/sshd\_config** 文件中完成。

> **技巧**
>
> 请注意区分 **/etc/ssh/sshd\_config** 与 **/etc/ssh/ssh\_config** （注意第一个文件名中多了一个 `d`）。第一个文件配置的是服务器，第二个文件配置的是客户端。请参考 [ssh\_config(5)](https://man.freebsd.org/cgi/man.cgi?query=ssh_config\&sektion=5\&format=html) 获取可用的客户端设置列表。

默认情况下，身份验证可以使用公钥和密码进行。为了**仅**允许公钥认证（强烈推荐），请更改以下变量：

```ini
PasswordAuthentication no
```

限制哪些用户可以登录 SSH 服务器以及他们从哪里登录是个好主意，可以使用 OpenSSH 服务器配置文件中的 `AllowUsers` 关键字。例如，要仅允许 `user` 从 `192.168.1.32` 登录，可以将以下行添加到 **/etc/ssh/sshd\_config** 中：

```ini
AllowUsers user@192.168.1.32
```

要允许 `user` 从任何地方登录，可以仅列出该用户，而不指定 IP 地址：

```ini
AllowUsers user
```

多个用户应列在同一行中，如下所示：

```ini
AllowUsers root@192.168.1.32 user
```

在进行所有更改后，在重新启动服务之前，建议执行以下命令验证配置是否正确：

```sh
# sshd -t
```

如果配置文件正确，则不会显示任何输出。如果配置文件不正确，将显示类似以下内容的错误信息：

```sh
/etc/ssh/sshd_config: line 3: Bad configuration option: sdadasdasdasads
/etc/ssh/sshd_config: terminating, 1 bad configuration options
```

在更改并检查配置文件正确后，通过运行以下命令告诉 sshd 重新加载其配置文件：

```sh
# service sshd reload
```
