如何加固 SSH 服务器配置
最后更新:
sshd_config 这一个文本文件,就是你的 SSH 服务器的全部安全姿态——而在多数系统上,它出厂时的状态是为兼容性优化的,不是为安全:密码登录默认开启、root 只要用密钥就能登录、空闲会话永不超时、服务器提供的算法取决于多年前安装的那个 OpenSSH 版本。加固它不是照抄一份 2021 年的清单:算法会被移除、默认值会变、五年前堪称典范的配置今天可能已经薄弱。本文讲清每一项改动实际做了什么、决策顺序为什么重要、以及如何测试新配置而不把自己锁在门外。你可以在SSH 服务器配置审计里逐行审计自己的文件——对照 2026-11-13 的基线,全程在浏览器本地完成。
默认值是起点,不是加固姿态
OpenSSH 的默认值是为了让全新安装对尽可能多的人开箱即用而选的——这正是它们不是安全姿态的原因。按 sshd_config 手册页记载的当前默认值,包括 PasswordAuthentication yes、PermitRootLogin prohibit-password、MaxAuthTries 6、LoginGraceTime 120 秒,以及 ClientAliveInterval 0,即空闲会话永不终止。这些都不是 bug:每一项都是有意的兼容性选择,而每一项在加固审计里都是一条发现。
实际后果是,一台从未加固过的服务器仍然可以被密码猜解、仍然接受用被盗密钥的 root 登录、仍然让被遗弃的会话无限期开着。默认值还会随时间变化——OpenSSH 10.6 出厂的默认值和 OpenSSH 7 的并不一样——所以“我什么都没改过”并不是一个中性陈述,它的意思是你的安全姿态就是恰好装上的那个版本所决定的,而要知道它是什么,只能去读这个文件。这是审计的第一项工作:让看不见的默认值现形,因为文件中没有出现的指令依然在生效。
关掉密码,比换端口管用得多
sshd_config 里最有效的一处改动是 PasswordAuthentication no 加上 PubkeyAuthentication yes:从这一刻起,任何密码——猜到的、泄露的、钓到的——都打不开会话,因为守护进程不再接受这种证明方式。密钥认证把攻击从“猜一个人想出来的秘密”变成了“偷一个从不经过网络的私钥文件”,这就是为什么包括 Mozilla 在内的每一份加固基线都从这里开始。如果本文只能带走一句话,就是这句:先生成一对密钥(见SSH 密钥套件和配套文章SSH 密钥详解)、装好公钥、确认能用密钥登录,然后再关掉密码。
相比之下,把端口从 22 换成一个冷门端口不是加固——只是隐蔽。它能减少日志里的噪音,因为多数全网扫描只敲 22 端口,但它拦不住任何一个愿意扫端口的攻击者:一次端口扫描几秒钟就能找到守护进程,而它背后的强度完全取决于配置。因此审计只把非 22 端口当作提示信息,绝不计分。关掉密码之前还有一个坑值得知道:在使用 PAM 的系统上,光设 PasswordAuthentication no 是不够的——键盘交互认证仍可能让 PAM 接受密码,所以 /etc/pam.d/sshd 里的 PAM 栈也必须拒绝密码。Mozilla 的指南明确写了这一点,而这是最常被漏掉的另一半。
Root 登录:prohibit-password 实际允许什么
PermitRootLogin 有四个取值,它们之间的差别就是有没有审计轨迹的差别。默认值 prohibit-password 允许 root 登录——只是不许用密码。被盗的 root 密钥照样长驱直入,而一旦会话成了 root,日志里就再也分不清是哪位管理员。Mozilla 的 Modern 配置把它设为 No,这才是加固的答案:root 根本不应该是一个登录账号。用具名用户登录,再用 sudo,这样每一次特权操作都能归属到具体的人。
中间值存在是有原因的,值得了解而不是害怕。forced-commands-only 只允许在 authorized_keys 里限定了单一命令的密钥以 root 登录——备份和监控脚本用的就是这个模式——是对自动化而言合理而有意的选择。而 yes 绝不合理:它允许 root 用密码登录,在任何审计里都是错误。实用的规则是:如果有人以 root 登录,配置就是错的;如果是脚本,就把密钥限定到一条命令,并在注释里写明,否则下一个读文件的人会把它当成问题“修掉”。
算法废弃是一个移动靶
你配置里的算法有保质期,而且比你想的短。OpenSSH 10.0(2025-04-09 发布)彻底移除了 DSA(ssh-dss)支持,把有限域 Diffie-Hellman 从服务器默认密钥交换里拿掉,并把后量子混合算法 mlkem768x25519-sha256 设为默认密钥协商。一份从 2021 年博客抄来的配置,可能还列着 diffie-hellman-group1-sha1、3des-cbc、arcfour 或 hmac-md5——在现代审计里这些全是错误,其中一些连装好的守护进程都不再支持。配置没有变,世界变了。
所以加固基线必须带上日期,而复查是工作的一部分,不是事后想起来的事。Mozilla 的 Modern 配置——curve25519 密钥交换、chacha20-poly1305 与 AES-GCM 加密、SHA-2 的先加密后认证(EtM)MAC——是参照标准,但它成文时还没有 OpenSSH 10.0 设为默认的后量子密钥交换,所以 2026 年的审计在它之外也接受 mlkem768x25519-sha256 与 sntrup761x25519-sha512。保持跟进的习惯很便宜:每年一两次,在服务器上跑 ssh -Q kex、ssh -Q cipher 和 ssh -Q mac,看看装好的版本实际提供什么,对照最新的 Mozilla 指南,再用审计工具对同一份文件重跑一次。2021 年的满分成绩是历史文件,不是现状。
Match 块与 Include:让“干净”审计撒谎的两种方式
配置文件不是一串平铺的设置——它是一个带条件分支的程序,而其中两个特性会让一份读起来很安全的配置表现得并不安全。第一个是 Match 块:Match User、Match Group 或 Match Address 块里的指令只在条件满足时生效,手册页明确写着,如果某个关键字出现在多个满足条件的 Match 块里,只应用第一次出现的那个。全局写了 PasswordAuthentication no、后面却有个 Match 块悄悄给某个组重新打开密码,是真实存在的配置,而逐行阅读恰恰最容易漏掉它。Match 块内的发现是有条件的,绝不是全局的,诚实的审计必须这样标注。
第二个是 Include。现代发行版会把 sshd_config 拆成多个文件——通常是 /etc/ssh/sshd_config.d/*.conf——Include 指令按字典序在它出现的位置把这些文件拉进来,而在多数发行版上它就位于文件顶部。因为先取到的值获胜,写在被包含文件里的指令会遮住主文件后面相同的指令:你读到的那一行并不是起作用的那一行。在浏览器里运行的审计工具无法跟随 Include——那些文件不在你的机器上——所以它会把 Include 标为“未跟随”并列出路径。审计时要审整个目录,而不只是一个文件;还要记住,重复的指令不是可以忽略的笔误:第一个获胜,第二个是死文本,只会迷惑下一个编辑文件的人。
安全上线:先测试,再关门
每一次 sshd_config 改动都带着同样的风险:一个拼写错误会让守护进程拒绝重启,而一个语法正确但设置错误的改动会拒绝你本人。避开两者的上线流程很短,而且没有商量余地:先用 sshd -t 检查语法再动运行中的服务——它只解析文件并报告错误,不会启动任何东西。然后重启或重载守护进程,再测试。绝不要一边改配置一边关掉自己唯一的会话。
测试本身就是纪律:保持现有会话开着,再开第二个会话,用新规则全新登录一次。第二次登录成功,改动就是安全的,可以关掉第一个会话;不成功,开着的会话就是你的退路,可以改回文件并重载。对于无法亲自到场的服务器,改动还应该一次只做一项——坏掉的密钥文件加上被禁用的密码方式放在同一次编辑里,就没有任何退路了。审计工具可以基于你的文件生成一份加固版作为起点,但那是需要逐个 Match 块审阅、用 sshd -t 测试的草稿,绝不是可以直接丢进去的文件。