背景与问题
SSH(Secure Shell)是 Linux 系统远程管理的首选协议,几乎所有服务器的远程管理都依赖 SSH。从简单的命令行登录到文件传输(SFTP)、端口转发、远程命令执行,SSH 是运维工程师每天都要使用的核心工具。
然而,SSH 默认配置存在安全隐患:默认端口 22 面临大量暴力破解攻击;允许密码认证容易被暴力破解或密码泄露;允许 root 直接登录风险极高;SSH 密钥默认没有设置过期机制。 另一方面,很多运维人员在配置 SSH 安全策略时过于激进,禁用了所有登录方式或删除了所有备份方法,结果在网络波动或配置失误时把自己锁在系统外面。
本文详细讲解 SSH 的安全配置方法,同时提供防止把自己锁在系统外面的保障措施。内容包括 SSH 协议原理、认证方式配置、密钥管理、网络层防护、配置文件详解、常见错误分析和应急恢复方法。
1 SSH 协议基础
1.1 SSH 协议版本
SSH 有两个主要版本:SSHv1 和 SSHv2。目前 SSHv1 已完全废弃,所有现代系统都使用 SSHv2。SSHv2 相比 SSHv1 有显著的安全改进,包括更强的加密算法(AES、ChaCha20)、完整的密钥交换协议(Diffie-Hellman)、支持公钥认证和证书。
查看 SSH 版本:
# 查看 SSH 客户端版本 ssh -V # 查看 SSH 服务器版本 sshd -V # 测试 SSH 连接使用的协议版本 ssh -1 user@host # 应该失败 ssh -2 user@host # 使用 SSHv2
1.2 SSH 连接过程
SSH 连接建立分为几个阶段:首先是 TCP 握手建立连接;然后是协议版本交换;接着是密钥交换阶段(Diffie-Hellman 或 ECDH);然后是服务器认证(服务器证明自己的身份);然后是用户认证(密码、公钥或其他方式);最后是会话建立,可以执行命令。
理解这个过程有助于排查 SSH 连接问题:
# 详细查看 SSH 连接过程 ssh -vvv user@host # 输出分为三段:debug1(连接和密钥交换)、debug2(认证过程)、debug3(会话建立)
1.3 SSH 密钥类型
现代 SSH 支持多种密钥类型:RSA 是最广泛支持的类型,推荐使用 4096 位;Ed25519 是现代算法,安全性和性能都很好,推荐使用;ECDSA 依赖曲线参数,不同实现可能存在兼容性问题。
生成 SSH 密钥:
# 生成 RSA 密钥(2048 位,兼容性好) ssh-keygen -t rsa -b 4096 -C"your_email@example.com" # 生成 Ed25519 密钥(推荐,性能好,密钥短) ssh-keygen -t ed25519 -C"your_email@example.com" # 生成 ECDSA 密钥 ssh-keygen -t ecdsa -b 521 -C"your_email@example.com" # 指定密钥存放位置 ssh-keygen -t ed25519 -f ~/.ssh/my_server_key -C"my_server" # 添加密码保护 ssh-keygen -t ed25519 -o -a 100 -C"your_email@example.com" # -o 参数使用 OpenSSH 新格式(更安全) # -a 参数指定密钥推导次数,越高越安全但越慢
2 SSH 服务器配置
2.1 配置文件位置
SSH 服务器配置文件位于/etc/ssh/sshd_config,客户端配置位于~/.ssh/config。本文重点讲解服务器端配置。
配置文件的语法规则:使用空格分隔的键值对;以#开头的是注释;空行被忽略;每个配置项一行。
# 查看默认配置 man sshd_config # 查看当前生效的配置 sshd -T # 检查配置语法(不实际重启服务) sshd -t # 测试配置文件并显示会生效的配置 sshd -T -C user=root,host=localhost,addr=127.0.0.1
2.2 核心安全配置项
以下配置项直接影响 SSH 的安全性:
# 编辑 SSH 服务器配置 vim /etc/ssh/sshd_config # 建议的配置: # 1. 更改默认端口(减少自动化攻击) Port 2222 # 2. 禁用 SSHv1(已废弃,不安全) Protocol 2 # 3. 监听特定地址(如果有多个网卡,指定只监听内网) ListenAddress 0.0.0.0 # 或只监听特定 IP ListenAddress 192.168.1.1 # 4. 禁用空密码 PermitEmptyPasswords no # 5. 禁用密码认证(强烈推荐,使用密钥认证) PasswordAuthentication no ChallengeResponseAuthentication no # 6. 禁用 root 直接登录 PermitRootLogin no # 7. 限制允许登录的用户 AllowUsers admin deploy@192.168.1.0/24 AllowGroups sshusers # 8. 禁用 hosts.equiv 和 .rhosts IgnoreRhosts yes HostbasedAuthentication no # 9. 禁用 GSSAPI 认证(减少攻击面) GSSAPIAuthentication no # 10. 启用公钥认证 PubkeyAuthentication yes # 11. 设置空闲超时 ClientAliveInterval 300 ClientAliveCountMax 2 # 12. 设置登录尝试限制(配合 Fail2Ban 使用) MaxAuthTries 3 MaxSessions 10 # 13. 设置空闲连接断开时间 LoginGraceTime 30 # 14. 禁用用户环境 PermitUserEnvironment no # 15. 禁用 .rhosts 文件 IgnoreUserKnownHosts yes # 16. 打印 motd(可选) PrintMotd no # 17. 禁用 TCP 转发 DisableForwarding yes # 18. 禁用 X11 转发(如果不是必要) X11Forwarding no # 19. 限制子系统(如 SFTP) Subsystem sftp internal-sftp -l INFO # 20. 配置 SFTP 用户的 chroot Match Group sftpusers ChrootDirectory /var/sftp ForceCommand internal-sftp AllowTcpForwarding no X11Forwarding no
2.3 编辑完配置后验证
修改 SSH 配置后,必须验证配置正确才能重启服务:
# 1. 检查配置语法 sshd -t # 2. 如果没有错误输出,说明语法正确 # 3. 查看会生效的配置(详细) sshd -T | grep -E"^passwordauthentication|^permitrootlogin|^pubkeyauthentication" # 4. 重启 SSH 服务 systemctl restart sshd systemctl restart ssh # 5. 确认服务状态 systemctl status sshd
3 公钥认证配置
3.1 公钥认证原理
公钥认证基于非对称加密:客户端持有私钥,公钥放在服务器上;登录时,客户端用自己的私钥签名一段随机数据;服务器用对应的公钥验证签名;验证通过则允许登录。
优点:不会被暴力破解(私钥无法通过猜测获得);无需在网络中传输密码;可以禁用密码认证,消除密码泄露风险;私钥可以设置密码保护。
3.2 配置服务器接受公钥认证
# 服务器端配置 # /etc/ssh/sshd_config PubkeyAuthentication yes AuthorizedKeysFile .ssh/authorized_keys # 限制 authorized_keys 文件的权限 # 服务器端应确保 # .ssh 目录权限 700 # authorized_keys 文件权限 600
3.3 用户端配置和管理
# 生成密钥对 ssh-keygen -t ed25519 # 将公钥复制到服务器(最简单的方式) ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host # 手动复制公钥 cat ~/.ssh/id_ed25519.pub | ssh user@host"mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys" # 服务器端设置权限 ssh user@host"chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys" # 验证权限是否正确 ssh user@host"ls -la ~/.ssh/"
3.4 管理 authorized_keys
# 查看用户的 authorized_keys
ssh user@host"cat ~/.ssh/authorized_keys"
# 添加多个公钥(可以是不同用户、不同机器的)
ssh user@host"cat >> ~/.ssh/authorized_keys"< ~/.ssh/new_key.pub
# 从 authorized_keys 中删除某个公钥
ssh user@host "grep -v 'ssh-rsa AAAAB3...' ~/.ssh/authorized_keys > /tmp/auth_keys && mv /tmp/auth_keys ~/.ssh/authorized_keys"
# 批量管理脚本
#!/bin/bash
# 添加多个用户的公钥到同一个账号
AUTH_KEYS_FILE="$HOME/.ssh/authorized_keys"
USER_KEYS_DIR="$HOME/.ssh/user_keys"
mkdir -p"$USER_KEYS_DIR"
# 为每个用户创建子目录
foruserinalice bob charlie;do
mkdir -p"$USER_KEYS_DIR/$user"
done
# 合并所有公钥(包含注释区分来源)
{
echo"# Alice's keys"
cat"$USER_KEYS_DIR/alice/"*.pub 2>/dev/null
echo"# Bob's keys"
cat"$USER_KEYS_DIR/bob/"*.pub 2>/dev/null
} >"$AUTH_KEYS_FILE"
4 防止把自己锁在系统外面
4.1 修改 SSH 配置前的准备工作
修改 SSH 配置前,必须确保不会把自己锁在外面。正确的操作顺序:
第一步,创建一个备份会话。在修改配置前,先开一个 SSH 会话并保持不退出。这个会话作为紧急恢复通道。
第二步,备份原配置文件:
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup.$(date +%Y%m%d) cp /etc/ssh/sshd_config /root/sshd_config.backup
第三步,使用sshd -t验证配置语法:
sshd -t # 如果没有输出,说明语法正确
第四步,准备远程恢复方法。如果有控制台访问(云平台的控制台、IPMI、iLO、DRAC),确保可以远程登录。记录下控制台登录信息。
4.2 分步修改配置
不要一次性做多个修改,每次只改一个,确认生效后再改下一个:
# 步骤一:只修改端口,保持其他配置不变 # 编辑 /etc/ssh/sshd_config Port 2222 # 验证并重启 sshd -t && systemctl restart sshd # 用新端口测试连接(保持旧会话不退出) ssh -p 2222 user@host # 确认新端口工作正常后,再进行下一步
4.3 使用 ansible 或脚本批量修改
批量修改多台服务器的 SSH 配置时,使用配置管理工具可以减少出错概率:
# ansible 批量修改 SSH 配置
ansible all -i inventory -m lineinfile
-a"path=/etc/ssh/sshd_config
regexp='^Port'
line='Port 2222'"
# 验证配置
ansible all -i inventory -mcommand-a"sshd -t"
# 重启服务
ansible all -i inventory -m systemd -a"name=sshd state=restarted"
4.4 设置 PermitRootLogin 的正确顺序
禁用 root 登录是高风险操作,必须确保有替代方案:
# 第一步:创建替代的 sudo 用户 useradd -m -s /bin/bash admin usermod -aG sudo admin # 第二步:为该用户配置 SSH 公钥登录 ssh-copy-id admin@host # 第三步:测试该用户能否 sudo 到 root ssh admin@host sudo -i # 第四步:确认可以 sudo 后,再禁用 root 登录 # 编辑 /etc/ssh/sshd_config PermitRootLogin no # 第五步:保留一个可用的 root 登录方式(物理控制台或带外管理)
4.5 使用 Fail2Ban 防护暴力破解
Fail2Ban 可以自动封禁多次登录失败的 IP:
# 安装 Fail2Ban apt-get install fail2ban # Debian/Ubuntu yum install fail2ban # RHEL/CentOS # 配置 Fail2Ban cat > /etc/fail2ban/jail.local <
4.6 紧急恢复方法
如果不幸被锁在系统外面,按以下步骤恢复:
方法一:通过控制台登录(云服务器)
大多数云平台提供网页版控制台,可以直接用 root 或其他用户登录,然后修复 SSH 配置。
方法二:通过云平台的用户数据脚本
某些云平台支持在实例启动时执行用户数据脚本,可以用来修复 SSH 配置。
方法三:通过修改启动参数进入单用户模式
重启服务器,在 GRUB 菜单按e编辑启动参数,在linux行末尾添加single或init=/bin/bash,以单用户模式启动,然后挂载根分区为可写,修复 SSH 配置。
方法四:通过云平台的"救援模式"
大多数云平台提供救援模式,可以从 ISO 启动,挂载原系统磁盘,修改 SSH 配置。
# 以 DigitalOcean 为例 # 1. 在控制台创建快照 # 2. 从快照创建新 droplet,选救援模式 # 3. 挂载原磁盘 mount /dev/vda1 /mnt # 4. 编辑 SSH 配置 vim /mnt/etc/ssh/sshd_config # 5. 卸载磁盘 umount /mnt # 6. 从原快照创建新 droplet
5 密钥管理最佳实践
5.1 密钥存储和权限
# 密钥文件权限(非常重要) # 私钥权限必须是 600 chmod 600 ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_rsa # 公钥可以是 644 chmod 644 ~/.ssh/id_ed25519.pub # .ssh 目录权限必须是 700 chmod 700 ~/.ssh # 服务器端 authorized_keys 权限必须是 600 chmod 600 ~/.ssh/authorized_keys # 用户目录不能让其他人有写权限 chmod go-w ~/
5.2 密钥轮换策略
定期更换密钥是良好的安全习惯:
# 创建新密钥 ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_2024 -C"rotation 2024" # 在服务器端添加新公钥 ssh user@host"cat >> ~/.ssh/authorized_keys"< ~/.ssh/id_ed25519_2024.pub # 测试新密钥可以登录 ssh -i ~/.ssh/id_ed25519_2024 user@host # 确认新密钥工作后,从 authorized_keys 中移除旧公钥 ssh user@host "grep -v 'old_key_comment' ~/.ssh/authorized_keys > /tmp/auth && mv /tmp/auth ~/.ssh/authorized_keys" # 本地删除旧私钥 mv ~/.ssh/id_ed25519 ~/.ssh/id_ed25519.old
5.3 使用 SSH Agent 转发
SSH Agent 可以缓存解密后的私钥,避免重复输入密码:
# 启动 SSH Agent eval"$(ssh-agent -s)" # 添加密钥到 Agent ssh-add ~/.ssh/id_ed25519 # 查看 Agent 中的密钥 ssh-add -l # 密钥转发(从跳板机跳转到内网机器,保留密钥访问能力) # 在 .ssh/config 中配置 Host jump-server HostName jumphost.example.com User admin Port 2222 ForwardAgent yes # 或者使用 -A 参数 ssh -A admin@jumphost.example.com
5.4 使用 config 文件管理多服务器
# ~/.ssh/config 示例 # 可以为每个服务器定义独立的配置 # 默认配置 Host * Port 2222 IdentityFile ~/.ssh/id_ed25519 ServerAliveInterval 300 ServerAliveCountMax 2 StrictHostKeyChecking ask # 生产服务器 Host prod-* HostName %h.example.com User admin ForwardAgent no LogLevel INFO # 跳板机 Host jump HostName jumphost.example.com User admin Port 2222 ForwardAgent yes # 数据库服务器(只能从跳板机访问) Host db-1 HostName 192.168.1.100 User dbadmin ProxyJump jump LocalForward 3306 127.0.0.1:3306 # 免密码快捷登录 Host github HostName github.com User git IdentityFile ~/.ssh/github_ed25519
6 连接问题排查
6.1 常见连接错误及解决
错误一:Connection refused
# 检查 SSH 服务是否运行 systemctl status sshd # 检查端口是否监听 ss -tlnp | grep sshd netstat -tlnp | grep sshd # 检查防火墙规则 iptables -L -n | grep 22 ufw status firewall-cmd --list-all
错误二:Permission denied
# 检查用户名是否正确 ssh user@host # 检查密钥是否正确配置 ssh -vvv user@host # 查看详细认证过程 # 检查服务器日志 tail -f /var/log/auth.log journalctl -u sshd -f # 客户端指定密钥 ssh -i ~/.ssh/specific_key user@host
错误三:Connection timeout
# 检查网络连通性 ping -c 4 host traceroute host # Linux tracert host # Windows # 检查端口是否可达 nc -zv host 22 telnet host 22 # 检查是否有 ACL 限制 ssh -b bind_ip user@host
6.2 查看详细连接日志
# 客户端查看详细日志 ssh -vvv user@host # 服务器端查看实时日志 tail -f /var/log/auth.log journalctl -u sshd -f # 调试 SSH 握手 ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 user@host
6.3 检查 SSH 服务状态
# 查看服务状态 systemctl status sshd # 查看监听端口 ss -tlnp | grep sshd # 测试本地 SSH 连接 ssh localhost # 检查 SELinux 上下文(RHEL/CentOS) getsebool -a | grep ssh setsebool -P ssh_sysadm_login on
7 完整的 SSH 安全加固脚本
#!/bin/bash # ssh_hardening.sh - SSH 安全加固脚本 set-euo pipefail BACKUP_DIR="/root/ssh_backups" mkdir -p"$BACKUP_DIR" backup_config() { cp /etc/ssh/sshd_config"${BACKUP_DIR}/sshd_config.$(date +%Y%m%d_%H%M%S)" echo"Backup created in$BACKUP_DIR" } verify_sudo() { if["$(id -u)"-ne 0 ];then echo"This script must be run as root" exit1 fi } verify_admin_user() { if! id admin &>/dev/null;then echo"Creating admin user..." useradd -m -s /bin/bash admin usermod -aG sudo admin fi if[ ! -f"/home/admin/.ssh/authorized_keys"];then echo"WARNING: admin user has no SSH keys configured!" echo"Please add your public key to /home/admin/.ssh/authorized_keys before continuing" read-p"Press Enter to continue anyway..." fi } apply_config() { cat > /etc/ssh/sshd_config <<'EOF' # SSH Server Configuration Port 2222 Protocol 2 ListenAddress 0.0.0.0 # Authentication PermitRootLogin no PubkeyAuthentication yes PasswordAuthentication no ChallengeResponseAuthentication no PermitEmptyPasswords no MaxAuthTries 3 LoginGraceTime 30 # Security IgnoreRhosts yes HostbasedAuthentication no PermitUserEnvironment no PrintMotd no TCPKeepAlive yes # Idle timeout ClientAliveInterval 300 ClientAliveCountMax 2 # Disable unused features X11Forwarding no AllowTcpForwarding no PermitTunnel no AllowAgentForwarding no # SFTP configuration Subsystem sftp internal-sftp -l INFO # Override for SFTP users Match Group sftpusers ChrootDirectory /var/sftp ForceCommand internal-sftp AllowTcpForwarding no X11Forwarding no EOF echo "Configuration applied" } set_permissions() { chmod 644 /etc/ssh/sshd_config # 确保 admin 用户目录权限正确 chown -R admin:admin /home/admin/.ssh chmod 700 /home/admin/.ssh chmod 600 /home/admin/.ssh/authorized_keys } verify_config() { echo "Verifying configuration..." sshd -t && echo "Configuration syntax OK" } restart_service() { echo "Restarting SSH service..." systemctl restart sshd systemctl status sshd --no-pager } main() { echo "SSH Security Hardening Script" echo "============================" verify_sudo verify_admin_user backup_config apply_config set_permissions verify_config echo "" echo "IMPORTANT: Keep your current SSH session open!" echo "Test a new connection before closing this session!" echo "" read -p "Restart SSH service now? (yes/no): " confirm if [ "$confirm" = "yes" ]; then restart_service echo "SSH service restarted. Please test a new connection." else echo "Service restart skipped. Run 'systemctl restart sshd' manually when ready." fi } main "$@"
8 结论
SSH 安全配置需要在安全性和可用性之间取得平衡。过度限制的配置可能导致自己无法登录,合理的安全配置应该既能防止攻击,又能保证管理员正常访问。
核心安全配置建议:更改默认端口减少自动化攻击;禁用密码认证,使用公钥认证;禁用 root 直接登录,使用 sudo;配置 Fail2Ban 防止暴力破解;定期轮换 SSH 密钥。
防止把自己锁在外面的关键:在修改配置前先备份;保持一个不退出 SSH 会话作为恢复通道;分步骤修改配置,每步确认后再进行下一步;使用控制台或带外管理作为最终恢复手段。
-
Linux
+关注
关注
88文章
11825浏览量
219617 -
服务器
+关注
关注
14文章
10377浏览量
91777 -
端口
+关注
关注
4文章
1113浏览量
34052 -
SSH
+关注
关注
0文章
201浏览量
17827
原文标题:SSH 安全配置怎么做,才能既安全又不把自己锁在门外?
文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
VScode终端ssh连接不到Linux服务器问题
以色列政府DNS服务器存在着Open SSH安全漏洞
ssh如何上传文件到服务器
Linux上保护 SSH 服务器连接的方法
在Linux上保护SSH服务器连接的8种方法
Linux上建立SSH安全连接的10种方法
轻量服务器怎么搭建ssh?
深入解析SSH协议,轻松实现安全高效的服务器管理
SSH 远程连接内网 Linux 服务器
详解SSH服务器的安全配置方法
评论