三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

Linux SSH服务端安全配置与优化实战指南

Linux SSH服务端安全配置与优化实战指南

1. 项目概述:为什么SSH配置是运维的“第一道门”

搞Linux运维或者自己搭服务器的朋友,对SSH(Secure Shell)肯定不陌生。它就像你服务器大门的钥匙和门禁系统,远程登录、文件传输、命令执行都靠它。但很多人对SSH的认知,可能就停留在ssh user@ip和改个端口、关个密码登录上。实际上,一个经过深思熟虑的SSH配置,远不止是防暴力破解,它关乎整个系统的访问安全基线、运维效率,甚至是故障恢复的“最后一道保险”。

我见过太多因为SSH配置不当引发的安全事件:从密码被暴力破解导致服务器沦为“肉鸡”,到密钥泄露被内网横向渗透,再到配置过于严格把自己锁在门外,不得不去机房接显示器的尴尬。所以,修改SSH配置绝不是简单地编辑一个/etc/ssh/sshd_config文件,它是一个需要结合安全、便利和可维护性的系统工程。今天,我就结合自己踩过的坑和最佳实践,从头到尾拆解一遍Linux下SSH服务端的配置优化,让你不仅能改,更要知道为什么这么改,以及改错了怎么救回来。

2. SSH服务端核心配置深度解析

SSH的配置文件主要分客户端(ssh_config)和服务端(sshd_config)。我们远程登录,核心是服务端的配置。在动手之前,务必理解一个关键原则:任何对sshd_config的修改,在测试通过前,务必确保有另一个可用的、稳定的登录会话(比如通过控制台、VNC,或者另一个未修改的SSH连接)保持打开状态。这是你操作失误后的“救命稻草”。

2.1 配置文件结构与语法初探

默认情况下,SSH服务端的主配置文件位于/etc/ssh/sshd_config。在修改前,第一件事就是备份:

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%Y%m%d)

这个命令不仅备份,还加上了日期后缀,方便版本管理。

打开配置文件,你会看到很多以#开头的注释行和具体的配置项。SSH配置的语法很简单:

  • #表示注释。
  • 配置项格式为关键字 值,例如Port 22
  • 值可以是数字、字符串(如yes/no)、列表或多个值(用空格分隔)。

一个常见的误区是,以为注释掉的行(前面有#)就是默认值。其实不然,SSH服务有自己内置的默认值,注释行只是说明。修改配置时,你需要找到对应的行,如果存在就去掉#修改值;如果不存在,就在文件末尾或合适位置(通常建议在文件末尾,结构清晰)添加。

2.2 关键安全配置项拆解与选型

安全是SSH配置的重中之重。下面我按优先级列出并解释最关键的几个配置项。

1. 修改默认端口 (Port)这是最广为人知的操作,主要目的是减少自动化脚本的扫描和攻击。

# 将默认的22端口改为一个1024-65535之间的非知名端口,例如 23456 Port 23456

注意:端口号不要用诸如2222、22222这种“看起来像22”的,因为扫描器也会尝试这些常见变种。建议使用一个随机的高位端口。修改后,连接命令需指定端口:ssh -p 23456 user@host

2. 禁用密码登录,强制使用密钥对 (PasswordAuthentication & PubkeyAuthentication)这是提升安全性的核心措施。密码易被暴力破解,而密钥对(公钥加密,私钥本地保存)则安全得多。

# 启用公钥认证 PubkeyAuthentication yes # 禁用密码认证 PasswordAuthentication no

重要心得:在将PasswordAuthentication设为no之前,必须确保你的公钥已经正确添加到服务器的~/.ssh/authorized_keys文件中,并且能用密钥成功登录一次。否则,你会立刻被锁在外面。

3. 禁止root用户直接登录 (PermitRootLogin)即使使用密钥,也不建议直接用root登录。最佳实践是使用普通用户登录,再通过sudo提权。

# 最安全的设置是禁止root以任何方式登录 PermitRootLogin no # 或者,如果确有需要,可以设置为仅允许通过密钥认证登录(比完全禁止稍灵活) # PermitRootLogin prohibit-password

4. 限制用户和用户组登录 (AllowUsers, AllowGroups, DenyUsers, DenyGroups)这是实现最小权限访问原则的利器。比如,你的服务器只允许admindeploy这两个用户登录。

AllowUsers admin deploy

或者,只允许属于ssh-users组的用户登录:

AllowGroups ssh-users

DenyUsersDenyGroups则用于黑名单。通常更推荐使用白名单(Allow*)模式。

5. 启用失败连接限制 (MaxAuthTries, MaxSessions)防止攻击者无限尝试密码或密钥。

# 每个连接最大认证尝试次数,建议设为3-6 MaxAuthTries 3 # 每个网络连接允许的最大会话数,防止单个连接占用过多资源 MaxSessions 10

6. 使用更安全的协议和加密算法 (Protocol, Ciphers, MACs)禁用老旧、不安全的SSHv1协议,并指定强加密算法套件。

# 只使用SSHv2协议 Protocol 2 # 指定优先使用的加密算法(示例,需根据系统支持的算法调整) Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr # 指定消息认证码算法 MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com

实操技巧:不要盲目复制这些算法列表。可以先通过ssh -Q cipherssh -Q mac命令查看当前OpenSSH客户端支持的算法,再从中挑选安全的进行配置。过于严格的算法列表可能导致老版本客户端无法连接。

2.3 性能与可用性调优配置

安全之外,稳定和高效同样重要。

1. 保持连接与心跳 (ClientAliveInterval, ClientAliveCountMax)对于不稳定的网络,或者防止中间防火墙断开空闲连接非常有用。

# 服务器每60秒向客户端发送一次保活消息 ClientAliveInterval 60 # 如果连续3次没有收到客户端响应,则断开连接 ClientAliveCountMax 3

这意味着,一个连接在无响应超过180秒(60*3)后会被断开。

2. 加快登录速度 (UseDNS)在内部网络或DNS解析较慢的环境下,可以关闭SSH服务端的DNS反查,能显著加快登录速度。

UseDNS no

3. 限制监听地址 (ListenAddress)如果服务器有多个IP,但只想让SSH监听在某个内网IP上,可以这样设置:

ListenAddress 192.168.1.100

这样,公网IP就无法通过SSH访问了,增加了另一层隔离。

3. 完整配置实操流程与验证

知道了“是什么”和“为什么”,接下来我们走一遍完整的操作流程,确保万无一失。

3.1 前置准备:密钥对生成与部署

在禁用密码登录前,这是必须完成的步骤。

1. 在本地客户端生成密钥对如果你还没有密钥,在本地机器(比如你的笔记本电脑)上执行:

ssh-keygen -t ed25519 -C “your_email@example.com”

-t ed25519:表示使用Ed25519算法,它比传统的RSA更安全、更快、密钥更短。如果你的老系统不支持,可以用-t rsa -b 4096。 接下来会提示你输入保存密钥的文件路径(直接回车用默认路径~/.ssh/id_ed25519)和密钥的密码(passphrase)。密码可以为空,但设置一个会更安全。

2. 将公钥上传到服务器假设你目前还能用密码登录服务器。

# 方法一:使用ssh-copy-id工具(最方便) ssh-copy-id -p 22 -i ~/.ssh/id_ed25519.pub user@server_ip # 它会自动将公钥追加到服务器对应用户的~/.ssh/authorized_keys文件中 # 方法二:手动操作 # 先在本地查看公钥内容 cat ~/.ssh/id_ed25519.pub # 复制输出内容,然后登录服务器 ssh user@server_ip # 在服务器上,确保.ssh目录存在且权限正确 mkdir -p ~/.ssh chmod 700 ~/.ssh # 将复制的公钥内容追加到authorized_keys文件 echo “粘贴你的公钥内容” >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys

3. 测试密钥登录在另一个终端,尝试使用密钥登录,不要关闭当前的密码登录会话

ssh -i ~/.ssh/id_ed25519 -p 22 user@server_ip

如果成功,说明密钥部署正确。这一步至关重要!

3.2 编辑并应用新配置

1. 编辑配置文件使用你熟悉的编辑器,如vimnano

sudo vim /etc/ssh/sshd_config

根据前面的解析,找到并修改或添加相应的配置项。一个整合了上述建议的基础安全配置示例如下:

# 端口设置 Port 23456 # 协议与算法 Protocol 2 Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com # 认证相关 PubkeyAuthentication yes PasswordAuthentication no PermitRootLogin no # 连接限制 MaxAuthTries 3 MaxSessions 10 # 网络与性能 ClientAliveInterval 60 ClientAliveCountMax 3 UseDNS no # 用户限制(根据实际情况修改) AllowUsers admin deploy

2. 语法检查与配置重载在重启服务前,先检查配置文件语法是否正确,避免因语法错误导致SSH服务无法启动。

sudo sshd -t

如果没有任何输出,表示语法检查通过。如果有错误,它会提示哪一行有问题。

现在,在你的那个“救命”会话(当前通过密码登录的会话)里,重新加载SSH服务配置。重载(reload)比重启(restart)更友好,它不会断开现有连接。

# 对于Systemd系统(如CentOS 7+, Ubuntu 16.04+) sudo systemctl reload sshd # 对于SysVinit系统(如CentOS 6) sudo service sshd reload

3.3 验证新配置

保持“救命”会话不动,打开一个新的本地终端窗口,使用新配置进行连接测试。

测试1:使用新端口和密钥登录

ssh -p 23456 -i ~/.ssh/id_ed25519 admin@server_ip

预期:成功登录。

测试2:尝试使用密码登录(应失败)

ssh -p 23456 admin@server_ip # 或者明确指定密码认证方式 ssh -p 23456 -o PreferredAuthentications=password admin@server_ip

预期:被拒绝,提示“Permission denied (publickey)”。

测试3:尝试root直接登录(应失败)

ssh -p 23456 root@server_ip

预期:被拒绝。

如果所有测试结果符合预期,恭喜你,核心安全配置已生效。现在,你可以放心地退出那个“救命”会话了。如果测试失败,立即在“救命”会话里回滚配置(sudo cp /etc/ssh/sshd_config.bak /etc/ssh/sshd_config并重载服务),然后排查问题。

4. 高级配置与故障排查实录

基本的配置能应对90%的场景,但有些深入的需求和突如其来的故障,需要更高级的知识和排查技巧。

4.1 高级场景配置

1. 为不同用户或组设置不同策略OpenSSH本身不支持在sshd_config里直接为不同用户设置不同端口或认证方式。但可以通过Match块实现一定程度的条件化配置。

# 在文件末尾添加 Match User git # 为git用户强制使用密钥认证,即使全局允许密码 PasswordAuthentication no # 并且只允许执行git相关命令,实现SFTP-only或命令限制 ForceCommand internal-sftp # 限制其可用的加密算法(举例) Ciphers aes128-ctr,aes192-ctr,aes256-ctr Match Group developers # 为developers组允许从特定IP段登录 AllowUsers *@192.168.1.*

Match指令非常强大,可以基于User, Group, Host, Address等条件进行细粒度控制。

2. 启用日志记录与审计详细的日志对于排查连接问题和安全审计至关重要。

# 设置日志级别为VERBOSE,记录详细信息 LogLevel VERBOSE

日志通常位于/var/log/auth.log(Debian/Ubuntu)或/var/log/secure(RHEL/CentOS)。使用sudo tail -f /var/log/auth.log可以实时观察登录尝试。

3. 使用TCP Wrappers进行额外访问控制除了sshd_config中的AllowUsers,还可以使用更古老的但通用的/etc/hosts.allow/etc/hosts.deny文件。

# 在 /etc/hosts.allow 中添加 sshd: 192.168.1.0/24, 10.0.0.5 # 在 /etc/hosts.deny 中添加 sshd: ALL

这个规则表示:只允许192.168.1.0/24网段和10.0.0.5这个IP连接SSH,其他全部拒绝。注意,这需要SSH编译时支持libwrap,现代发行版一般默认支持。

4.2 常见问题与排查技巧

即使再小心,也可能遇到问题。这里记录几个我踩过的坑和解决方法。

问题1:修改端口后无法连接

  • 症状ssh -p 新端口 user@host连接超时或被拒绝。
  • 排查思路
    1. 检查服务是否监听在新端口:在服务器上运行sudo ss -tlnp | grep sshdsudo netstat -tlnp | grep sshd。查看是否有一行显示LISTEN状态,且地址中包含:23456(你的新端口)。
    2. 检查防火墙:这是最常见的原因!Linux自带的防火墙(如firewalldufw)以及云服务商的安全组/网络ACL,都必须放行你的新端口。
      • firewalld:sudo firewall-cmd --add-port=23456/tcp --permanent && sudo firewall-cmd --reload
      • ufw:sudo ufw allow 23456/tcp
      • 云平台:登录控制台,找到安全组规则,添加入站规则。
    3. 检查SELinux:如果启用了SELinux,它可能会阻止SSH绑定到非标准端口。临时解决:sudo semanage port -a -t ssh_port_t -p tcp 23456;永久解决需要修改策略或将其设为允许。

问题2:配置密钥登录后依然被要求输入密码

  • 症状:已经将公钥放入authorized_keys,但登录时仍跳转到密码提示。
  • 排查思路
    1. 检查文件权限:这是**99%**的原因。服务器上.ssh目录权限必须是700authorized_keys文件权限必须是600。用ls -la ~/.ssh/检查。
    2. 检查sshd_config:确认PubkeyAuthentication yes已设置,且没有被后面的Match块覆盖。
    3. 查看详细日志:在客户端连接时添加-vvv参数输出详细调试信息:ssh -vvv -p 23456 user@host。在服务器的/var/log/auth.log中也会看到详细的认证过程日志,会明确提示“Authentication refused: bad ownership or modes for directory /home/user/.ssh”之类的错误。

问题3:修改配置后重载服务失败

  • 症状:执行sudo systemctl reload sshd后,服务状态变为failedinactive
  • 排查思路
    1. 使用sshd -t检查语法:如前所述,这是第一步。
    2. 查看系统日志:使用sudo journalctl -xe -u sshdsudo systemctl status sshd.service查看具体的错误信息。常见错误包括:无效的关键字、错误的值格式、依赖的算法或模块不存在。
    3. 回滚并逐步测试:立即用备份文件恢复配置,重载服务使其恢复正常。然后,将你的新配置一项一项地添加回去,每加一项就重载并测试一次,这样可以快速定位是哪一行配置出了问题。

问题4:连接缓慢

  • 症状:输入命令后到出现登录提示有很长延迟,或登录后执行命令反应慢。
  • 排查思路
    1. 禁用DNS反查:确认UseDNS no已设置。这是导致连接缓慢的经典原因。
    2. 检查GSSAPI认证:尝试在客户端连接时禁用GSSAPI:ssh -o GSSAPIAuthentication=no user@host,如果变快,可以在服务端配置中设置GSSAPIAuthentication no
    3. 网络问题:使用mtrtraceroute检查网络链路。

最后,分享一个我个人的习惯:任何生产环境的SSH配置变更,我都会写成一个Ansible Playbook或Shell脚本。这样不仅可重复、可版本控制,而且在需要回滚或批量部署时极其高效。脚本里会包含备份原配置、部署新配置、语法检查、测试连接(用一个预置的测试密钥)等完整步骤,只有测试连接通过了,才真正重启服务。这套流程让我在无数次配置变更中保持了从容。

← 返回列表