Skip to content

SSH 配置与安全加固

掌握 ~/.ssh/configsshd_config 的配置精髓,以及生产环境安全加固的完整检查清单。

速查卡片

项目内容
客户端配置~/.ssh/config
系统级配置/etc/ssh/ssh_config
服务端配置/etc/ssh/sshd_config
测试配置语法sshd -t
安全密钥生成ssh-keygen -t ed25519
禁用密码登录PasswordAuthentication no
禁用 root 登录PermitRootLogin prohibit-password
修改默认端口Port 2222
限制用户AllowUsers alice bob
查看登录失败journalctl -u sshd | grep Failed
测试客户端配置ssh -G host
开连接复用ControlMaster auto + ControlPersist 10m

客户端配置 —— ~/.ssh/config

配置文件优先级

  1. 命令行选项(最高优先级)
  2. ~/.ssh/config(用户配置)
  3. /etc/ssh/ssh_config(系统全局配置)

第一个匹配的值生效,因此将具体主机配置放在文件开头,通配符默认值放在末尾。

示例一:完整配置示例

# 通配符:适用于所有主机
Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3
    TCPKeepAlive yes
    # 连接复用
    ControlMaster auto
    ControlPath ~/.ssh/controlmasters/%r@%h:%p
    ControlPersist 10m

# GitHub
Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_ed25519_github

# 生产服务器
Host prod-*
    HostName %h.example.com
    User deploy
    Port 2222
    IdentityFile ~/.ssh/prod_ed25519
    LogLevel VERBOSE
    # 禁止 agent 转发
    ForwardAgent no

# 跳板机 + 目标服务器组合
Host internal-db
    HostName 10.0.1.50
    User admin
    ProxyJump bastion
    LocalForward 3306 127.0.0.1:3306

Host bastion
    HostName bastion.example.com
    User jumpuser

# 针对特定命令的配置
Match host *.dev.example.com exec "pwd | grep -q /opt/deploy"
    IdentityFile ~/.ssh/deploy_ed25519

示例二:按网络环境切换配置

# 公司内网(匹配本地网段)
Match localnetwork 10.0.0.0/8
    ProxyCommand none

# 外部网络(用跳板机)
Host *.internal.corp.com
    ProxyJump user@bastion.corp.com

常用配置项速查

配置项默认值推荐值说明
Hostname命令行值实际主机名
User本地用户登录用户名
Port22远程端口
IdentityFile默认密钥私钥路径
ServerAliveInterval060保活间隔(秒)
ServerAliveCountMax33保活失败重试次数
ConnectTimeout10连接超时(秒)
ConnectionAttempts13连接重试次数
StrictHostKeyCheckingaskaccept-new主机密钥检查策略
ForwardAgentnonoAgent 转发(危险)
ForwardX11nonoX11 转发
Compressionnoyes(慢网络)压缩传输
TCPKeepAliveyesyesTCP 保活
ControlMasternoauto连接复用
ControlPersist10m后台保持主连接
ProxyJump跳板机
IdentitiesOnlynoyes仅使用配置指定的密钥
LogLevelINFO日志级别
RequestTTYautoTTY 分配策略
PasswordAuthenticationyesno密码认证
PubkeyAuthenticationyesyes公钥认证
VerifyHostKeyDNSnoDNS SSHFP 验证

条件匹配(Match)

Match 块是 Host 块的增强版,支持更灵活的条件:

text
Match [canonical] [final] [exec command] [localnetwork CIDR] \
      host pattern user pattern localuser pattern ...
    # 仅在此条件满足时生效的配置项
bash
# 仅在公司网络使用特定密钥
Match host *.corp.com localnetwork 10.0.0.0/8
    IdentityFile ~/.ssh/corp_ed25519

# 仅在特定目录下工作时的配置
Match exec "test $(pwd) = /opt/deploy"
    IdentityFile ~/.ssh/deploy_ed25519

# 仅对 SFTP 会话(不执行命令)
Match sessiontype subsystem
    RemoteCommand internal-sftp

Include 拆分管理

text
# 主配置文件 ~/.ssh/config
Include ~/.ssh/config.d/work
Include ~/.ssh/config.d/personal
Include ~/.ssh/config.d/github

服务端配置 —— sshd_config

安全加固配置(推荐基线)

text
# === 端口与监听 ===
Port 2222                              # 修改默认端口
ListenAddress 192.168.1.1              # 仅监听内网 IP
# ListenAddress 0.0.0.0               # 监听所有接口

# === 登录控制 ===
PermitRootLogin prohibit-password      # 禁止 root 密码登录
# PermitRootLogin no                   # 完全禁止 root 登录
AllowUsers alice bob                   # 白名单(最严格)
# DenyUsers mallory                    # 黑名单
# AllowGroups ssh-users                # 允许特定组

# === 认证方式 ===
PubkeyAuthentication yes               # 启用公钥认证
PasswordAuthentication no              # 禁用密码登录
PermitEmptyPasswords no               # 禁止空密码
AuthenticationMethods publickey        # 强制仅使用公钥
MaxAuthTries 3                         # 最大认证尝试次数

# === Agent/GSSAPI ===
AllowAgentForwarding no                # 禁止 agent 转发(安全)
GSSAPIAuthentication no                # 禁用 GSSAPI

# === 端口转发控制 ===
AllowTcpForwarding no                  # 禁用 TCP 转发(严格)
# AllowTcpForwarding local             # 仅允许本地转发
AllowStreamLocalForwarding no          # 禁用 Unix 套接字转发
GatewayPorts no                        # 远程转发仅绑 127.0.0.1
PermitTunnel no                        # 禁止 TUN 转发

# === X11 与 Pseudo-TTY ===
X11Forwarding no                       # 禁止 X11 转发
PermitTTY yes                          # 允许 TTY(不设 no 会无法交互)

# === 会话控制 ===
MaxSessions 10                         # 单连接最大会话数
MaxStartups 10:30:100                  # 限制并发未认证连接
LoginGraceTime 60                      # 认证超时(秒)
ClientAliveInterval 300                # 客户端保活间隔(秒)
ClientAliveCountMax 3                  # 保活最大重试

# === 日志与信息 ===
LogLevel VERBOSE                       # 详细日志(安全审计)
SyslogFacility AUTH
PrintMotd no                           # 不显示 motd
PrintLastLog yes                       # 显示上次登录信息
Banner /etc/ssh/banner                 # 登录前警告横幅

# === 加密策略 ===
# 指定允许的密钥交换算法
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org

# 指定允许的加密算法
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com

# 指定允许的 MAC 算法
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com

# 最小 RSA 密钥长度
RequiredRSASize 2048

# === 其他 ===
UseDNS no                              # 禁用 DNS 反向查询(加速连接)
PermitUserEnvironment no               # 禁止用户设置环境变量
StrictModes yes                        # 检查文件权限

修改配置后重启

bash
# 检查配置文件语法(必须!)
sshd -t

# 如果语法正确,重载配置
systemctl reload sshd    # Linux (systemd)
service sshd reload      # Linux (SysVinit)
launchctl kickstart -k system/com.openssh.sshd   # macOS

常见服务端配置项

配置项默认值安全推荐说明
Port22非标准端口监听端口
PermitRootLoginprohibit-passwordno/prohibit-passwordroot 登录策略
PasswordAuthenticationyesno密码认证
PubkeyAuthenticationyesyes公钥认证
MaxAuthTries63最大认证尝试
LoginGraceTime12060登录宽限时间(秒)
ClientAliveInterval0300保活间隔
X11ForwardingnonoX11 转发
AllowTcpForwardingyesno/localTCP 转发
UseDNSnonoDNS 反向查询
AllowUsers指定用户用户白名单
PermitEmptyPasswordsnono空密码
StrictModesyesyes文件权限检查

安全最佳实践

客户端安全

  1. 使用 Ed25519 密钥:推荐 ssh-keygen -t ed25519
  2. 为私钥设置密码(passphrase):即使私钥泄露也难以直接使用
  3. 使用 ssh-agent 管理密钥:避免频繁输入密码
  4. IdentitiesOnly yes:只使用显式指定的密钥,防止 agent 中的其他密钥被尝试
  5. ForwardAgent no(默认):绝不随意开启 Agent 转发
  6. StrictHostKeyChecking accept-new:首次自动接受但主机密钥变更时拒绝
  7. VerifyHostKeyDNS yes:如果 DNS 配置了 SSHFP 记录
  8. HashKnownHosts yes:known_hosts 中的主机名哈希化
  9. 使用 Host 别名 + HostName:避免长期记住 IP

服务端安全

  1. 禁用密码登录PasswordAuthentication no
  2. 禁用 root 密码登录PermitRootLogin prohibit-password
  3. 限制用户AllowUsers alice bob
  4. 修改默认端口(简单但有效):Port 2222
  5. 部署 Fail2Ban 防暴力破解
  6. 定期审计日志grep "Failed password" /var/log/auth.log
  7. 证书认证(CA) 管理大规模 SSH 密钥
  8. 禁用不安全的旧算法:限制 KexAlgorithms / Ciphers / MACs
  9. 使用 PermitOpen / PermitListen 限制端口转发目标
  10. ChrootDirectory 限制 SFTP-only 用户的环境

Fail2Ban 配置示例

ini
# /etc/fail2ban/jail.local
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600

常见误区

❌ 错误做法✅ 正确做法
私钥无密码保护ssh-keygen -t ed25519 时设置强密码
ForwardAgent yes 在所有主机仅在可信主机开启,或使用 ProxyJump 替代
StrictHostKeyChecking no使用 accept-new 或首次手动确认
密码登录 + 弱密码禁用密码,仅用公钥认证
PermitRootLogin yes设为 prohibit-passwordno
不限制端口转发AllowTcpForwarding localno
GatewayPorts yes 默认开启保持默认 no,需要时再开启
DSA 密钥(已废弃)使用 Ed25519 或 RSA(≥3072 位)
known_hosts 明文存储主机名ssh-keygen -H 哈希化
使用 SSH-1 协议仅使用 SSH-2

调试与排错

连接问题排查流程

bash
# 1. 用详细日志找出问题阶段
ssh -vvv user@host

# 2. 查看客户端最终生效的配置
ssh -G host | grep -E "hostname|port|user|identityfile"

# 3. 检查权限(私钥必须 600,.ssh 目录必须 700)
ls -la ~/.ssh/
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_*

# 4. 检查服务端日志
ssh user@host 'sudo tail -n 50 /var/log/auth.log'

# 5. 测试密钥是否可用
ssh -i ~/.ssh/id_ed25519 -o IdentitiesOnly=yes user@host

# 6. 检查 known_hosts 冲突
ssh-keygen -R hostname    # 删除旧条目重试

常见报错与解决

报错信息原因解决方案
Permission denied (publickey)密钥未授权或权限问题chmod 600 ~/.ssh/id_*,检查 authorized_keys
Host key verification failed主机密钥变更ssh-keygen -R hostname 删除旧指纹
Connection refused端口错误或 sshd 未运行确认端口和 sshd 状态
Connection timed out防火墙/网络不通检查网络连接和防火墙规则
Too many authentication failuresagent 中密钥过多IdentitiesOnly yesssh-add -D
WARNING: UNPROTECTED PRIVATE KEY FILE私钥权限过宽chmod 600 ~/.ssh/id_*
Bad owner or permissions on ~/.ssh/config配置文件权限过宽chmod 600 ~/.ssh/config
No matching host key type found算法不匹配ssh -Q key 检查,HostKeyAlgorithms +ssh-rsa 兼容旧主机

版本信息

  • OpenSSH 服务端和客户端版本需匹配。在服务器上使用 sshd -?ssh -V 查看版本。
  • 各发行版的 OpenSSH 版本可能落后于上游,apt/yum 安装的版本通常比 man.openbsd.org 文档旧。

来源

来源链接
OpenSSH ssh_config(5) 手册https://man.openbsd.org/ssh_config
OpenSSH sshd_config(5) 手册https://man.openbsd.org/sshd_config
OpenSSH 安全指南https://infosec.mozilla.org/guidelines/openssh
Fail2Ban 项目https://github.com/fail2ban/fail2ban