香港服务器SSH端口暴露有风险吗:如何限制登录来源并检查密钥权限

香港服务器的 SSH 端口直接暴露在公网,有风险,但不代表服务器已经失守。公网可达意味着端口可能被持续扫描,也可能遭遇密码猜测、无效账号尝试或针对 SSH 配置缺陷的攻击。风险是否可控,取决于 SSH 是否只接受必要来源、是否允许不安全的认证方式,以及登录密钥和目录权限是否可靠。
验收时不要只看“22 端口是否开放”或“端口是否改成了其他数字”。更有价值的判断是:
- 未授权网络是否无法建立 SSH 连接,或至少无法进入认证流程;
- 允许来源是否能够使用预期账号和公钥正常登录;
- 是否关闭不需要的密码认证和 root 直接登录;
- 用户家目录、
.ssh目录及authorized_keys是否由正确账号拥有,且不允许其他用户写入; - 修改配置前是否有备用管理通道、配置备份和明确回滚方法。
下面以常见 Linux 系统为例。执行前先确认系统发行版、SSH 服务名、当前监听端口、允许登录的账号,以及管理端实际公网出口地址。不要直接把示例中的用户名和 IP 写入生产配置。
先建立现状和备用通道
不要在唯一会话中修改 SSH
SSH 配置或防火墙规则修改错误,可能导致新的连接全部失败。执行任何访问控制变更前,至少保留以下一种备用入口:
- 已经登录并保持可用的第二个 SSH 会话;
- 云平台提供的网页终端、串口或远程控制台;
- 已验证可用的堡垒机或 VPN 管理入口。
同时确认管理端真正使用的公网出口地址:
curl -4 https://ifconfig.me
如果管理端可能通过 IPv6 访问,还要单独确认 IPv6 地址。只把 IPv4 地址加入白名单,而 SSH 同时监听 IPv6,仍可能留下未限制的访问入口。
办公电脑的私有地址,例如 192.168.x.x 或 10.x.x.x,通常不是服务器看到的来源地址。白名单应使用实际出口公网 IP、VPN 网段或堡垒机地址。若办公出口地址经常变化,不适合把某个临时 IP 当作长期唯一入口,应优先确认固定出口、VPN 或备用控制台方案。
确认系统、服务名和监听端口
先查看系统信息和 SSH 服务单元:
cat /etc/os-release
systemctl list-unit-files | grep -E '^ssh(d)?\.service'
再查看当前监听情况:
sudo ss -ltnp
重点记录 SSH 实际监听的端口,以及监听地址:
0.0.0.0:<端口>表示监听所有 IPv4 地址;[::]:<端口>表示监听所有 IPv6 地址;- 只监听某个内网或管理地址,暴露面可能小于监听全部地址,但仍需结合网络路径验证。
不要只凭端口号判断风险。SSH 使用 22 端口、2222 端口或其他端口,都不改变“是否允许不必要来源连接”这一核心问题。
查看当前生效配置:
sudo sshd -T | grep -E '^(port|listenaddress|permitrootlogin|passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|allowusers|allowgroups)'
如果命令报错,不要继续 reload 或 restart 服务,应先处理配置语法问题。若配置使用了 Match 条件,针对实际账号和来源进一步查看:
sudo sshd -T -C user=admin,addr=203.0.113.24 \
| grep -E '^(port|listenaddress|permitrootlogin|passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|allowusers|allowgroups)'
其中 admin 和 203.0.113.24 应替换为实际登录账号与来源地址。
先备份配置
修改主配置前保存备份:
sudo cp -a /etc/ssh/sshd_config \
/etc/ssh/sshd_config.bak.$(date +%F-%H%M%S)
sudo ls -la /etc/ssh/sshd_config.d 2>/dev/null
确认主配置是否包含独立配置目录:
sudo grep -nE '^[[:space:]]*Include[[:space:]]+' /etc/ssh/sshd_config
如果存在类似配置:
Include /etc/ssh/sshd_config.d/*.conf
可以使用独立文件保存访问控制规则,减少直接改动主配置的范围。若目录中已经存在同名配置文件,先备份该文件,不要直接覆盖。
备份文件最好同步保存到服务器之外的安全位置,并确保云控制台或其他备用入口仍然可用。备份的价值在于发生配置错误时能恢复,不是为了在无法登录后才临时寻找文件。
限制 SSH 的登录来源
用账号和来源建立最小允许范围
假设需要允许的账号是 admin,办公出口是 203.0.113.24,VPN 网段是 198.51.100.0/24,可以在独立配置文件中写入:
AllowUsers admin@203.0.113.24 admin@198.51.100.0/24
创建配置文件前,确认实际用户和来源确实如此:
getent passwd admin
id admin
写入配置:
sudo tee /etc/ssh/sshd_config.d/20-access-control.conf >/dev/null <<'EOF'
AllowUsers admin@203.0.113.24 admin@198.51.100.0/24
EOF
AllowUsers 启用后,未列出的用户即使公钥正确,也不能通过 SSH 登录。服务器如果还有部署账号、自动化账号或监控账号,必须先确认它们是否确实需要远程登录,并将必要账号及其来源一并纳入设计。
也可以按用户组控制:
AllowGroups sshlogin
使用前确认目标账号已经加入该组:
getent group sshlogin
id admin
如果账号不在该组中,启用规则后会直接影响其 SSH 登录权限。加入或调整用户组前,应保持备用会话可用,并在新会话中完成验证。
正常与异常的分界可以这样判断:
| 检查项 | 正常状态 | 异常状态 |
|---|---|---|
| 允许账号 | 只有确实需要远程管理的账号 | 任意普通账号、停用账号或未知账号均可尝试登录 |
| 允许来源 | 固定办公出口、VPN 网段或堡垒机 | 所有公网地址均可进入 SSH 认证 |
| IPv4/IPv6 | 实际使用的地址族都已验证 | 只限制 IPv4,但 IPv6 仍监听且未限制 |
| 未授权来源测试 | 连接被拒绝、超时或认证阶段明确失败 | 未授权网络能够正常进入目标账号 |
| 生效配置 | sshd -T 与预期一致 | 文件看似正确,但有效配置仍允许更大范围 |
表中的“连接被拒绝、超时或认证失败”可能分别来自防火墙和 SSH 服务层。验收时关键不是强求某一种错误提示,而是确认未授权来源无法成功登录,并能用日志说明拒绝发生在哪一层。
配合主机或云侧防火墙
SSH 配置限制的是服务层访问,主机防火墙或云侧访问控制可以在更早阶段阻断来源。先识别当前使用的防火墙方式,不要在不了解现有规则的情况下同时启用多个管理工具:
sudo ufw status verbose 2>/dev/null
sudo firewall-cmd --state 2>/dev/null
sudo nft list ruleset 2>/dev/null | head -n 80
使用 UFW 的系统
先保存并查看现有规则:
sudo ufw status numbered
如果 SSH 当前端口为 22,只允许办公出口访问,可添加精确规则:
sudo ufw allow from 203.0.113.24 to any port 22 proto tcp
如果原来存在对所有来源开放的 22/tcp 规则,不要立即删除。先确认精确来源规则已经添加,并从第二个会话测试成功,再处理旧规则。删除前记录规则编号和完整输出,因为删除或调整规则可能影响远程运维、监控及自动化任务。
如果实际端口不是 22,应把命令中的端口替换为当前 SSH 端口。
使用 firewalld 的系统
查看活动区域和已开放服务:
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --list-all
可以先添加固定来源的运行时规则进行测试:
sudo firewall-cmd \
--add-rich-rule='rule family="ipv4" source address="203.0.113.24" port port="22" protocol="tcp" accept'
从允许来源完成验证后,再决定是否持久化:
sudo firewall-cmd \
--permanent \
--add-rich-rule='rule family="ipv4" source address="203.0.113.24" port port="22" protocol="tcp" accept'
sudo firewall-cmd --reload
如果原来通过 ssh 服务项对所有来源开放,必须先验证精确来源规则,再处理原有开放规则。防火墙删除、重载或区域调整都可能影响远程连接,操作前应保存现有规则作为回滚依据。
检查密钥、目录和账号权限
查看路径、所有者和权限
以 admin 为例,先确认账号的实际家目录:
getent passwd admin
如果家目录确实是 /home/admin,再检查路径上的每一级权限:
sudo namei -l /home/admin/.ssh/authorized_keys
sudo stat -c '%A %a %U:%G %n' \
/home/admin \
/home/admin/.ssh \
/home/admin/.ssh/authorized_keys
较稳妥的验收状态如下:
| 对象 | 建议所有者 | 常见建议权限 | 需要关注的异常 |
|---|---|---|---|
/home/admin | admin:admin | 不应被其他用户或组写入 | 组或其他用户可写 |
/home/admin/.ssh | admin:admin | 700 | 目录可被其他用户写入,或所有者错误 |
authorized_keys | admin:admin | 600 | 文件可被组或其他用户写入 |
| 服务器上的管理员私钥 | 通常不应存在 | 不适用 | 私钥误放在服务器或被其他账号读取 |
OpenSSH 会检查目录和文件的所有权及可写权限。即使 authorized_keys 内容正确,只要父目录可被不可信用户写入,也可能导致认证失败,或形成替换密钥、篡改授权文件的风险。
这里的“建议权限”不是脱离路径和系统策略的绝对结论,最终应结合实际所有者、sshd 有效配置和登录日志判断。验收时至少要证明:目标账号能够读取自己的授权文件,其他不可信账号不能修改它。
在确认路径后修复权限
确认用户名和家目录无误后,再修复目录与文件权限:
sudo chown admin:admin /home/admin
sudo chmod go-w /home/admin
sudo install -d -m 700 -o admin -g admin /home/admin/.ssh
sudo chown admin:admin /home/admin/.ssh/authorized_keys
sudo chmod 600 /home/admin/.ssh/authorized_keys
上述命令会修改所有者和权限,影响目标账号的 SSH 认证。不要对不确定的路径执行递归 chown -R 或递归 chmod,尤其是共享目录、挂载目录和自动化账号目录,否则可能影响其他服务。
修复后重新检查:
sudo stat -c '%A %a %U:%G %n' \
/home/admin \
/home/admin/.ssh \
/home/admin/.ssh/authorized_keys
如果系统启用了 SELinux,权限看起来正常但仍无法读取密钥时,检查安全上下文:
getenforce 2>/dev/null
ls -Zd /home/admin/.ssh /home/admin/.ssh/authorized_keys
确认路径属于标准用户家目录后,可恢复上下文:
sudo restorecon -Rv /home/admin/.ssh
检查授权内容和客户端私钥
查看公钥文件时,只核对密钥类型、指纹或注释,不要把完整密钥粘贴到工单、聊天群或公开日志中:
sudo awk 'NF >= 2 && $1 !~ /^#/ {print NR, $1, $3}' \
/home/admin/.ssh/authorized_keys
重点确认:
- 没有不再使用的旧公钥;
- 没有来源不明的公钥;
- 没有将私钥内容误写入
authorized_keys; - 需要限制用途时,可在公钥前使用
from=、no-agent-forwarding、no-port-forwarding等选项。
客户端私钥应保存在管理员自己的终端,不应复制到香港服务器。客户端可以检查:
stat -c '%A %a %U:%G %n' ~/.ssh/id_ed25519
ssh-keygen -lf ~/.ssh/id_ed25519.pub
私钥通常应仅由当前用户可读,例如权限为 600。如果私钥已经泄露,单纯修改文件权限不能消除风险,应在服务器上删除对应公钥,重新生成密钥对,并重新验证登录。
在关闭密码认证前完成顺序验证
确认公钥登录已经成功,并且仍有备用访问入口后,再考虑关闭不需要的认证方式:
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
这些设置会影响所有 SSH 用户:
- 关闭密码认证后,未配置公钥的账号将无法登录;
- 禁止 root 直接登录后,应先使用普通管理账号登录,再通过
sudo提权; - 如果系统依赖双因素认证或 PAM 交互认证,不应未经确认就关闭
KbdInteractiveAuthentication。
推荐顺序是:
- 先确认目标账号能够使用公钥建立新会话;
- 再限制账号和来源;
- 再关闭不需要的密码或 root 直接登录;
- 每一步都执行语法检查并从新会话验证。
如果还没有完成公钥登录测试,不要先关闭密码认证。否则一旦密钥路径、账号、来源或权限存在问题,可能同时失去密码和密钥两种登录方式。
检查配置、重载服务并进行双向测试
语法检查和安全重载
完成配置修改后,先检查语法:
sudo sshd -t
没有输出通常表示语法检查通过。出现错误时,记录报错行号并修复,不要执行服务重载。
根据实际服务名选择命令:
sudo systemctl reload ssh
或:
sudo systemctl reload sshd
重载后检查服务状态:
sudo systemctl --no-pager --full status ssh
如果系统使用 sshd.service,将命令中的 ssh 替换为 sshd。优先使用 reload,因为它通常不会主动断开已有会话;如果服务不支持 reload,不要在没有备用入口时直接 restart。
重载后再次确认有效配置:
sudo sshd -T | grep -E '^(port|permitrootlogin|passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|allowusers|allowgroups)'
同时查看实际监听状态:
sudo ss -ltnp
“端口正在监听”只能证明服务存在,不能证明来源限制已经生效。必须把有效配置、主机或云侧防火墙规则和外部连接测试结合起来判断。
从允许来源测试
在允许的办公出口、VPN 网段或堡垒机发起新连接:
ssh -vvv -o PreferredAuthentications=publickey admin@服务器地址
如果 SSH 使用非默认端口,补充 -p <实际端口>。
允许来源的成功标准是:
- TCP 连接能够建立;
- 客户端实际使用预期的公钥;
- 服务器接受该公钥;
- 能够进入目标账号;
- 原有管理会话仍然可用。
-vvv 输出可能包含主机名、账号和连接细节,不要未经处理直接公开。验收记录可以保留关键结果,但不应保存私钥或完整敏感凭据。
从不允许来源测试
使用不在允许列表中的网络进行连接,例如另一条未授权的办公出口或临时测试环境:
ssh -vvv admin@服务器地址
根据限制所在层级,未授权来源可能出现:
- 连接超时;
- TCP 连接被拒绝;
- 已建立 TCP 连接,但 SSH 认证阶段被拒绝。
三种结果都需要结合防火墙规则和服务器日志解释。真正的异常是:未授权来源最终能够进入目标账号,或测试结果与配置预期不一致。
允许来源和拒绝来源至少各验证一次,并记录:
- 测试时间;
- 测试来源公网 IP;
- 服务器地址和端口;
- 使用的账号;
- 客户端返回结果;
- 服务器端对应日志。
不要只凭本机一次测试判断规则成功。若测试环境和生产管理端处在同一出口,无法证明其他来源已经被拒绝。
通过日志和配置留证
查看 SSH 服务日志:
sudo journalctl -u ssh -n 80 --no-pager
如果服务名为 sshd:
sudo journalctl -u sshd -n 80 --no-pager
筛选认证成功、失败和预认证阶段信息:
sudo journalctl -u ssh --since "30 minutes ago" --no-pager \
| grep -Ei 'failed|invalid|preauth|accepted|refused'
需要留证的不是某一条孤立日志,而是能够相互对应的四类信息:
sshd -T:证明哪些配置实际生效;ss -ltnp:证明 SSH 监听端口和地址;namei、stat:证明密钥路径的权限与所有者;- 允许和不允许来源的测试结果及对应时间段日志:证明控制措施确实产生了预期效果。
可以保存以下验收输出,但应根据实际端口和服务名调整命令:
{
date -Is
echo '--- effective sshd config ---'
sudo sshd -T | grep -E '^(port|permitrootlogin|passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|allowusers|allowgroups)'
echo '--- listening sockets ---'
sudo ss -ltnp
echo '--- key path permissions ---'
sudo namei -l /home/admin/.ssh/authorized_keys
sudo stat -c '%A %a %U:%G %n' \
/home/admin \
/home/admin/.ssh \
/home/admin/.ssh/authorized_keys
} | sudo tee /root/ssh-acceptance-$(date +%F).txt
留证文件可能包含服务器地址、账号名和监听信息,应限制访问:
sudo chmod 600 /root/ssh-acceptance-$(date +%F).txt
不要把私钥、完整敏感凭据或不必要的完整 authorized_keys 内容写入验收文件。
失败处理与回滚
sshd -t 报错
不要 reload。先根据错误行号检查最近修改的文件。如果是新建的独立配置文件导致,可以暂时移走该文件:
sudo mv /etc/ssh/sshd_config.d/20-access-control.conf \
/etc/ssh/sshd_config.d/20-access-control.conf.disabled
再检查:
sudo sshd -t
确认通过后,根据报错修正配置。不要用空文件覆盖主配置,也不要删除原始备份。
公钥正确但仍提示权限错误
依次检查完整路径、所有者、权限以及 SELinux 上下文:
sudo namei -l /home/admin/.ssh/authorized_keys
sudo stat -c '%A %a %U:%G %n' \
/home/admin \
/home/admin/.ssh \
/home/admin/.ssh/authorized_keys
重点确认家目录没有被组或其他用户写入,.ssh 及 authorized_keys 属于目标账号,且没有误将目录、挂载点或其他账号路径当成目标路径。
新会话全部无法连接
立即停止继续修改,使用云控制台或备用会话恢复。若是独立 SSH 配置文件导致,可回退:
sudo mv /etc/ssh/sshd_config.d/20-access-control.conf.disabled \
/etc/ssh/sshd_config.d/20-access-control.conf
然后执行:
sudo sshd -t
确认语法通过后,再重载对应服务。若是防火墙规则导致,应按照之前保存的规则记录恢复,不要随意执行“允许所有来源”的临时命令。
AllowUsers 误阻断账号
检查实际生效值:
sudo sshd -T | grep -E '^(allowusers|allowgroups)'
AllowUsers 是全局限制。账号未列入允许列表时,即使公钥、密码和目录权限都正确,也会被拒绝。确认来源 IP 是固定出口还是动态地址后,将确实需要远程管理的账号和来源补入配置,再执行 sshd -t、reload 和新会话验证。
上线或验收检查清单
- [ ] 已确认系统发行版、SSH 服务名、实际端口和监听地址。
- [ ] 已确认管理端实际公网 IPv4,必要时也确认 IPv6。
- [ ] 已保留第二个登录会话、云控制台或其他备用入口。
- [ ] 已备份
/etc/ssh/sshd_config及新增或修改的独立配置文件。 - [ ]
AllowUsers或AllowGroups只包含必要账号。 - [ ] 已限制办公出口、VPN 或堡垒机来源,并验证 IPv4、IPv6 是否都覆盖。
- [ ] 已检查主机防火墙或云侧访问控制,未保留不必要的全公网 SSH 放行规则。
- [ ]
PermitRootLogin、PasswordAuthentication等设置符合实际运维需求。 - [ ] 用户家目录不允许不可信用户写入。
- [ ]
.ssh目录通常为700,authorized_keys通常为600,所有者正确。 - [ ] 已确认服务器上没有误放管理员私钥。
- [ ]
sshd -t通过,服务 reload 后状态正常。 - [ ] 已从允许来源成功使用预期公钥登录。
- [ ] 已从不允许来源验证连接或认证失败。
- [ ] 已保存有效配置、监听状态、权限检查和测试日志。
- [ ] 已记录备份位置、备用入口和明确回滚步骤。
因此,香港服务器 SSH 端口暴露的风险判断,不应简化为“公网开放就是不安全”或“改了端口就安全”。可验收的标准是:不必要来源无法登录,必要来源能够稳定使用正确账号和密钥登录,密钥路径不能被其他用户篡改,配置变更有日志证据并且能够回滚。即使这些项目全部通过,也只能说明当前访问控制和密钥权限达到预期,不能替代对系统及 SSH 软件安全更新状态的独立核查。