保护你的节点安全

本指南旨在引导你采取措施来保护你的节点免受恶意攻击者的侵害。 无论你是在家中运行本地服务器还是在云端运行 VPS 服务器/虚拟机,这里的技巧都将帮助你加固节点以防外部攻击,并在其生命周期内提供保护。

本节将介绍必要操作(你必须采取)和可选操作(有帮助但不是必需的)。

注意

本指南旨在作为一些加固节点机器方法的入门介绍。 如果你熟悉命令行终端并希望进一步保护你的节点,请查看流行的 imthenachoman/How-To-Secure-A-Linux-Server 指南。

本指南的假设

本指南假设你的节点运行 Ubuntu 20.04 LTS。 这些概念适用于其他系统,但示例命令可能不适用。

与本指南中的所有命令一样,我们假设你使用 ssh 远程连接到节点的命令终端。 如果你需要复习如何使用 ssh,请先查看 Secure Shell 介绍 指南。

必要:保持客户端机器的安全

注意

如果你在本地使用 Smartnode(通过直接连接键盘和显示器物理登录),那么本节与你无关 - 你可以跳过它

大多数 Smartnode 运营者通过使用 ssh 从另一台计算机连接到其终端来远程与节点交互:

  • 你连接的机器(在本例中为你的节点机器)称为服务器
  • 你连接的机器(例如你的笔记本电脑、台式机,甚至手机)是客户端

保护 Smartnode 最重要的事情之一就是保持客户端机器的安全。 如果你的客户端机器遭到入侵,并且你使用它登录到节点,那么你应用于节点的大多数安全设置都可以被绕过。

例如:如果你使用笔记本电脑作为 SSH 客户端,并且它安装了键盘记录器,那么你通过 SSH 连接时在节点上键入的任何机密内容(例如密码或恢复助记词)都会被窃取。

没有确定性的指南来保持客户端机器的安全,但意识到它是你安全性的一个因素是良好的第一步。 确保你的客户端机器尽可能安全。

以下是一些技巧:

  • 不要在客户端机器上进行高风险活动(例如访问不可信的网站或安装不必要的程序)
  • 保持客户端机器更新至最新安全补丁
  • 如果可能,为你的操作系统使用恶意软件和反病毒保护程序

为了获得最大的安全性,你可能希望使用专用机器作为 SSH 客户端,尽管这对你来说可能不实用。

必要:保护你的 SSH 访问

注意

如果你在本地使用 Smartnode(通过直接连接键盘和显示器物理登录),那么本节与你无关 - 你可以跳过它

无论你是在家运行 Smartnode 还是在远程数据中心使用 VPS,你很可能通过 SSH 访问它,或者即使你不使用它,SSH 也已启用

SSH 连接基于安全加密,但与任何安全系统一样,真正的安全性来自正确使用它。 你需要为 SSH 设置做两件主要的事情:

  1. 使用 SSH 密钥而不是用户名和密码进行远程登录
  2. 完全禁用基于密码的身份验证,使 SSH 密钥成为唯一的远程登录选项

正如你现在可能熟悉的那样,通过 SSH 登录到节点的默认方式是使用用户名和密码。 这样做的缺点是你的密码通常是相当"短"的东西,容易受到暴力攻击

幸运的是,有另一种通过 SSH 登录的方式:SSH 密钥对

SSH 密钥对的工作方式类似于区块链钱包;它们有公钥部分(如你的钱包地址)和私钥部分(钱包地址的私钥):

  • 你向节点提供公钥部分。这样,节点知道你被允许连接到它,并且知道真的是你在尝试连接。
  • 你在客户端机器上保留私钥部分。这样,只有你(而且只有你)可以连接到你的节点。
    • 你可以(也应该!)用密码保护私钥部分,这样窃取你密钥的人就无法使用它。
  • 从计算机的角度来看,私钥比密码难破解得多。这减轻了针对节点的暴力攻击的风险。
提示

如果你想在创建自己的 SSH 密钥对之前了解更多信息,请查看以下链接:

创建 SSH 密钥对

让我们从在客户端机器上创建新的 SSH 密钥对开始。 有许多类型的密钥,但我们将使用一种名为 ed25519 的密钥类型,它提供出色的安全性。

客户端机器上运行以下命令(即,你不应在已经通过 SSH 连接到节点机器时运行此命令 - 如果是,请先退出 SSH):

ssh-keygen -t ed25519 -C "your_email@example.com"

你将看到以下内容:

Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/username/.ssh/id_ed25519):

这会询问你希望将私钥文件保存在何处。 SSH 与提供的默认值兼容,如果你选择它,将自动为你使用它。 但是,如果你愿意,可以选择将其更改为其他内容。

注意

路径 /home/username/.ssh/id_ed25519 只是一个示例,假设你的用户名是 username。 你可能有不同的用户名。 每当你在本指南中看到类似上述路径时,请将其替换为系统实际打印的带有实际用户名的路径。

如果你对默认设置感到满意,只需按 Enter

否则,输入密钥的所需位置。 它必须是绝对路径(例如在 Linux 上是 /home/username/.ssh/rocketpool_key,或在 OSX 上是 /Users/username/.ssh/rocketpool_key)。 完成后按 Enter

Enter 后,你将看到:

Enter passphrase (empty for no passphrase):

这将成为私钥本身的密码。 每当你使用密钥连接到节点时,都需要首先输入此密码。

警告

你不应该将此留空 - 否则,任何拥有 SSH 密钥文件的人都能够使用它! 选择一个只有你(而且只有你)知道的好密码。

另外,不要忘记你的密码 - 如果丢失此密码,则无法恢复。

输入密码后,按 Enter。 它会要求你重新输入以进行确认。

之后,你将看到类似以下的输出:

Your identification has been saved in /home/username/.ssh/id_ed25519
Your public key has been saved in /home/username/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:CASbPZETiQ83lLhpUO2aoT05TxMVLwqiWtdsRtoPt4s your_email@example.com
The key's randomart image is:
+--[ED25519 256]--+
| .o*==..         |
|. +=O...         |
|..+B++o .        |
|..=.+X o         |
|.+.=+.O S        |
|o.B.oo + .       |
|.  = .  o        |
|    .  . .       |
|      E .        |
+----[SHA256]-----+

第一行说明了私钥的位置,默认名为 id_ed25519(注意它没有文件扩展名)。 如果此私钥文件位于默认位置,Ubuntu 将在你使用 ssh 时自动为你加载此密钥。

第二行说明了公钥的位置,默认名为 id_ed25519.pub。 我们将在下一步需要公钥。

注意

Ubuntu 应该自动加载这个新密钥。 但是,某些系统(例如 macOS 机器)不会自动加载它 - 你必须使用以下命令在客户端机器上告诉它执行此操作:

ssh-add $HOME/.ssh/id_ed25519

请注意,这是我们在上一步生成的私钥的路径,不是公钥。 将路径替换为系统在上一步中打印的路径。

如果你收到 ssh-agent 未运行的错误,请在客户端机器上运行以下命令来启动它:

eval $(ssh-agent)

如果你不想每次打开终端时都输入这两个命令,可以通过向 ~/.bashrc 文件添加 alias 来创建添加密钥的快捷方式。

使用文本编辑器打开文件:

nano ~/.bashrc

在末尾添加此行(假设你使用了私钥的默认路径 - 根据需要更新):

alias loadkey='ssh-add $HOME/.ssh/id_ed25519'

使用 Ctrl+OEnter,然后 Ctrl+X 保存并退出。 接下来,关闭并打开终端以使更改生效。

现在你可以在客户端机器上输入 loadkey 来加载密钥。

将公钥添加到节点

一旦有了 SSH 密钥对,你现在可以将公钥添加到节点。 这将让你使用刚刚生成的私钥通过 ssh 连接到它,而不是使用用户名和密码。

有两种方法可以做到这一点 - 如果一种不起作用,请尝试另一种方法:

使用 ssh-copy-id
手动添加密钥

注意:如果你的客户端机器运行的是 Windows,ssh-copy-id 尚不可用。 请按照"手动添加密钥"选项卡中的说明进行操作。

客户端机器上运行以下命令:

ssh-copy-id -i $HOME/.ssh/id_ed25519.pub username@node.ip.address

例如,如果我在节点上的用户名是 staker,节点的 IP 地址是 192.168.1.10,我将运行以下命令:

ssh-copy-id -i $HOME/.ssh/id_ed25519.pub staker@192.168.1.10

你将看到一些类似以下的消息:

/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/username/.ssh/id_ed25519.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys

这告诉你它首先尝试使用你的密钥登录以确保它还不存在。 一旦登录失败,它就知道可以将新公钥添加到节点机器。

然后它会提示你输入节点机器上用户的密码。 (注意,这不是 SSH 密钥的密码

输入用户密码,你将看到以下输出:

Number of key(s) added: 1

Now try logging into the machine with:   "ssh 'username@node.ip.address'"
and check to make sure that only the key(s) you wanted were added.

这意味着它成功了!

你现在应该能够像平常一样通过 ssh 连接到节点,但现在你不必输入用户帐户的密码。

相反,你必须输入 SSH 私钥的密码。 根据你的系统设置,你可能每次重启时只需执行一次此操作,或者每次使用密钥连接到节点时都必须执行此操作。

禁用通过密码登录

即使你已设置 SSH 密钥对,你的节点仍将允许其他机器尝试使用用户名和密码方法登录。 这违背了使用 SSH 密钥的全部目的,因此下一步是禁用这些。

注意

你即将修改 SSH 服务器的配置。 你所有的现有 SSH 会话都将被保留。 但是,如果你犯了错误,那么你可能无法再创建新的 SSH 会话,并有效地将自己锁定在机器之外。

为了防止这种情况,我们强烈建议你为接下来的步骤创建 2 个 SSH 会话 - 一个用于编辑和测试,另一个作为备份,以便你可以恢复任何破坏性更改。

首先像往常一样使用 ssh 登录到你的机器:

ssh user@your.node.ip.address

提醒一下,你应该在两个单独的终端上执行此操作两次,以便你拥有备份会话以防万一。 你现在可以忽略备份会话 - 我们会告诉你何时需要它。 仅在第一个会话中运行以下命令。

打开 SSH 服务器的配置文件:

sudo nano /etc/ssh/sshd_config

与所有以 sudo 开头的命令一样,这将提示你输入用户帐户的密码。 这是一个大文件,因此你必须使用键盘上的箭头键或 Page Up / Page Down 进行导航。

进行以下更改:

  1. 如果 #AuthorizedKeysFile 被注释掉,则取消注释(通过删除前面的 #
  2. KbdInteractiveAuthentication yes 更改为 KbdInteractiveAuthentication no 并取消注释(通过删除前面的 #) - 注意,较旧版本的 SSH 将此选项称为 ChallengeResponseAuthentication 而不是 KbdInteractiveAuthentication
  3. PasswordAuthentication yes 更改为 PasswordAuthentication no 并取消注释(通过删除前面的 #
  4. PermitRootLogin yes 更改为 PermitRootLogin prohibit-password,除非它已经设置为该值并且前面有 #

完成后,使用 Ctrl+OEnter 保存,然后使用 Ctrl+X 退出。

最后,运行 sudo sshd -T | grep -i passwordauthentication 并确保它打印 passwordauthentication no。 如果没有,你可能还需要运行 sudo nano /etc/ssh/sshd_config.d/50-cloud-init.conf 并将该文件中的 PasswordAuthentication yes 设置为 PasswordAuthentication no。 像以前一样使用 Ctrl+OEnter,然后 Ctrl+X 保存并退出

接下来,重新启动 SSH 服务器以使其采用新设置:

sudo systemctl restart ssh.service

在此之后,通过用户名和密码登录 SSH 应该被禁用。

注意

此时,你应该退出 SSH 会话并尝试重新通过 SSH 登录。 如果你能够成功执行此操作,那么你的 SSH 配置仍然有效!

如果你无法重新登录,那么你的配置出了问题。 使用你在本节开始时创建的备份 SSH 会话来修改 /etc/ssh/sshd_config 文件。

尝试找到错误或撤消更改,然后使用 sudo systemctl restart sshd 重新启动 SSH 服务器。

重新启动后,在"另一个"终端上再次尝试使用 SSH 连接。 继续这样做,直到它再次正常工作并且你能够成功连接。

(可选)启用双因素身份验证

双因素身份验证涉及除密码或 SSH 密钥外还需要第二个安全措施,通常是在与主设备分开的设备上。

例如,你可能熟悉使用密码和 Google Authenticator 代码(或短信代码)登录到网站(例如加密货币交易所)。 这个两步过程是双因素身份验证的一个例子。

SSH 也可以配置为需要 Google Authenticator 代码,这意味着以某种方式破坏了你的 SSH 密钥及其密码的攻击者仍然需要带有身份验证器应用程序的设备(大概是你的手机)。 这为你的系统增加了一层额外的安全性。

警告

我们强烈建议你在第二个终端中打开与节点的 SSH 连接,以防你配置错误。 这样,如果你将自己锁定在外面,你将拥有一个仍然连接的备份,以便你可以轻松撤消错误。

如果你确实设法将自己锁定在外面,你将需要通过其本地显示器和键盘物理访问节点以登录并修复配置错误。

首先在手机上安装 Google Authenticator(或兼容的替代品),如果你还没有的话。 对于 Android 用户,考虑 andOTP,这是一个支持密码锁定和方便备份的开源替代品。

接下来,使用以下命令在节点上安装 Google Authenticator 模块:

sudo apt install -y libpam-google-authenticator

现在告诉 PAM(可插拔身份验证模块)使用此模块。 首先,打开配置文件:

sudo nano /etc/pam.d/sshd

找到 @include common-auth(它应该在顶部)并通过在其前面添加 # 来注释掉它,使其如下所示:

# Standard Un*x authentication.
#@include common-auth

接下来,将这些行添加到文件顶部:

# Enable Google Authenticator
auth required pam_google_authenticator.so

然后使用 Ctrl+OEnterCtrl+X 保存并退出文件。

现在 PAM 知道使用 Google Authenticator,下一步是告诉 sshd 使用 PAM。 打开 sshd 配置文件:

sudo nano /etc/ssh/sshd_config

现在将行 KbdInteractiveAuthentication no 更改为 KbdInteractiveAuthentication yes,使其如下所示:

# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
KbdInteractiveAuthentication yes

(较旧版本的 SSH 将此选项称为 ChallengeResponseAuthentication 而不是 KbdInteractiveAuthentication。)

将以下行添加到文件底部,这向 sshd 指示它同时需要 SSH 密钥和 Google Authenticator 代码:

AuthenticationMethods publickey,keyboard-interactive:pam

然后使用 Ctrl+OEnterCtrl+X 保存并退出文件。

现在 sshd 已设置好,我们需要创建我们的 2FA 代码。 在你的终端中运行:

google-authenticator

首先,它会询问你关于基于时间的令牌。 对此问题回答 y

Do you want authentication tokens to be time-based: y

你现在将在屏幕上看到一个大二维码;使用 Google Authenticator 应用程序扫描它以添加它。 你还会看到你的秘密和一些备份代码,如下所示:

Your new secret key is: IRG2TALMR5U2LK5VQ5AQIG3HA4
Your verification code is 282436
Your emergency scratch codes are:
  29778030
  86888537
  50553659
  41403052
  82649596
注意

将紧急临时代码记录在安全的地方,以防你需要登录到机器但没有 2FA 应用程序。 没有应用程序,你将无法再通过 SSH 连接到机器!

最后,它会询问你一些更多的参数;推荐的默认值如下:

Do you want me to update your "/<username>/.google_authenticator" file: y
Do you want to disallow multiple uses of the same authentication token: y
By default... < long story about time skew > ... Do you want to do so: n
Do you want to enable rate-limiting: y

完成后,重新启动 sshd 以使其获取新设置:

sudo systemctl restart sshd

当你尝试使用 SSH 密钥通过 SSH 连接到服务器时,现在还应该要求你输入 2FA 验证码,但不需要密码。

必要:启用自动安全更新

操作系统供应商定期发布更新和安全修复,因此使用最新补丁保持系统最新非常重要。 最简单的方法是启用自动更新。

节点机器上运行以下命令:

sudo apt update
sudo apt install -y unattended-upgrades update-notifier-common

你可以通过编辑 /etc/apt/apt.conf.d/20auto-upgrades 来更改自动更新设置:

sudo nano /etc/apt/apt.conf.d/20auto-upgrades

这是一个合理的自动更新设置示例:

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";

# This is the most important choice: auto-reboot.
# This should be fine since Rocketpool auto-starts on reboot.
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "02:00";

完成添加更改后,使用 Ctrl+OEnter 保存,然后使用 Ctrl+X 退出。

之后,确保加载新设置:

sudo systemctl restart unattended-upgrades

必要:启用防火墙

通常,你的机器应该只接受执行客户端、共识客户端和 Smartnode 堆栈使用的端口上的网络流量。 为了强制执行这一点并防止任何意外或不需要的流量,我们可以在节点上安装防火墙

注意

如果你在 Rocketpool 设置期间选择了不同的执行/共识客户端端口,则需要编辑下面的端口以反映你的设置。

Ubuntu 默认安装了 ufwuncomplicated fire wall),这是一个用于管理节点防火墙设置的便捷实用程序。

以下命令将为你的 Smartnode 设置 ufw 的良好默认配置。 在节点机器上运行这些命令

禁用连接,除非它们被后续规则明确允许:

sudo ufw default deny incoming comment 'Deny all incoming traffic'

允许 SSH:

sudo ufw allow "22/tcp" comment 'Allow SSH'

允许执行客户端(以前称为 ETH1):

sudo ufw allow 30303/tcp comment 'Execution client port, standardized by Rocket Pool'
sudo ufw allow 30303/udp comment 'Execution client port, standardized by Rocket Pool'

允许共识客户端(以前称为 ETH2):

sudo ufw allow 9001/tcp comment 'Consensus client port, standardized by Rocket Pool'
sudo ufw allow 9001/udp comment 'Consensus client port, standardized by Rocket Pool'

如果你运行 lighthouse 客户端 v4.5.0+,你可以使用 quic 协议来减少延迟/增加带宽,quic 协议默认使用 lighthouse 的 --port + 1 来监听 quic 消息:https://lighthouse-blog.sigmaprime.io/Quic,%20Networking.html

sudo ufw allow 8001/udp comment 'Consensus client port, standardised by Rocket Pool'

最后,启用 ufw

sudo ufw enable
注意

iptables 专家可能会注意到 Docker 绕过 ufw 设置。 严格来说,这意味着除非你在混合模式下运行,否则不需要执行客户端和共识客户端规则。 但是,添加它们没有任何缺点,并且将确保如果你切换到混合模式,你不会遇到防火墙问题。

(可选)启用暴力破解和 DDoS 保护

为了保护你的服务器免受 DDoS 攻击和暴力连接尝试,你可以安装 fail2ban。 此程序将监视传入连接并阻止反复尝试使用错误凭据登录的 IP 地址。

有关入侵防护的更多信息,请参阅本指南

节点机器上运行以下命令:

安装服务:

sudo apt install -y fail2ban

接下来,打开 /etc/fail2ban/jail.d/ssh.local

sudo nano /etc/fail2ban/jail.d/ssh.local

向其中添加以下内容:

[sshd]
enabled = true
banaction = ufw
port = 22
filter = sshd
logpath = %(sshd_log)s
maxretry = 5

你可以更改 maxretry 设置,这是在锁定违规地址之前允许的尝试次数。

完成后,使用 Ctrl+OEnter 保存并退出,然后使用 Ctrl+X

最后,重新启动服务:

sudo systemctl restart fail2ban

至此,你刚刚大大改善了节点的安全态势。 恭喜!