news 2026/8/24 14:41:13

云平台服务器遭遇黑客攻击?用 Nginx 批量封锁敏感接口,自动返回 444 关闭连接

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
云平台服务器遭遇黑客攻击?用 Nginx 批量封锁敏感接口,自动返回 444 关闭连接

前言

最近在处理云平台服务器安全问题时,发现大量来自外部的扫描请求,目标直指/actuator/swagger-ui/druid/health/metrics等敏感路径。这些路径一旦暴露,黑客可能获取系统内部信息、配置详情甚至数据库监控页面,为进一步渗透提供便利。
本文将介绍一种通用的 Nginx 加固方案:批量在所有server块中插入安全规则,让外部访问这些敏感路径时直接返回444(Nginx 特有的“关闭连接”响应码),从源头阻断扫描,降低被攻击风险。

方案适用于所有使用标准 Nginx 的 Linux 云服务器,不依赖特定云厂商,只需本地修改 Nginx 配置,风险可控。


为什么要这样做?

黑客在对云服务器发起攻击前,通常会进行自动化扫描,探测常见的管理端点、API 文档、监控页面等。例如:

  • /actuator:Spring Boot 应用监控端点,可能泄露 beans、env、health、metrics 等信息。
  • /swagger-ui/v2/api-docs:接口文档,暴露 API 结构和参数。
  • /druid:阿里巴巴数据库连接池监控页面,若未授权可直接查看 SQL 执行情况。
  • /health/metrics:应用健康检查和指标信息,可能泄露内部状态。

这些路径如果直接返回 404 或 403,虽然也能拦截,但攻击者仍可判断服务器存在,并继续尝试其他路径。而444是 Nginx 自定义的非标准响应码,表示直接关闭连接,不返回任何 HTTP 响应,可以让扫描器认为目标不可达或异常,从而增加攻击难度,隐藏真实服务信息。


这样做的作用

  1. 批量防护:自动扫描/etc/nginx/conf.d/下所有.conf文件,为每个server块插入统一的敏感路径封锁规则,避免遗漏。
  2. 精确匹配:规则使用正则匹配,覆盖/actuator/api/actuator/swagger-ui及其子路径,防止绕过。
  3. 安全可控:脚本执行前自动备份配置,并在修改后运行nginx -t检查语法;若语法错误自动回滚,不影响线上服务。
  4. 无业务侵入:只拦截指定的敏感路径,正常业务接口不受影响。同时脚本会跳过upstream块内的server指令,不会误伤后端服务定义。

适用场景与前提

  • 服务器使用标准 Nginx 作为反向代理或 Web 服务器。
  • 配置文件位于/etc/nginx/conf.d/目录下(可包含子目录)。
  • 确认没有内部系统依赖这些敏感路径(例如监控探针、健康检查)。
  • 云负载均衡器的健康检查使用 TCP 协议,不受 HTTP 444 影响。

完整操作步骤

第 1 步:备份现有 Nginx 配置

cp-r/etc/nginx/conf.d /etc/nginx/conf.d.bak.$(date+%Y%m%d_%H%M%S)

执行后会生成类似/etc/nginx/conf.d.bak.20260821_173000的备份目录。

验证备份:

ls-ld/etc/nginx/conf.d.bak.*

第 2 步:创建敏感接口封锁规则文件

mkdir-p/etc/nginx/snippetsvim/etc/nginx/snippets/block_sensitive_paths.conf

i进入插入模式,粘贴以下内容:

# 敏感接口统一封锁规则(修正正则,匹配子路径) location ~* ^/actuator(/.*)?$ { access_log off; return 444; } location ~* ^/api/actuator(/.*)?$ { access_log off; return 444; } location ~* ^/(swagger-resources|v2/api-docs|v3/api-docs|swagger-ui|webjars/springfox)(/.*)?$ { access_log off; return 444; } location ~* ^/api/(swagger-resources|v2/api-docs|v3/api-docs|swagger-ui|webjars/springfox)(/.*)?$ { access_log off; return 444; } location ~* ^/(swagger-ui\.html|doc\.html)$ { access_log off; return 444; } location ~* ^/api/(swagger-ui\.html|doc\.html)$ { access_log off; return 444; } location ~* ^/(druid|h2-console|jolokia)(/.*)?$ { access_log off; return 444; } location ~* ^/api/(druid|h2-console|jolokia)(/.*)?$ { access_log off; return 444; } location ~* ^/(health|env|beans|configprops|mappings|metrics|heapdump|threaddump|logfile|loggers|shutdown|trace|autoconfig|dump)(/.*)?$ { access_log off; return 444; } location ~* ^/api/(health|env|beans|configprops|mappings|metrics|heapdump|threaddump|logfile|loggers|shutdown|trace|autoconfig|dump)(/.*)?$ { access_log off; return 444; }

Esc,输入:wq保存退出。


第 3 步:创建批量插入脚本

vim/root/apply_block_rules.py

i进入插入模式,粘贴以下完整 Python 脚本:

#!/usr/bin/env python3importosimportreimportsubprocessimportshutilimportsysfromdatetimeimportdatetime CONF_ROOT="/etc/nginx/conf.d"SNIPPET_DIR="/etc/nginx/snippets"SNIPPET_FILE=os.path.join(SNIPPET_DIR,"block_sensitive_paths.conf")BACKUP_DIR=f"/etc/nginx/conf.d.bak.{datetime.now().strftime('%Y%m%d_%H%M%S')}"INCLUDE_LINE=f" include{SNIPPET_FILE};\n"defbackup_configs():print(f"[1/5] 备份配置到{BACKUP_DIR}")shutil.copytree(CONF_ROOT,BACKUP_DIR)print("备份完成。")defcreate_snippet():print("[2/5] 创建规则文件...")os.makedirs(SNIPPET_DIR,exist_ok=True)content="""# 敏感接口统一封锁规则(修正正则,匹配子路径) location ~* ^/actuator(/.*)?$ { access_log off; return 444; } location ~* ^/api/actuator(/.*)?$ { access_log off; return 444; } location ~* ^/(swagger-resources|v2/api-docs|v3/api-docs|swagger-ui|webjars/springfox)(/.*)?$ { access_log off; return 444; } location ~* ^/api/(swagger-resources|v2/api-docs|v3/api-docs|swagger-ui|webjars/springfox)(/.*)?$ { access_log off; return 444; } location ~* ^/(swagger-ui\\.html|doc\\.html)$ { access_log off; return 444; } location ~* ^/api/(swagger-ui\\.html|doc\\.html)$ { access_log off; return 444; } location ~* ^/(druid|h2-console|jolokia)(/.*)?$ { access_log off; return 444; } location ~* ^/api/(druid|h2-console|jolokia)(/.*)?$ { access_log off; return 444; } location ~* ^/(health|env|beans|configprops|mappings|metrics|heapdump|threaddump|logfile|loggers|shutdown|trace|autoconfig|dump)(/.*)?$ { access_log off; return 444; } location ~* ^/api/(health|env|beans|configprops|mappings|metrics|heapdump|threaddump|logfile|loggers|shutdown|trace|autoconfig|dump)(/.*)?$ { access_log off; return 444; } """withopen(SNIPPET_FILE,'w')asf:f.write(content)print(f"规则文件已创建:{SNIPPET_FILE}")defget_conf_files():files=[]forroot,dirs,namesinos.walk(CONF_ROOT):fornameinnames:ifnotname.endswith(".conf"):continuepath=os.path.join(root,name)if".bak"inpathor"/template/"inpath:continuefiles.append(path)returnfilesdefis_server_block_start(lines,i):"""判断第 i 行是否是一个真正的 server 块起始(排除 upstream 块内 server 指令)"""line=lines[i]stripped=line.strip()ifstripped.startswith('#'):returnFalse# 形式1:server { (同一行)ifre.match(r'^\s*server\s*\{',line):returnTrue# 形式2:纯 server 行,后换行 {ifre.match(r'^\s*server\s*$',line):# 向后找到第一个非注释行,检查是否包含 {k=i+1whilek<len(lines):s=lines[k].strip()ifs.startswith('#'):k+=1continueif'{'inlines[k]:returnTrueelse:returnFalsereturnFalsereturnFalsedefinsert_include_in_file(file_path):withopen(file_path,'r',encoding='utf-8',errors='ignore')asf:lines=f.readlines()full="".join(lines)ifSNIPPET_FILEinfull:returnFalse,0new_lines=[]i=0modified=Falseinsert_count=0whilei<len(lines):line=lines[i]ifis_server_block_start(lines,i):# 找到 server 块的 { 所在行,插入 include# 如果是 server { 同在一行,则直接在该行后插入# 如果是纯 server 行,{ 在后续行,则在找到 { 的那一行后插入j=i found_brace=Falsewhilej<len(lines):s=lines[j].strip()ifs.startswith('#'):j+=1continueif'{'inlines[j]:found_brace=Truebreak# 不应该发生,安全起见中断ifj>i+5:# 最多向后找5行breakj+=1iffound_brace:# 把从 i 到 j 的行原样加入forkinrange(i,j+1):new_lines.append(lines[k])# 在 j 行后插入 includenew_lines.append(INCLUDE_LINE)insert_count+=1i=j+1modified=Trueelse:new_lines.append(line)i+=1else:new_lines.append(line)i+=1ifmodified:withopen(file_path,'w',encoding='utf-8')asf:f.writelines(new_lines)returnmodified,insert_countdefapply_rules():print("[3/5] 批量插入 include ...")files=get_conf_files()modified_files=0total_inserts=0forfpinfiles:mod,cnt=insert_include_in_file(fp)ifmod:modified_files+=1total_inserts+=cntprint(f" [+] 修改:{fp}(插入{cnt}个 include)")print(f"处理完成:修改{modified_files}个文件,共插入{total_inserts}个 include。")deftest_nginx():print("[4/5] 检查 Nginx 语法...")result=subprocess.run(["nginx","-t"],capture_output=True,text=True)print(result.stdout)print(result.stderr)returnresult.returncode==0defreload_nginx():print("[5/5] 重载 Nginx ...")subprocess.run(["systemctl","reload","nginx"],check=True)print("部署成功!")defverify():print("\n=== 验证引用情况 ===")files=get_conf_files()forfpinfiles:withopen(fp,'r')asf:content=f.read()count=content.count(SNIPPET_FILE)ifcount>0:print(f"{fp}:{count}个 include")print("验证完成。")defrollback():print("检测到语法错误,正在自动回滚...")ifos.path.exists(CONF_ROOT):shutil.rmtree(CONF_ROOT)shutil.copytree(BACKUP_DIR,CONF_ROOT)print(f"已恢复配置,备份目录保留:{BACKUP_DIR}")print("正在重新加载 Nginx 使回滚生效...")subprocess.run(["systemctl","reload","nginx"],check=False)defmain():backup_configs()create_snippet()apply_rules()iftest_nginx():reload_nginx()verify()print("✅ 敏感路径封锁规则已生效。")else:rollback()print("❌ 语法错误,已回滚并重载 Nginx。请检查配置。")sys.exit(1)if__name__=="__main__":main()

Esc,输入:wq保存退出。


第 4 步:执行脚本

chmod+x /root/apply_block_rules.py python3 /root/apply_block_rules.py

脚本会自动完成:

  1. 备份配置
  2. 创建规则文件
  3. 批量插入 include(准确识别server {}块,忽略upstreamserver指令、注释)
  4. 检查 Nginx 语法
  5. 语法通过则重载,失败则自动回滚并重载旧配置
  6. 输出验证信息

第 5 步:手动验证(可选,但建议)

5.1 查看哪些文件包含规则引用
grep-rl"block_sensitive_paths.conf"/etc/nginx/conf.d/
5.2 查看每个文件的 include 数量
grep-rc"block_sensitive_paths.conf"/etc/nginx/conf.d/|grep-v':0'
5.3 测试敏感路径拦截
curl-Ihttp://127.0.0.1/actuatorcurl-Ihttp://127.0.0.1/actuator/health

如果返回HTTP/1.1 444或 curl 报连接被关闭,说明拦截成功。


回退步骤

如果脚本未自动回滚或需要手动恢复,可执行以下操作:

  1. 查看备份目录
ls-td/etc/nginx/conf.d.bak.*|head-n5
  1. 恢复备份(替换为实际备份目录名)
rm-rf/etc/nginx/conf.dcp-r/etc/nginx/conf.d.bak.20260821_173000 /etc/nginx/conf.d
  1. 检查并重载
nginx-t&&systemctl reload nginx

总结

通过以上步骤,我们可以在所有 Nginxserver块中统一加入敏感路径封锁规则,让外部访问/actuator/swagger-ui/druid/health/metrics等路径时直接被关闭连接(444),有效隐藏敏感信息,降低被扫描攻击的风险。

整个方案具备以下特点:

  • 自动化:脚本自动备份、自动插入、自动检查、自动回滚。
  • 安全性:只修改 Nginx 配置,不涉及应用代码;语法检查失败自动恢复。
  • 通用性:适用于任何使用标准 Nginx 的 Linux 云服务器。
  • 无侵入:不影响正常业务,不干扰upstream定义。

建议先在测试环境验证一遍,再上生产环境执行,确保万无一失。

效果

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/24 14:40:12

【单片机毕设案例分享】基于 51/STM32 单片机的温室补光通风加湿一体化控制系统设计 基于 51/STM32 单片机的环境安全感知与继电器联动控制系统设计(017904)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于单片机&#xff0c;STM32单片机&#xff0c;51单片机&#xff0c;J…

作者头像 李华
网站建设 2026/8/24 14:39:31

SeetaFace6 完整指南:9 大模块 3 步搭起一套人脸识别系统

SeetaFace6 完整指南&#xff1a;9 大模块 3 步搭起一套人脸识别系统 【免费下载链接】SeetaFace6 SeetaFace 6: Newest open and free, full stack face recognization toolkit. 项目地址: https://gitcode.com/gh_mirrors/se/SeetaFace6 SeetaFace6 是中科视拓开源免…

作者头像 李华
网站建设 2026/8/24 14:36:23

PLL学习记录1

内容主要参考李致毅老师在B站的视频教程&#xff0c;结合自己的理解。最简单的PD是一个XOR&#xff0c;输入信号不同&#xff08;一个0一个1&#xff09;时输出1&#xff0c;其他时刻输出0如下图所示&#xff0c;当Vout和REF相位差较大时&#xff0c;PD输出的直流分量较高&…

作者头像 李华
网站建设 2026/8/24 14:33:55

DeepSeek Harness 源码安装避坑,Node 版本与 pnpm 依赖冲突处理

源码安装前的环境自检 DeepSeek Harness 的源码安装并不复杂&#xff0c;但前提是环境得先对上路子。官方文档里写得清楚&#xff1a;Node.js 需要 v22.19 及以上&#xff0c;或者直接用 v24 系列&#xff0c;包管理器指定 pnpm。听起来没几行字&#xff0c;实际踩坑的人里&…

作者头像 李华
网站建设 2026/8/24 14:33:41

linux java开发 Linux装Java开发环境?别让JDK选择坑哭你,1.8和11的生死局

这个摘要部分, 是, 要阐述, 怎样, 在linux系统这样子的环境之下, 去进行java开发环境的安装, 接下来, 要对怎么去介绍安装jdk1.8作出说明。关于在linux系统下安装java开发环境的介绍, 本文会先说明如何介绍安装jdk1.8, 之后还会阐述如何安装jdk11。分开两次进行介绍, 原因在于j…

作者头像 李华