Linux VPS上的SSH安全加固:sshd_config完整配置指南
在Debian 12或Ubuntu 24.04 VPS上锁定SSH。Ed25519密钥生成、sshd_config加固、ProxyJump跳板机配置、加密算法优化、ssh-audit验证。每一步都有验证环节。
SSH是服务器的大门。VPS上线几分钟内,自动化机器人就会开始扫描22端口。本指南将逐步讲解在Debian 12(OpenSSH 9.2)和Ubuntu 24.04(OpenSSH 9.6)上加固sshd_config所需的每一项配置,每次修改后都有验证步骤,确保配置生效。
前提条件
你需要:
- 一台运行Debian 12或Ubuntu 24.04的VPS(全新或已有均可)
- 一个拥有sudo权限的非root用户
- 一个已打开的第二终端或SSH会话(修改配置时需要用它来测试,避免把自己锁在外面)
本指南是Linux VPS安全:威胁、层级与加固指南系列的一部分。完成SSH加固后,接下来配置自动暴力破解防护 。
如何为VPS生成安全的SSH密钥?
在本地机器(笔记本电脑或工作站,不是服务器)上生成Ed25519密钥。Ed25519生成256位密钥,提供128位安全强度,等同于RSA-3072,同时生成和验证速度更快。签名是确定性的(deterministic),不依赖签名时的随机数生成器。这消除了影响RSA的一整类实现攻击。
ssh-keygen -t ed25519 -C "yourname@yourmachine"
你会看到类似这样的输出:
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/yourname/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/yourname/.ssh/id_ed25519
Your public key has been saved in /home/yourname/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:xR5xGk3TOs4mEfW8sBv7g7LkE2PLxYae2TqfGxpfM3Q yourname@yourmachine
设置一个密码短语(passphrase)。如果有人窃取了你的私钥文件,密码短语是他们和你的服务器之间唯一的屏障。
Ed25519与RSA:应该用哪种密钥?
| Ed25519 | RSA-4096 | |
|---|---|---|
| 密钥长度 | 256位 | 4096位 |
| 安全强度 | 约128位 | 约140位 |
| 密钥生成 | 瞬间完成 | 1-5秒 |
| 签名验证 | 更快 | 更慢 |
| 私钥文件大小 | 464字节 | 约3.3 KB |
| 签名时依赖随机数 | 否(确定性) | 是 |
| 兼容性 | OpenSSH 6.5+(2014年) | 通用 |
除非你需要连接运行OpenSSH 6.5以下版本的系统(2026年已非常罕见),否则使用Ed25519。
将公钥复制到服务器
从本地机器执行:
ssh-copy-id -i ~/.ssh/id_ed25519.pub youruser@your-server-ip
如果ssh-copy-id不可用(某些macOS环境),手动复制:
cat ~/.ssh/id_ed25519.pub | ssh youruser@your-server-ip "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
**验证:**从新终端使用密钥认证登录:
ssh -i ~/.ssh/id_ed25519 youruser@your-server-ip
如果你无需输入服务器密码(只需输入密钥的密码短语)就获得了shell,说明密钥认证已生效。
理解Include指令
编辑sshd_config之前,你需要知道:Debian 12和Ubuntu 24.04都在/etc/ssh/sshd_config的顶部包含了Include /etc/ssh/sshd_config.d/*.conf。OpenSSH对大多数指令使用它找到的第一个值。sshd_config.d/中的.conf文件优先于主配置文件中的设置。
检查已有配置:
ls -la /etc/ssh/sshd_config.d/
在Ubuntu 24.04上,如果cloud-init处于活跃状态,通常会看到50-cloud-init.conf。修改前先查看已有文件:
cat /etc/ssh/sshd_config.d/*.conf 2>/dev/null
我们将所有加固配置放在一个最先加载的文件中:
sudo touch /etc/ssh/sshd_config.d/00-hardening.conf
sudo chmod 600 /etc/ssh/sshd_config.d/00-hardening.conf
00-前缀确保我们的文件在其他配置片段之前被读取。chmod 600将读取权限限制为仅root,因为该文件控制着谁可以登录。
本指南中所有sshd_config修改都放入/etc/ssh/sshd_config.d/00-hardening.conf,除非另有说明。
如何禁用SSH密码认证?
禁用密码认证后,只允许密钥登录。暴力破解攻击变得毫无意义,因为没有密码可猜。
打开加固配置文件:
sudo nano /etc/ssh/sshd_config.d/00-hardening.conf
添加:
PasswordAuthentication no
KbdInteractiveAuthentication no
KbdInteractiveAuthentication替代了OpenSSH 9.x中已弃用的ChallengeResponseAuthentication。两者都禁用,以关闭所有基于密码的登录路径。
重启sshd之前,务必验证配置并保持当前会话不关闭。
sudo sshd -t
如果没有输出,说明配置有效。任何错误会打印到终端。
现在重启sshd:
sudo systemctl restart sshd
从第二个终端验证(不要关闭当前会话):
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no youruser@your-server-ip
你应该看到:
youruser@your-server-ip: Permission denied (publickey).
这确认密码认证已关闭。注意输出中显示(publickey)作为唯一允许的方法。这正是我们要的结果。
现在从同一个第二终端确认密钥登录仍然有效:
ssh youruser@your-server-ip
如果两项测试都通过,密码认证已禁用且密钥登录正常。如果密钥登录失败,回到仍然打开的第一个会话修复配置,以免被锁在外面。
如何在Ubuntu和Debian上禁用SSH root登录?
应该关闭通过SSH直接以root身份登录。即使只允许密钥认证,被泄露的root密钥会直接获得完整系统权限,且没有登录者的审计记录。改用普通用户加sudo。
在/etc/ssh/sshd_config.d/00-hardening.conf中添加:
PermitRootLogin no
验证并重启:
sudo sshd -t && sudo systemctl restart sshd
从第二个终端验证:
ssh root@your-server-ip
预期输出:
root@your-server-ip: Permission denied (publickey).
用sshd -T验证设置是否生效(大写T输出运行中的配置):
sudo sshd -T | grep -i permitrootlogin
permitrootlogin no
如何限制SSH访问特定用户和组?
AllowUsers和AllowGroups将SSH登录限制在明确的列表内。不在列表中的人会被拒绝,即使他们有有效的密钥。这是防止意外密钥部署或软件包创建新用户的安全网。
在/etc/ssh/sshd_config.d/00-hardening.conf中添加:
AllowUsers youruser
将youruser替换为你的实际用户名。允许多个用户:
AllowUsers youruser deployer
也可以使用基于组的访问控制(更适合团队):
sudo groupadd sshusers
sudo usermod -aG sshusers youruser
然后在配置中:
AllowGroups sshusers
处理顺序
OpenSSH按以下顺序评估访问权限:DenyUsers、AllowUsers、DenyGroups、AllowGroups。任何阶段的deny都会阻止该用户。如果使用AllowUsers,只有列出的用户可以登录。如果使用AllowGroups,只有列出的组的成员可以登录。可以组合使用,但AllowUsers先被检查。
验证并重启:
sudo sshd -t && sudo systemctl restart sshd
从第二个终端验证:
ssh youruser@your-server-ip
确认你的用户仍然可以登录。然后验证非列表用户会被拒绝:
sudo sshd -T | grep -i allowusers
allowusers youruser
应该设置哪些SSH会话限制?
这些指令限制认证尝试次数、连接超时和未认证连接数。它们减缓暴力破解攻击并清理僵死会话。
在/etc/ssh/sshd_config.d/00-hardening.conf中添加:
MaxAuthTries 3
LoginGraceTime 20
MaxStartups 10:30:60
MaxSessions 3
ClientAliveInterval 300
ClientAliveCountMax 2
各项设置的含义:
| 指令 | 值 | 效果 |
|---|---|---|
| MaxAuthTries | 3 | 每次连接3次认证失败后断开 |
| LoginGraceTime | 20 | 给予20秒时间完成认证,超时断开 |
| MaxStartups | 10:30:60 | 10个未认证连接后,随机丢弃30%的新连接。到60个时丢弃所有新连接。 |
| MaxSessions | 3 | 每个连接最多3个多路复用会话 |
| ClientAliveInterval | 300 | 每300秒(5分钟)发送一次保活包 |
| ClientAliveCountMax | 2 | 2次保活无响应后断开 |
**ClientAliveInterval计算:**实际空闲超时时间为ClientAliveInterval x ClientAliveCountMax。按当前配置:300 x 2 = 600秒 = 10分钟。空闲会话在10分钟无响应后断开。
验证并重启:
sudo sshd -t && sudo systemctl restart sshd
验证:
sudo sshd -T | grep -E "maxauthtries|logingracetime|maxstartups|maxsessions|clientaliveinterval|clientalivecountmax"
maxauthtries 3
logingracetime 20
maxstartups 10:30:60
maxsessions 3
clientaliveinterval 300
clientalivecountmax 2
禁用不必要的转发功能
转发功能扩大了SSH的攻击面。禁用所有你没有在用的功能。
在/etc/ssh/sshd_config.d/00-hardening.conf中添加:
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
PermitTunnel no
验证并重启:
sudo sshd -t && sudo systemctl restart sshd
验证:
sudo sshd -T | grep -E "allowagentforwarding|allowtcpforwarding|x11forwarding|permittunnel"
allowagentforwarding no
allowtcpforwarding no
x11forwarding no
permittunnel no
为什么应该禁用SSH Agent Forwarding?
Agent Forwarding(代理转发)允许远程服务器使用你本地的SSH密钥来认证到其他服务器。听起来方便,但问题在于:在该远程服务器上拥有root权限的任何人都可以劫持你的agent socket(代理套接字)并使用你的密钥。
攻击场景:
- 你启用Agent Forwarding并SSH到服务器A。
- OpenSSH在服务器A上创建一个socket,位于
/tmp/ssh-XXXX/agent.YYYY。 - 在服务器A上拥有root权限的攻击者读取你会话中的
SSH_AUTH_SOCK环境变量。 - 攻击者连接到该socket:
SSH_AUTH_SOCK=/tmp/ssh-XXXX/agent.YYYY ssh user@server-b。 - 服务器B看到一个使用你的密钥的有效认证。攻击者成功进入。
攻击者从未接触你的私钥。他们只需要在你的会话活跃期间拥有中间服务器的root权限。
改用ProxyJump(下一节)。它提供同样的多跳访问,但不会将你的agent socket暴露给任何中间服务器。
如何配置SSH ProxyJump实现跳板机访问?
ProxyJump通过跳板机(bastion)路由你的SSH连接,无需Agent Forwarding。你的密钥始终留在本地机器上。连接是端到端加密的:跳板机只能看到经过加密的流量通过。
命令行用法
ssh -J jumpuser@bastion.example.com targetuser@10.0.1.50
-J参数告诉SSH先连接到跳板机,然后通过隧道到达目标。可以用逗号链接多个跳转:
ssh -J jump1@bastion1,jump2@bastion2 targetuser@10.0.1.50
SSH配置文件设置
日常使用时,在本地机器的~/.ssh/config中添加条目:
Host bastion
HostName bastion.example.com
User jumpuser
IdentityFile ~/.ssh/id_ed25519
Host internal-app
HostName 10.0.1.50
User appuser
ProxyJump bastion
IdentityFile ~/.ssh/id_ed25519
Host internal-db
HostName 10.0.2.100
User dbadmin
ProxyJump bastion
IdentityFile ~/.ssh/id_ed25519
现在可以直接连接内部服务器:
ssh internal-app
SSH自动处理跳板机中转。
加固跳板机
在跳板机上限制jump用户的操作。在跳板机的sshd_config中添加:
Match User jumpuser
PermitTTY no
X11Forwarding no
PermitTunnel no
ForceCommand /usr/sbin/nologin
AllowTcpForwarding yes
这允许TCP转发(ProxyJump需要),但阻止jump用户获取shell、执行命令或使用X11。如果跳板机被攻破,攻击者得到的只是一个没有shell权限的纯转发账户。
哪些SSH加密算法和密钥交换算法是安全的?
OpenSSH默认的加密算法列表包含为向后兼容而保留的算法。移除弱算法可以缩小攻击面。以下建议针对OpenSSH 9.2+(Debian 12)和9.6+(Ubuntu 24.04)。
首先,仅使用Ed25519重新生成主机密钥,并移除所有DSA或ECDSA密钥:
sudo rm -f /etc/ssh/ssh_host_*key*
sudo ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ""
sudo ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N ""
我们保留一个RSA主机密钥,用于不支持Ed25519的客户端(很少见,但可以避免锁定)。
接下来,移除弱Diffie-Hellman模数(moduli)(小于3072位的组):
sudo awk '$5 >= 3071' /etc/ssh/moduli > /tmp/moduli.safe
sudo mv /tmp/moduli.safe /etc/ssh/moduli
sudo chown root:root /etc/ssh/moduli
sudo chmod 644 /etc/ssh/moduli
在/etc/ssh/sshd_config.d/00-hardening.conf中添加:
HostKeyAlgorithms ssh-ed25519-cert-v01@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256
KexAlgorithms sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512
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
| 类别 | 算法 | 说明 |
|---|---|---|
| 密钥交换 | sntrup761x25519、curve25519、DH group16/18 | sntrup761是后量子混合算法。curve25519是当前标准。 |
| 加密算法 | ChaCha20-Poly1305、AES-256-GCM、AES-128-GCM、AES-CTR | ChaCha20优先:在没有AES-NI的软件环境中更快。GCM是认证加密。 |
| MAC | HMAC-SHA2 ETM、UMAC-128 ETM | 仅使用ETM(Encrypt-then-MAC,先加密后MAC)模式。非ETM模式更弱。 |
| 主机密钥 | Ed25519、RSA(SHA-2) | 不用DSA(已被破解)。不用ECDSA(NIST曲线信任问题)。 |
验证并重启:
sudo sshd -t && sudo systemctl restart sshd
**从第二个终端验证你仍然可以连接。**如果你的SSH客户端不支持这些算法中的任何一个(客户端非常旧),你会收到"no matching cipher"错误。此时,更新客户端或临时添加回所需的算法。
配置登录横幅
隐藏SSH版本信息并显示法律警告横幅:
sudo nano /etc/ssh/banner.txt
Authorized access only. All activity is monitored and logged.
保持简短。包含系统信息的长横幅会帮助攻击者识别你的操作系统。
在/etc/ssh/sshd_config.d/00-hardening.conf中添加:
Banner /etc/ssh/banner.txt
DebianBanner no
DebianBanner no从SSH协议横幅中移除Debian/Ubuntu版本字符串。版本泄露帮助攻击者针对你特定OpenSSH版本的已知漏洞发起攻击。
验证并重启:
sudo sshd -t && sudo systemctl restart sshd
从本地机器验证:
ssh -v youruser@your-server-ip 2>&1 | grep "banner"
完整的加固sshd_config参考
以下是本指南中所有设置的完整/etc/ssh/sshd_config.d/00-hardening.conf:
# Authentication
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
AuthenticationMethods publickey
# Access control
AllowUsers youruser
# Session limits
MaxAuthTries 3
LoginGraceTime 20
MaxStartups 10:30:60
MaxSessions 3
ClientAliveInterval 300
ClientAliveCountMax 2
# Forwarding restrictions
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
PermitTunnel no
# Cryptography
HostKeyAlgorithms ssh-ed25519-cert-v01@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256
KexAlgorithms sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512
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
# Banner
Banner /etc/ssh/banner.txt
DebianBanner no
# Logging
LogLevel VERBOSE
LogLevel VERBOSE记录额外的详细信息,包括用于认证的密钥指纹。对于审计谁用哪个密钥登录非常有用。
写入此文件后,重启前务必验证:
sudo sshd -t && sudo systemctl restart sshd
查看完整的生效配置:
sudo sshd -T
这会输出每个活跃设置,包括默认值。通过grep管道检查特定值:
sudo sshd -T | grep -E "permitrootlogin|passwordauthentication|allowusers"
permitrootlogin no
passwordauthentication no
allowusers youruser
如何使用ssh-audit验证SSH加固效果?
ssh-audit扫描你的服务器,将每个算法评级为good、warning或fail。加固完成后运行它,确认所有项都通过。
在本地机器或另一台服务器上安装(不要装在目标服务器上):
pip3 install ssh-audit
或者在Debian/Ubuntu上用apt安装:
sudo apt update && sudo apt install -y ssh-audit
扫描你的服务器:
ssh-audit your-server-ip
按照本指南的加固配置,你应该看不到任何[fail]条目。输出从检测到的OpenSSH版本开始,然后列出各算法类别:
# general
(gen) banner: SSH-2.0-OpenSSH_9.6
(gen) software: OpenSSH 9.6
(gen) compression: enabled (zlib@openssh.com)
# key exchange algorithms
(kex) sntrup761x25519-sha512@openssh.com -- [info] available since OpenSSH 8.5
(kex) curve25519-sha256 -- [info] available since OpenSSH 7.4
...
# encryption algorithms (ciphers)
(enc) chacha20-poly1305@openssh.com -- [info] available since OpenSSH 6.5
(enc) aes256-gcm@openssh.com -- [info] available since OpenSSH 6.2
...
如果看到任何[fail]条目,检查你的00-hardening.conf是否被加载(注意Include顺序),以及sshd_config.d/中是否有其他文件覆盖了你的设置。
ssh-audit还内置了加固指南:
ssh-audit --list-hardening-guides
故障排除
被锁在外面了
如果配置修改后无法SSH登录:
- 使用VPS提供商的Web控制台(KVM/VNC)直接登录。
- 修复
/etc/ssh/sshd_config.d/00-hardening.conf。 - 运行
sshd -t验证。 - 重启:
systemctl restart sshd。
这就是为什么我们说:测试完毕前绝不关闭你的当前会话。
配置修改后sshd无法启动
sudo sshd -t
这会打印出错误所在的确切行和文件。常见问题:
- 算法名称拼写错误(逗号分隔的列表中不允许有空格)
- 多个文件中存在重复指令(检查
sshd_config.d/和主sshd_config) AllowUsers中指定了不存在的用户名(sshd可以启动,但没人能登录)
加密算法加固后连接被拒绝
你本地的SSH客户端可能不支持你配置的加密算法。检查客户端支持哪些算法:
ssh -Q cipher
与服务器的列表对比。添加回客户端需要的算法,或更新你的客户端。
查看SSH日志
sudo journalctl -u sshd -f
在从另一个终端尝试连接的同时实时查看日志。认证失败、配置错误和连接中断都会显示在这里。
验证哪个配置文件设置了某个指令
sudo sshd -T | grep passwordauthentication
如果值与你设置的不一致,说明sshd_config.d/中有其他文件覆盖了你的设置。文件按字母顺序加载。我们的00-hardening.conf最先加载,所以对大多数指令它的设置优先。但要检查cloud-init或其他管理工具是否写入了自己的配置。
验证清单
完成所有加固步骤后逐项检查:
- 密码认证已禁用:
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no youruser@server返回"Permission denied" - Root登录已禁用:
ssh root@server返回"Permission denied" - 密钥认证正常:
ssh youruser@server获得shell - AllowUsers生效:
sudo sshd -T | grep allowusers显示你的用户 - 会话限制已设置:
sudo sshd -T | grep maxauthtries显示3 - 转发已禁用:
sudo sshd -T | grep allowagentforwarding显示no - 仅使用强加密算法:
ssh-audit server-ip没有[fail]条目 - 日志正常:
sudo journalctl -u sshd -n 20显示最近的认证条目
SSH加固完成后,配置 自动封禁认证失败的IP。关于网络层面的SSH访问控制,参见 。
Copyright 2026 Virtua.Cloud. All rights reserved.