1. 项目概述:为什么你的SSH配置总被安全扫描“点名”?
最近在帮几个朋友的公司做安全合规检查,发现一个高频出现的问题:无论是Nessus、OpenVAS还是商业化的漏洞扫描器,总有一堆服务器因为SSH的密钥交换算法(KexAlgorithms)配置不当而被标记为“中危”甚至“高危”漏洞。报告里常常写着“使用弱密钥交换算法,如diffie-hellman-group1-sha1”,搞得运维同学很紧张,业务方也频频追问。其实,这问题说大不大,说小也不小。说它不大,是因为在双方都使用现代SSH客户端和服务端的场景下,实际被利用的风险相对可控;说它不小,是因为在合规审计(如等保、PCI DSS)和安全评级中,这类“已知弱点”的配置会直接拉低整体评分,甚至影响业务上线。
OpenSSH作为最主流的远程管理协议,其安全性配置一直是纵深防御中容易被忽视的一环。很多人安装完系统,默认的/etc/ssh/sshd_config文件用到底,却不知道里面可能藏着一些为了兼容老旧设备而保留的、现已不被推荐的算法。密钥交换算法,顾名思义,是SSH连接建立初期,客户端和服务器用来安全协商出一个后续加密通信所用的“会话密钥”的算法。如果这个协商过程本身使用的算法存在理论上的弱点(比如基于过时的SHA1哈希,或者使用不够安全的Diffie-Hellman群组),那么整个连接的安全性基石就不够稳固。
我处理过不下百台服务器的此类问题,从CentOS 7到Ubuntu 22.04,从物理机到容器镜像。核心解决思路就一条:在sshd_config配置文件中,明确指定一套强健、现代的KexAlgorithms(密钥交换算法)列表,并禁用那些已知的弱算法。这不仅能让你轻松通过各种安全扫描,更是提升服务器整体安全水位的一个扎实步骤。接下来,我就把手把手的配置方法、背后的原理,以及我踩过的坑都分享出来。
2. 核心原理:密钥交换算法(KEX)到底是什么?为什么弱算法有风险?
在深入配置之前,我们得先搞明白我们在调整什么。SSH连接建立过程大致分为几个阶段:协议版本协商、密钥交换、用户认证和连接通道建立。其中,密钥交换(Key Exchange, 简称KEX)是第二阶段,也是最关键的安全基石阶段。
2.1 密钥交换过程简述
- 算法协商:客户端连接服务器时,双方会交换各自支持的算法列表,包括密钥交换算法、加密算法、消息认证码算法等。它们会从各自列表的第一个开始匹配,选择第一个双方都支持的算法。
- 密钥生成与交换:使用协商好的密钥交换算法,客户端和服务器在不安全的网络上,通过数学计算(通常是基于离散对数或椭圆曲线问题)共同生成一个只有双方知道的共享秘密。这个过程中交换的只是公开参数,即使被窃听,也无法推算出最终的共享秘密。
- 派生会话密钥:利用这个共享秘密,结合连接期间交换的随机数(称为“交换哈希”),通过一个密钥派生函数,生成后续用于对称加密(如AES)和完整性校验(如HMAC)的实际会话密钥。
所以,KexAlgorithms这个配置项,定义的就是服务器端愿意参与协商的密钥交换算法列表及其优先级顺序。
2.2 弱算法风险何在?
安全扫描器标记的“弱算法”,通常指以下几类:
- 基于SHA1的算法:例如
diffie-hellman-group-exchange-sha1、diffie-hellman-group14-sha1。SHA1哈希算法早在2005年就被发现存在碰撞漏洞,理论上的安全性已大打折扣。虽然在实际的SSH KEX场景中,直接攻击的难度依然很高,但出于“深度防御”原则和安全合规要求,应当禁用。 - 使用小质数群组的Diffie-Hellman算法:例如
diffie-hellman-group1-sha1(对应768位模数)。这类算法的安全性依赖于“离散对数问题”的难度,而小质数群组(模数位数低)使得暴力计算或预计算攻击成为可能。早在2015年,就有研究团队成功对768位DH群组进行了实际破解。 - 已被证明存在潜在问题的算法:如
diffie-hellman-group-exchange-sha256虽然使用SHA256,但其基于的“Group Exchange”模式在特定实现下可能存在信息泄露风险,因此一些严格的安全基线也建议优先使用固定群的算法。
注意:风险是相对的。如果你的服务器只被内部、可控的、使用现代OpenSSH客户端(>=7.3)的管理员访问,那么即使启用了弱算法,实际连接时也会优先协商到更强的算法(如
curve25519-sha256)。风险主要存在于:1)存在老旧客户端(如某些嵌入式设备、老版本Windows工具)强制使用弱算法连接;2)满足合规性要求;3)防范潜在的降级攻击(虽然现代SSH实现已很难成功)。
3. 实战配置:手把手调整OpenSSH的KexAlgorithms
理论懂了,我们直接上操作。整个过程分为诊断、配置、验证三步。
3.1 第一步:诊断当前服务器的KEX算法配置
在修改之前,必须先查看当前配置,了解现状。
查看sshd当前生效的配置:
# 查看sshd_config中关于KexAlgorithms的配置行 sudo grep -i "^KexAlgorithms" /etc/ssh/sshd_config如果没有任何输出,说明使用的是OpenSSH的默认算法列表。
查看sshd实际支持的算法列表(更准确):
# 使用ssh-keyscan或ssh命令查看服务器提供的算法 ssh -Q kex localhost或者,更直接地,模拟一个连接并查看详细的协商日志(需要调整客户端日志级别):
ssh -vvv -o KexAlgorithms=diffie-hellman-group1-sha1 localhost 2>&1 | grep -i "kex algorithm"这条命令会强制客户端使用弱算法尝试连接,在-vvv的详细输出中,你可以看到服务器是否接受该算法。
使用nmap进行外部扫描(模拟攻击者或审计视角):
# 安装nmap(如果尚未安装) # sudo yum install nmap 或 sudo apt install nmap # 扫描目标服务器的SSH算法支持情况 nmap --script ssh2-enum-algos -p 22 你的服务器IP这个nmap脚本会列出服务器支持的所有密钥交换、加密、MAC等算法,非常直观。
3.2 第二步:编辑sshd_config配置文件
现在开始修改。强烈建议在修改前备份原配置文件!
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%Y%m%d)使用你熟悉的编辑器(如vim, nano)打开配置文件:
sudo vim /etc/ssh/sshd_config找到或添加KexAlgorithms配置行。一个安全且兼容性较好的现代配置如下:
# 在文件末尾或Ciphers/MACs配置附近添加 KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256配置行详解:
curve25519-sha256,curve25519-sha256@libssh.org:这是当前首选的算法。基于椭圆曲线Curve25519,速度快,安全性高,且被认为能更好地抵抗某些类型的密码学攻击。@libssh.org是libssh库的实现标识。ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521:基于NIST标准椭圆曲线的算法,广泛支持,是良好的备选。虽然对NIST曲线存在一些讨论,但在实践中它们仍然是安全可靠的选择。diffie-hellman-group-exchange-sha256:允许客户端请求特定大小的DH群组,灵活性高。一些严格策略可能禁用它,但对于通用场景,保留它可以提高兼容性。diffie-hellman-group16-sha512, diffie-hellman-group18-sha512:使用大群组(group16: 4096位, group18: 8192位)和SHA512的DH算法,强度非常高,但计算开销也稍大。diffie-hellman-group14-sha256:使用2048位群组的DH算法,是之前多年的“安全基准”,现在依然是安全的选择,但优先级应放在更现代的曲线算法之后。
关键点:列表的顺序就是优先级顺序。服务器会按这个顺序与客户端提供的列表进行匹配,选择第一个双方都支持的。所以把最安全、最快的算法(如curve25519)放在最前面。
需要禁用的弱算法(确保它们不在列表中):
diffie-hellman-group1-sha1diffie-hellman-group14-sha1diffie-hellman-group-exchange-sha1ecdh-sha2-nistp256-cert-v01@openssh.com(证书相关变种,通常不需要)
3.3 第三步:应用配置并验证
检查配置文件语法:在重启服务前,先检查配置是否有语法错误。
sudo sshd -t如果没有任何输出,表示语法正确。如果报错,请根据错误信息修正配置行。
重启sshd服务:
# Systemd系统(CentOS 7+, Ubuntu 16.04+, Debian 8+) sudo systemctl restart sshd # SysVinit系统(旧版) sudo service ssh restart验证新配置是否生效:
- 方法A:从另一台机器使用nmap再次扫描(最客观)。
查看输出的nmap --script ssh2-enum-algos -p 22 你的服务器IPkex_algorithms部分,应该只包含你配置的那些强算法,不再有-sha1或group1等弱算法。 - 方法B:使用特定弱算法尝试连接(应该失败)。
预期结果应该是连接超时或立即失败,并提示ssh -o KexAlgorithms=diffie-hellman-group1-sha1 用户名@你的服务器IPno matching key exchange method found。 - 方法C:使用正常客户端连接并查看日志。
在详细输出中,你应该能看到类似ssh -vvv 用户名@你的服务器IP 2>&1 | grep -i "kex algorithm"kex algorithm: curve25519-sha256的日志,表明成功协商到了你列表中的首选算法。
- 方法A:从另一台机器使用nmap再次扫描(最客观)。
4. 兼容性考量与降级处理:当老旧设备还需要连接时怎么办?
在实际生产环境中,一刀切地禁用所有旧算法可能会“误伤”一些老旧但重要的设备或软件。我遇到过工厂里的工控机(跑着很老的Linux)、某些网络设备(交换机、路由器)的管理接口,或者一些遗留的自动化脚本,它们内置的SSH客户端可能只支持老旧的算法。
处理原则:安全与兼容的平衡
隔离网络,区别对待:这是最推荐的方式。将必须使用老旧协议/算法的设备划分到独立的管理VLAN或网段,在该网段对应的SSH服务监听端口(可以是非22端口)上,配置一套兼容性策略。而面向互联网或办公网的SSH服务(22端口)则使用最严格的策略。
# 在sshd_config中,使用Match块针对不同地址或用户进行配置 # 严格策略(默认) KexAlgorithms curve25519-sha256,ecdh-sha2-nistp256,diffie-hellman-group16-sha512 # 为来自特定管理网段的连接启用兼容模式 Match Address 192.168.100.0/24 KexAlgorithms +diffie-hellman-group14-sha1,diffie-hellman-group1-sha1注意:
+号表示在原有列表基础上追加,而不是覆盖。更安全的做法是为兼容性监听另一个端口,并在该端口的配置中单独设置算法列表。升级客户端:如果可能,推动老旧设备或软件的升级。例如,为老版本Windows安装新版的OpenSSH for Windows或使用Putty的最新版本。
使用跳板机(Bastion Host):不允许老旧设备直接连接核心服务器。让它们先连接到一台专门配置了兼容性算法的“跳板机”,再从跳板机用强算法连接到目标服务器。
实操心得:在金融行业的一次合规改造中,我们遇到一批无法升级的ATM机管理终端。最终方案是,在核心服务器上创建了一个非标端口(如2222),在该端口的sshd配置中,通过
Match Address针对这些终端的管理IP,单独放行了diffie-hellman-group14-sha1。同时,在防火墙上严格限制了只有这些特定IP能访问2222端口。这样既满足了扫描器对22端口“零弱算法”的要求,又保证了业务的连续性。关键是要有清晰的记录和审批流程,明确哪些设备、为什么需要例外。
5. 进阶加固:结合Ciphers和MACs的全局安全配置
只调整KexAlgorithms是远远不够的。一个完整的SSH加固配置,通常需要联动修改加密算法(Ciphers)和消息认证码算法(MACs),形成一套组合拳。
一个完整的、偏严格的安全配置示例(适用于OpenSSH 7.3及以上版本):
# /etc/ssh/sshd_config # 密钥交换算法(本文核心) KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,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-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com # 其他重要安全选项 Protocol 2 # 禁用老旧的SSHv1 PermitRootLogin prohibit-password # 禁止root密码登录,建议改为no或prohibit-password PasswordAuthentication no # 禁用密码认证,强制使用密钥 PubkeyAuthentication yes PermitEmptyPasswords no ChallengeResponseAuthentication no UsePAM yes X11Forwarding no AllowTcpForwarding no # 按需开启 ClientAliveInterval 300 ClientAliveCountMax 2配置解析与取舍:
- Ciphers:优先选择带AEAD(认证加密)模式的算法,如
chacha20-poly1305和aes-gcm,它们将加密和完整性校验合二为一,更高效安全。aes-ctr是传统的加密模式,作为兼容备选。 - MACs:优先选择
-etm(Encrypt-then-MAC)模式的算法,这种模式能更好地防止某些定时攻击。hmac-sha2系列是目前的主流。 - 取舍:上述配置可能过于严格,会拒绝一些老旧的客户端(如老版本macOS的Terminal、某些IoT设备)。你需要根据你的客户端生态进行调整。一个更兼容但仍安全的Ciphers列表可以是:
aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr,chacha20-poly1305@openssh.com。
如何测试你的配置对客户端的影响?可以使用在线工具(如ssh-audit)或本地脚本,模拟不同版本的SSH客户端来测试你的服务器配置。但最直接的方法,是收集你们公司所有类型的运维终端(Windows上的Putty/Xshell/MobaXterm、macOS Terminal、Linux各发行版、各种编程语言/工具的SSH库版本),用它们实际连接测试一次。
6. 自动化与持续监控:让安全配置一劳永逸
手动配置几十上百台服务器不现实,也容易出错。我们需要自动化。
6.1 使用配置管理工具(Ansible示例)
下面是一个Ansible Playbook片段,用于批量配置SSH的KEX算法:
--- - name: Harden SSH Key Exchange Algorithms hosts: all_servers become: yes tasks: - name: Backup original sshd_config ansible.builtin.copy: remote_src: yes src: /etc/ssh/sshd_config dest: /etc/ssh/sshd_config.bak_{{ ansible_date_time.date }} - name: Set strong KexAlgorithms in sshd_config ansible.builtin.lineinfile: path: /etc/ssh/sshd_config regexp: '^#?KexAlgorithms' line: 'KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512' state: present backup: yes - name: Validate sshd_config syntax ansible.builtin.command: sshd -t changed_when: false failed_when: false register: sshd_check - name: Fail if sshd_config syntax is invalid ansible.builtin.fail: msg: "sshd_config syntax check failed. Please check the configured KexAlgorithms line." when: sshd_check.rc != 0 - name: Restart sshd service ansible.builtin.service: name: sshd state: restarted when: sshd_check.rc == 0这个Playbook会先备份,然后确保KexAlgorithms行被设置为强算法列表,进行语法检查,最后在语法正确的情况下重启服务。
6.2 集成到镜像或容器构建过程
对于使用Docker或虚拟机模板的场景,应该在基础镜像或模板制作阶段就完成安全配置。
Dockerfile示例:
FROM ubuntu:22.04 RUN apt-get update && apt-get install -y openssh-server # 创建目录并生成主机密钥 RUN mkdir /var/run/sshd RUN ssh-keygen -A # 复制预先准备好的、已加固的sshd_config文件 COPY hardened_sshd_config /etc/ssh/sshd_config EXPOSE 22 CMD ["/usr/sbin/sshd", "-D"]关键:这个hardened_sshd_config文件就是你本地已经测试好的、包含强KexAlgorithms等配置的完整文件。
6.3 持续监控与合规检查
配置不是一劳永逸的。OpenSSH版本会更新,新的漏洞和算法建议也会出现。你需要建立监控机制。
- 定期扫描:使用Nessus、OpenVAS或商业扫描器,定期(如每月)对服务器进行SSH专项漏洞扫描。
- 使用ssh-audit进行专项检查:
ssh-audit是一个优秀的命令行工具,能给出详细的配置评分和建议。
它会输出一个报告,明确告诉你哪些算法弱、哪些好,并给出修改建议。# 安装 pip install ssh-audit # 审计你的服务器 ssh-audit 你的服务器IP - 集中日志分析:将SSH的日志(
/var/log/auth.log或/var/log/secure)集中到SIEM(如Elastic Stack)中。可以设置告警规则,监控是否有连接尝试使用已被你禁用的弱算法(日志中会有no matching key exchange method等记录),这可能是攻击者探测或老旧客户端异常的信号。
7. 常见问题与故障排查实录
在实际操作中,你肯定会遇到各种问题。这里把我遇到过的典型问题和解决方法列出来。
7.1 问题:重启sshd服务失败,报错“Invalid configuration value”
可能原因:KexAlgorithms(或Ciphers,MACs)的配置行有语法错误。常见错误包括:
- 算法名称拼写错误(如
curve25519-sha256写成curve25519-sha256)。 - 使用了当前OpenSSH版本不支持的算法(比如在很老的版本上配置了
chacha20-poly1305@openssh.com)。 - 列表中存在重复的算法。
- 逗号后面有空格(在某些版本中可能导致解析问题)。
排查步骤:
- 运行
sudo sshd -t,它会精确指出哪一行、哪个附近有错误。 - 对照官方文档或
ssh -Q kex的输出,检查算法名。 - 简化列表进行测试。先只配置一个确认可用的算法(如
curve25519-sha256),重启服务看是否成功,再逐步添加。
7.2 问题:配置生效后,特定客户端(如老版本Java应用)无法连接
现象:客户端连接时报错Algorithm negotiation failed或no matching key exchange method。
原因:客户端支持的算法列表与你服务器配置的列表没有交集。
解决方案:
- 确定客户端支持的算法:如果客户端是你可控的,尝试在其机器上运行
ssh -Q kex(如果是OpenSSH)或查阅其文档。对于Java应用,使用的可能是JSch或Apache MINA SSHD库,需要查对应库版本的文档。 - 在服务器端添加兼容算法:在服务器的
KexAlgorithms列表末尾,追加客户端支持的、相对最强的那个算法。例如,如果客户端只支持diffie-hellman-group14-sha256,那么就在列表最后加上它。务必加在最后,以确保其他现代客户端优先使用更安全的算法。 - 升级客户端库:这是根本解决办法。联系开发团队,升级应用依赖的SSH库版本。
7.3 问题:安全扫描器仍然报告存在弱算法漏洞
现象:你已经确认sshd_config配置正确,且用ssh -Q kex和nmap扫描都显示弱算法已禁用,但扫描器(如Nessus)的报告依然显示存在diffie-hellman-group1-sha1漏洞。
可能原因及排查:
- 扫描器缓存:扫描器可能有缓存,尝试清除扫描任务的缓存或重新运行扫描。
- 多个SSH服务实例:服务器上可能运行着多个
sshd进程或监听在不同端口的sshd服务,而你只修改了其中一个配置文件。用netstat -tlnp | grep :22或ss -tlnp | grep sshd检查监听22端口的进程及其启动命令,确认它使用的是你修改的/etc/ssh/sshd_config。 - 配置未生效:确保修改配置后,重启的是正确的
sshd服务。对于Systemd,使用sudo systemctl restart sshd;对于通过inetd/xinetd或容器内启动的,重启方式可能不同。 - 扫描器误报或规则过时:有些扫描器插件规则可能比较老旧或过于敏感。你可以手动验证:用
nmap --script ssh2-enum-algos扫描,如果结果中没有弱算法,那么你的配置是正确的。可以将此结果作为证据,向审计或安全团队申请对扫描结果进行“误报”确认或规则调整。
7.4 问题:配置后SSH连接速度变慢
现象:启用新的KEX算法(特别是diffie-hellman-group16/18-sha512)后,感觉连接建立阶段变慢了。
原因:更大的Diffie-Hellman群组(4096位、8192位)需要更多的计算资源来进行密钥交换。
解决方案:
- 调整算法优先级:将计算量大的算法(如
diffie-hellman-group18-sha512)在列表中的位置往后放。将curve25519-sha256和ecdh-sha2-nistp256这类基于椭圆曲线、速度快且安全的算法放在最前面。 - 评估是否必要:对于绝大多数场景,
curve25519-sha256和ecdh-sha2-nistp256提供的安全性已经足够。可以考虑将diffie-hellman-group16/18-sha512从默认列表中移除,或者仅在与特定高安全要求的客户端连接时通过Match块启用。 - 硬件性能:如果服务器CPU资源非常紧张,可以考虑升级硬件。但在云时代,这通常不是问题。
一个折中的、兼顾安全与性能的算法列表参考:
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha256这个列表移除了计算最重的group16/18-sha512,保留了足够安全的选项,兼容性也比较好。安全扫描通常也能通过。