1. 项目概述:从WAF告警到主机修复的完整闭环
最近在给一个线上业务系统做安全加固,安全扫描报告里赫然躺着两条让人头疼的告警:“目标主机支持RSA密钥交换”和“SSL证书使用了弱hash算法”。这两条告警,但凡做过Web应用安全或者运维的朋友,估计都不陌生。它们通常来自部署在应用前端的WAF(Web应用防火墙)或者安全扫描器的检测结果。WAF在这里扮演了“哨兵”的角色,它通过分析流入的流量,识别出后端服务器在TLS/SSL握手过程中暴露出的不安全配置。简单来说,就是你的服务器在和客户端(比如浏览器)建立加密连接时,使用了一些已经被认为不够安全甚至存在漏洞的加密套件和算法。
这可不是小事。支持不安全的RSA密钥交换,意味着攻击者可能利用像“FREAK”、“Logjam”这样的降级攻击,迫使你的服务器使用较弱的、容易被破解的加密强度进行通信。而SSL证书使用弱hash算法(比如SHA-1),则意味着证书本身的完整性和真实性可以被伪造,攻击者可以制作一个看起来和你网站一模一样的假证书,配合中间人攻击,用户的敏感数据就危险了。对于任何一个对安全有要求的企业,尤其是涉及用户登录、支付等场景的系统,这都是必须立即处理的高危风险。
这篇文章,我就以一个实际处理案例为蓝本,带你走一遍从理解漏洞原理、定位问题根源,到在真实服务器上实施修复的完整流程。无论你是运维工程师、安全工程师,还是负责线上业务的开发,这套思路和实操方法都能直接拿来用。我们不会停留在理论,而是深入到Nginx、Tomcat等常见服务器的配置文件中,告诉你改哪里、为什么这么改,以及改了之后如何验证。过程中踩过的坑、总结的技巧,我也会一并分享出来。
2. 漏洞原理深度拆解:为什么这些配置是“漏洞”
在动手修复之前,我们必须搞清楚WAF到底在报警什么。知其然更要知其所以然,这样才能在复杂的生产环境中做出正确的判断,而不是盲目地“一刀切”。
2.1 目标主机支持RSA密钥交换:被时代淘汰的密钥协商机制
“RSA密钥交换”这个说法在TLS 1.2及更早的协议中非常常见。它的核心流程是:客户端生成一个随机数(预主密钥),然后用服务器SSL证书中的RSA公钥加密它,发送给服务器。服务器用自己的RSA私钥解密,双方就得到了相同的预主密钥,进而派生出最终的会话密钥。
听起来很完美,但问题出在它的“静态性”上。服务器的RSA密钥对是长期固定的。这就导致了两个致命缺陷:
- 前向安全性缺失:如果攻击者截获并保存了今天的全部加密通信流量,未来某一天他成功窃取或破解了服务器的RSA私钥,那么他可以用这把私钥解密过去所有保存下来的流量,拿到当时的会话密钥,从而解密全部历史通信内容。这在密码学上是不可接受的。
- 易受降级攻击:一些老旧的实现(如出口版本的RSA算法)使用较短的密钥长度(如512位)。攻击者可以利用“FREAK”、“Logjam”等漏洞,在握手阶段“欺骗”服务器和客户端,让它们使用这种弱强度的RSA密钥交换,从而大大降低破解难度。
现代TLS的最佳实践是使用基于迪菲-赫尔曼(Diffie-Hellman, DH)或椭圆曲线迪菲-赫尔曼(ECDH)的密钥交换。这类算法的特点是每次会话都会临时生成一对新的密钥,即使本次会话的临时私钥泄露,也不会影响其他会话的安全性,完美实现了“前向保密”。
所以,WAF报警“支持RSA密钥交换”,本质上是在警告:你的服务器配置的加密套件列表中,包含了那些使用RSA进行密钥交换的陈旧套件(例如TLS_RSA_WITH_*开头的套件)。我们需要在服务器配置中禁用它们。
2.2 SSL证书使用弱hash算法:信任链的根基不牢
SSL证书的核心作用之一是“身份认证”,证明“你访问的baidu.com就是真正的百度”。证书的防伪依赖于数字签名。证书颁发机构(CA)用它的私钥,对证书持有者的公钥、域名等信息进行签名,生成一个hash值(即摘要)。这个签名算法就是hash算法。
SHA-1是曾经广泛使用的hash算法,但早在2005年,密码学家就发现了其理论上的碰撞漏洞(即可以制造两个不同的输入,产生相同的hash值)。随着计算能力的提升,实际制造碰撞的成本越来越低。如果一个证书使用SHA-1签名,攻击者理论上可以伪造另一个内容不同但签名相同的证书,从而冒充你的网站。
因此,行业早已全面弃用SHA-1。主流浏览器多年前就已停止信任SHA-1签名的证书。现在的最低要求是SHA-256。WAF检测到你的证书签名算法是SHA-1(或更弱的MD5),就会触发“弱hash算法”告警。
这里需要区分两个概念:
- 证书的签名算法:CA用哪个算法给这张证书签名。这是WAF主要检查的。
- 证书的公钥算法:证书里包含的公钥是RSA还是ECC。这通常不影响这个告警。
修复方法很明确:更换由受信任的CA颁发的、使用SHA-256或更强算法签名的SSL证书。对于自签名证书,在生成时就必须指定使用SHA-256。
注意:有些老旧的内网系统或设备可能内置了SHA-1签名的证书,且不易更换。这种情况下,需要评估该系统的暴露面和风险,如果必须对外服务,则应考虑在网络层面(如负载均衡器)进行SSL终结和证书替换,而不是直接修改老旧系统本身。
3. 修复前的侦察与诊断:精准定位问题
拿到告警,别急着改配置。首先得确认问题到底出在哪里,影响范围有多大。盲目操作可能导致服务不可用。
3.1 使用专业工具进行扫描验证
WAF的告警需要我们自己用工具复现一遍,一方面确认问题,另一方面获取更详细的信息。
- SSL Labs在线测试:访问
https://www.ssllabs.com/ssltest/,输入你的域名。这是最全面、最权威的免费SSL/TLS配置评估工具。它会给出详细的评分,并明确指出服务器支持的加密套件列表、证书详情、协议版本等信息。在结果中,你可以直接看到是否有TLS_RSA_*套件,以及证书的签名算法是否为SHA-1。 - 命令行工具扫描:
nmap:使用nmap --script ssl-enum-ciphers -p 443 your-domain.com可以枚举服务器支持的加密套件,并标注出哪些是弱的(WEAK)。openssl s_client:这是一个更底层的工具。例如,openssl s_client -connect your-domain.com:443 -cipher 'RSA'可以测试服务器是否接受仅使用RSA密钥交换的套件。连接成功后,使用openssl x509 -in <(openssl s_client -connect your-domain.com:443 2>/dev/null | sed -n '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p') -noout -text | grep 'Signature Algorithm'可以快速提取证书的签名算法。
3.2 分析服务器配置现状
工具扫描是从外部视角看,我们还需要从内部视角检查服务器软件的具体配置。不同的Web服务器,配置文件的位置和语法不同。
- Nginx:主要配置文件通常是
/etc/nginx/nginx.conf,而SSL和加密套件的配置通常在server块中,或者被包含在/etc/nginx/conf.d/或/etc/nginx/sites-enabled/下的独立配置文件里。你需要找到ssl_ciphers这个指令。 - Apache:配置可能在
/etc/httpd/conf.d/ssl.conf或虚拟主机配置文件中。关键指令是SSLCipherSuite。 - Tomcat (Java):对于使用APR/Native连接器或BIO/NIO连接器并配置了SSL的Tomcat,配置在
server.xml的<Connector>标签内,属性是ciphers。对于使用Spring Boot内嵌容器的Java应用,配置则在application.properties或application.yml中。
你需要记录下当前ssl_ciphers或ciphers的值。一个典型的、包含不安全套件的旧配置可能长这样:
ssl_ciphers HIGH:!aNULL:!MD5;这个配置虽然禁用了匿名(aNULL)和MD5算法,但仍然允许使用RSA密钥交换的强加密套件(HIGH组中包含它们)。
同时,检查证书路径和文件。在Nginx中,是ssl_certificate和ssl_certificate_key指令指向的文件。用openssl x509 -in /path/to/your/cert.pem -noout -text命令查看证书详情,重点关注Signature Algorithm一行。
4. 核心修复方案与实操步骤
诊断清楚后,就可以开始修复了。我们的目标是两个:第一,从加密套件列表中剔除不安全的RSA密钥交换套件;第二,确保使用SHA-256或以上强度签名的证书。
4.1 禁用不安全的RSA密钥交换套件
这里提供一个经过线上验证的、安全性与兼容性平衡的配置方案。我们以Nginx和Tomcat为例。
Nginx 配置修改:
编辑你的Nginx SSL配置文件,找到ssl_ciphers指令,将其替换为以下内容:
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!aNULL:!MD5:!ADH:!RC4:!DH:!DHE:!RSA:!3DES; ssl_prefer_server_ciphers on;配置解读与技巧:
ECDHE-RSA-AES128-GCM-SHA256:这是一个兼具前向保密(ECDHE)、强加密(AES128-GCM)和认证(RSA)的现代、安全的套件,放在最前面表示优先使用。ECDHE:ECDH:AES:HIGH:这些是套件组。ECDHE和ECDH表示支持基于椭圆曲线的迪菲-赫尔曼密钥交换(前者是临时性的,前向保密性更好)。AES和HIGH表示使用AES加密算法和高强度加密。!aNULL:!MD5:!ADH:!RC4:明确禁用匿名套件、MD5算法、ADH(匿名DH)和已被攻破的RC4流加密算法。!DH:!DHE:关键在这里。我们禁用了传统的、非椭圆曲线的迪菲-赫尔曼(DHE)套件。虽然DHE也提供前向保密,但其性能开销远大于ECDHE,且如果参数设置不当(如素数过小),同样不安全。在现代环境中,优先使用ECDHE是更好的选择。!RSA:核心修复点。这个感叹号表示禁用所有使用RSA进行密钥交换的套件(即TLS_RSA_WITH_*)。这是解决WAF告警的关键一步。!3DES:禁用3DES算法,它虽然强度尚可,但速度慢,已不被推荐。ssl_prefer_server_ciphers on;:让服务器端的套件优先级顺序生效,确保客户端连接时优先协商我们配置的安全套件。
Tomcat (Spring Boot) 配置修改:
对于使用Spring Boot内嵌Tomcat的应用,在application.yml中配置:
server: ssl: ciphers: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 enabled-protocols: TLSv1.2这里我们明确列出了几个安全的、支持前向保密的套件,并禁用了TLS 1.0和1.1,只启用TLS 1.2(根据业务情况,可考虑加入TLS 1.3)。
实操心得:修改加密套件列表后,务必测试对老旧客户端的兼容性。你可以用旧版本的浏览器(如IE 8/9/10)或特定版本的Java客户端进行测试。如果业务必须支持这些老旧客户端,你可能需要保留个别较安全的RSA套件(如
TLS_RSA_WITH_AES_128_CBC_SHA256),但这会牺牲前向保密性,需要和安全团队充分评估风险。我们的原则是:在满足业务兼容性的前提下,尽可能提高安全性。
4.2 更换弱hash算法SSL证书
如果检测发现证书签名算法是SHA-1,唯一的根治方法就是换证。
- 申请新证书:向你的证书提供商(如Let‘s Encrypt、DigiCert、Sectigo等)申请一张新的证书。在申请过程中,确保选择SHA-256作为签名算法(现在这基本是默认且唯一的选择)。对于Let‘s Encrypt,使用Certbot等工具自动续签的证书默认就是SHA-256。
- 替换证书文件:将新获得的证书文件(通常是
.crt或.pem文件)和私钥文件(.key)上传到服务器。 - 更新服务器配置:修改Nginx或Apache的配置文件,将
ssl_certificate和ssl_certificate_key指令指向新的文件路径。 - 平滑重启服务:对于Nginx,使用
nginx -s reload命令可以重新加载配置而不中断现有连接。对于Apache,可能是systemctl reload httpd或apachectl graceful。
自签名证书的重新生成:对于内部测试或开发环境使用的自签名证书,需要用openssl命令重新生成:
# 生成一个新的RSA私钥(2048位或4096位) openssl genrsa -out server.key 2048 # 使用SHA-256算法生成证书签名请求(CSR) openssl req -new -key server.key -out server.csr -sha256 # 使用SHA-256算法自签名证书(有效期365天) openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt -sha256关键就在于-sha256参数,它确保了签名使用的hash算法是SHA-256。
5. 修复后的验证与回归测试
修改配置和证书后,绝对不能假设问题已经解决。必须进行严格的验证。
- 配置语法检查:对于Nginx,运行
nginx -t;对于Apache,运行apachectl configtest。确保配置文件语法正确,否则服务可能无法启动。 - 服务重启与状态确认:重启Web服务,并检查服务状态是否正常 (
systemctl status nginx)。查看错误日志 (tail -f /var/log/nginx/error.log) 是否有相关报错。 - 工具复扫:再次使用SSL Labs和nmap进行扫描。目标很明确:
- SSL Labs评分应达到A或A+。
- 在“Cipher Suites”部分,不应该再看到任何
TLS_RSA_WITH_*的套件。 - 在“Certification Paths”部分,证书的签名算法应显示为“SHA256withRSAEncryption”或类似字样。
- 业务功能回归测试:这是最重要的一步。你需要用各种方式访问你的网站或API:
- 主流浏览器(Chrome, Firefox, Safari, Edge)访问网页,功能是否正常。
- 移动端APP(如果涉及)访问后端API,是否正常。
- 其他内部系统或第三方调用,是否正常。
- 特别关注那些使用特定编程语言老版本库的客户端(如某些旧的Java、Python应用),它们可能对加密套件有特定要求。
6. 常见问题排查与进阶技巧
在实际操作中,你可能会遇到一些意料之外的情况。这里记录几个我踩过的坑和解决方法。
问题1:修改了Nginx配置并reload后,SSL Labs扫描结果依旧显示支持RSA套件。
- 排查思路:首先确认你的网站是否通过了CDN或负载均衡器(如阿里云SLB、AWS ALB)。如果走了CDN,那么SSL Labs扫描到的是CDN边缘节点的配置,而不是你源站的配置。
- 解决方法:你需要登录CDN或负载均衡器的管理控制台,找到SSL/TLS策略或监听器配置,在那里修改加密套件。通常云服务商都提供了“安全策略”模板,选择类似“TLSv1.2_2021”或“安全高兼容”这类策略,它们通常已经禁用了不安全的套件。
问题2:业务系统依赖的一个老旧客户端(如某硬件设备)在修改套件后无法连接了。
- 排查思路:首先用
openssl s_client -connect your-server:port配合-cipher参数测试,看服务器是否还支持客户端所需的特定套件。查看客户端的错误日志,通常会包含类似“handshake failure”或“no shared cipher”的信息。 - 解决方法:这是一个安全和兼容性的权衡。如果该客户端无法升级,且业务必须支持,你需要在服务器配置的加密套件列表中,为这个特定的IP或域名“开一个小口子”。在Nginx中,可以使用
ssl_ciphers指令配合$ssl_client_hello_ciphers变量(需要较新版本)或通过不同的server块来为特定入口提供不同的套件列表。务必记录在案,并评估由此引入的安全风险。
问题3:证书链不完整,导致某些客户端(如Android旧版本)报告证书错误。
- 排查思路:使用SSL Labs测试,在证书详情部分查看是否提示“Chain issues: Incomplete”。用命令
openssl s_client -connect your-domain:443 -showcerts可以看到服务器发送的所有证书。通常你需要发送服务器证书+中间CA证书。 - 解决方法:将你的证书文件(
server.crt)和中间CA证书文件(intermediate.crt)合并成一个文件,然后让Nginx的ssl_certificate指向这个合并后的文件。合并顺序是:你的证书在前,中间CA证书在后。
然后在Nginx配置中:cat server.crt intermediate.crt > chained.crtssl_certificate /path/to/chained.crt;
问题4:如何持续监控,防止配置被意外改回?
- 进阶技巧:将安全配置(如ssl_ciphers)写入基础镜像或配置管理模板(如Ansible Playbook, Chef Cookbook)。利用自动化巡检工具,定期(如每周)用脚本调用openssl或nmap检查线上服务的加密套件和证书信息,与安全基线进行比对,发现异常自动告警。可以将SSL Labs的测试API集成到你的CI/CD流水线中,在每次部署前对测试环境进行扫描,不通过则阻断部署。
修复WAF告警的这两个漏洞,是一个典型的“安全左移”实践。它不仅仅是解决一次扫描告警,更是将安全标准固化到基础设施配置中的过程。通过这次修复,我们不仅提升了系统的实际安全水位,也梳理了与加密、证书相关的运维知识。记住,安全配置不是一劳永逸的,随着密码学研究的深入和计算能力的提升,今天安全的配置明天可能就有风险。保持对行业最佳实践的关注,定期审查和更新你的安全配置,是每一个技术从业者的必修课。