跳转到内容

正确保护SSH访问:用密钥代替密码、更改端口、配置fail2ban

更新与新闻  ·   ·   ·  5 分钟 阅读时间

简而言之
  • 用密钥登录代替密码登录,可以基本杜绝针对SSH的暴力破解攻击
  • 必须完全禁用root的密码登录——root只能通过密钥登录
  • 更改端口可以减少自动化扫描带来的背景噪音,但不能替代真正的安全防护
  • 一旦登录尝试失败次数过多,fail2ban会自动封禁相应的IP地址

每台开放22端口的root服务器,都会在几分钟内收到第一波登录尝试——发起者不是人,而是全天候扫描各个IP段、寻找开放SSH端口的脚本。大多数尝试都会卡在密码这一关。但也有例外:可能是密码本身太弱,可能是密码此前已在别处泄露,又或者是某项服务本身破坏了身份验证机制——就像Proxmox VE漏洞,该漏洞使攻击者完全无需密码就能以root身份登录那样。针对第二种情况,除了打补丁你做不了太多——但针对第一种情况,你能做的不少。

为什么密码登录才是真正的风险

密码是一个你能记住的秘密——而正是这一点使它容易被攻破。它可以被猜到、可以用字典逐一尝试,也可以从完全不相关的另一项服务的数据泄露中被重复利用。相比之下,SSH密钥对由两部分组成:一个公钥保存在服务器上,一个私钥永远不会离开你的设备。没有私钥,无论尝试多少次,谁都进不去。

最安全的登录尝试,是那种技术上根本不可能发生的尝试——而不是那种在五次密码错误后才被锁定的尝试。
特征密码登录密钥登录
可被暴力破解攻击实际上不会
可能因其他泄露而被重复利用是,如果密码被多处使用否,密钥是唯一的
用户需要记住是,这正是问题所在否,无需记住
丢失后的撤销方式更改密码从authorized_keys中移除公钥

分步操作:保护SSH访问

  1. 生成密钥对。在你自己的电脑上生成,而不是在服务器上。Ed25519是目前的标准算法——比RSA的密钥更短,安全性至少相当。
    ssh-keygen -t ed25519 -C "dein-name@rootserver"
  2. 将公钥传输到服务器。只要密码登录仍然启用,这一步只需一条命令即可完成。此时先不要关闭原有的会话。
    ssh-copy-id -p 22 root@dein-server-ip
  3. 在关闭任何功能之前先测试登录。打开第二个终端窗口,用新密钥登录,同时不要关闭第一个连接。
    ssh root@dein-server-ip
  4. 禁用密码登录和root密码登录。/etc/ssh/sshd_config中设置(或修改)以下几行,然后重启服务。
    PasswordAuthentication no
    PermitRootLogin prohibit-password
    
    systemctl restart sshd
  5. 更改端口。同样在/etc/ssh/sshd_config中修改,然后调整防火墙规则并重启服务。使用1024以上的端口可以避免与其他标准服务发生冲突。
    Port 2222
    
    ufw allow 2222/tcp
    systemctl restart sshd
  6. 安装fail2ban并为SSH启用它。创建独立的jail.local文件,这样系统更新时不会覆盖你的配置。
    apt install fail2ban
    
    # /etc/fail2ban/jail.local
    [sshd]
    enabled = true
    port = 2222
    maxretry = 5
    bantime = 1h
    
    systemctl restart fail2ban
只有在另一个窗口中确认已经可以通过新端口、用新密钥成功登录之后,才能关闭第一个仍然正常工作的SSH会话。否则服务器对你来说就锁死了,只能通过救援控制台重新打开。

更改端口——有意义还是只是摆设?

更改端口本身并不是真正意义上的安全措施,它主要是减少日志中自动化扫描造成的噪音。如果有人专门针对你的服务器进行搜索,即便端口是2222或22022,他们照样能找到——一次简单的端口扫描只需要几秒钟。

支持理由
  • 来自自动化大规模扫描的日志条目明显减少
  • fail2ban及其他分析结果保持清晰易读
  • 一次设置完成后无需额外维护
反对理由
  • 对有针对性的攻击没有防护作用
  • 每次新增防火墙规则或客户端配置时都必须记得考虑到它
  • 无法替代密钥登录和fail2ban,只能作为补充
如果你们多人共用服务器,或者从多台设备访问,请为每台设备生成单独的密钥。这样一来,撤销某一个访问权限时,不需要给其他所有人重新分发新密钥。

检查是否设置成功

完成设置后,在完全信赖新配置之前,值得先做一次简单检查。

  • 测试密码登录:使用错误密钥或不使用密钥进行连接尝试时,必须被拒绝,而不是转而询问密码。
  • 检查端口:ssh -p 2222 root@dein-server-ip必须能够正常连接,而尝试连接22端口应该毫无反应。
  • 查询fail2ban状态:fail2ban-client status sshd会显示当前生效的封禁以及失败尝试的次数。
  • 查看日志:几天之后,/var/log/auth.log(或journalctl -u sshd)中显示的登录尝试次数应该明显比之前少。

如果服务器此后长时间平稳运行,这才是真正的确认——但前提是得有人去查看。如果你不想手动追踪日志,也可以通过我们的监控服务持续检查服务器的可达性。

以上步骤适用于Linux root服务器,具体产品可以在我们的Root服务器概览中查看。如果你同时通过RDP运行Windows服务器,那里适用一套完全不同的规则——相关细节我们已经整理在《保护公开可访问的Windows服务器》一文中。

常见问题

如果我已经使用密钥登录,还有必要更改SSH端口吗?
并非必须。密钥登录已经堵住了真正的攻击途径。更改端口只是为了避免日志被自动化扫描淹没——有用,但不能替代密钥。
如果我不小心把自己锁在外面了怎么办?
通过客户中心里的救援控制台,你可以独立于SSH进入服务器,并在那里修正sshd_config。这也是为什么建议只有在确认新会话可以正常使用后,才关闭旧会话。
只用fail2ban,不禁用密码登录,够用吗?
fail2ban可以拖慢暴力破解的速度,但无法阻止一个被猜中或泄露的密码继续生效。两者结合使用,要比单独使用其中一个稳固得多。
刚订购的全新root服务器也适用这些步骤吗?
适用,你可以在初次安装完成后、服务器正式投入使用之前,直接按这些步骤操作。订购的详细信息见“订购Root服务器”页面。
fail2ban会封禁一个IP地址多久?
这由你自己在jail.local中设定,比如上面示例中的bantime = 1h。对于重复违规的情况,也可以通过bantime.increment配置递增的封禁时长。
Prepaid-Host.com 本身即为服务器、虚拟主机与域名服务商,在此报道的正是自己所处的市场。我们如何处理这一点,见利益披露说明