尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

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

云平台服务器遭遇黑客攻击?用 Nginx 批量封锁敏感接口,自动返回 444 关闭连接 前言最近在处理云平台服务器安全问题时发现大量来自外部的扫描请求目标直指/actuator、/swagger-ui、/druid、/health、/metrics等敏感路径。这些路径一旦暴露黑客可能获取系统内部信息、配置详情甚至数据库监控页面为进一步渗透提供便利。本文将介绍一种通用的 Nginx 加固方案批量在所有server块中插入安全规则让外部访问这些敏感路径时直接返回444Nginx 特有的“关闭连接”响应码从源头阻断扫描降低被攻击风险。方案适用于所有使用标准 Nginx 的 Linux 云服务器不依赖特定云厂商只需本地修改 Nginx 配置风险可控。为什么要这样做黑客在对云服务器发起攻击前通常会进行自动化扫描探测常见的管理端点、API 文档、监控页面等。例如/actuatorSpring Boot 应用监控端点可能泄露 beans、env、health、metrics 等信息。/swagger-ui、/v2/api-docs接口文档暴露 API 结构和参数。/druid阿里巴巴数据库连接池监控页面若未授权可直接查看 SQL 执行情况。/health、/metrics应用健康检查和指标信息可能泄露内部状态。这些路径如果直接返回 404 或 403虽然也能拦截但攻击者仍可判断服务器存在并继续尝试其他路径。而444是 Nginx 自定义的非标准响应码表示直接关闭连接不返回任何 HTTP 响应可以让扫描器认为目标不可达或异常从而增加攻击难度隐藏真实服务信息。这样做的作用批量防护自动扫描/etc/nginx/conf.d/下所有.conf文件为每个server块插入统一的敏感路径封锁规则避免遗漏。精确匹配规则使用正则匹配覆盖/actuator、/api/actuator、/swagger-ui及其子路径防止绕过。安全可控脚本执行前自动备份配置并在修改后运行nginx -t检查语法若语法错误自动回滚不影响线上服务。无业务侵入只拦截指定的敏感路径正常业务接口不受影响。同时脚本会跳过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.dSNIPPET_DIR/etc/nginx/snippetsSNIPPET_FILEos.path.join(SNIPPET_DIR,block_sensitive_paths.conf)BACKUP_DIRf/etc/nginx/conf.d.bak.{datetime.now().strftime(%Y%m%d_%H%M%S)}INCLUDE_LINEf include{SNIPPET_FILE};\ndefbackup_configs():print(f[1/5] 备份配置到{BACKUP_DIR})shutil.copytree(CONF_ROOT,BACKUP_DIR)print(备份完成。)defcreate_snippet():print([2/5] 创建规则文件...)os.makedirs(SNIPPET_DIR,exist_okTrue)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):continuepathos.path.join(root,name)if.bakinpathor/template/inpath:continuefiles.append(path)returnfilesdefis_server_block_start(lines,i):判断第 i 行是否是一个真正的 server 块起始排除 upstream 块内 server 指令linelines[i]strippedline.strip()ifstripped.startswith(#):returnFalse# 形式1server { 同一行ifre.match(r^\s*server\s*\{,line):returnTrue# 形式2纯 server 行后换行 {ifre.match(r^\s*server\s*$,line):# 向后找到第一个非注释行检查是否包含 {ki1whileklen(lines):slines[k].strip()ifs.startswith(#):k1continueif{inlines[k]:returnTrueelse:returnFalsereturnFalsereturnFalsedefinsert_include_in_file(file_path):withopen(file_path,r,encodingutf-8,errorsignore)asf:linesf.readlines()full.join(lines)ifSNIPPET_FILEinfull:returnFalse,0new_lines[]i0modifiedFalseinsert_count0whileilen(lines):linelines[i]ifis_server_block_start(lines,i):# 找到 server 块的 { 所在行插入 include# 如果是 server { 同在一行则直接在该行后插入# 如果是纯 server 行{ 在后续行则在找到 { 的那一行后插入ji found_braceFalsewhilejlen(lines):slines[j].strip()ifs.startswith(#):j1continueif{inlines[j]:found_braceTruebreak# 不应该发生安全起见中断ifji5:# 最多向后找5行breakj1iffound_brace:# 把从 i 到 j 的行原样加入forkinrange(i,j1):new_lines.append(lines[k])# 在 j 行后插入 includenew_lines.append(INCLUDE_LINE)insert_count1ij1modifiedTrueelse:new_lines.append(line)i1else:new_lines.append(line)i1ifmodified:withopen(file_path,w,encodingutf-8)asf:f.writelines(new_lines)returnmodified,insert_countdefapply_rules():print([3/5] 批量插入 include ...)filesget_conf_files()modified_files0total_inserts0forfpinfiles:mod,cntinsert_include_in_file(fp)ifmod:modified_files1total_insertscntprint(f [] 修改:{fp}(插入{cnt}个 include))print(f处理完成修改{modified_files}个文件共插入{total_inserts}个 include。)deftest_nginx():print([4/5] 检查 Nginx 语法...)resultsubprocess.run([nginx,-t],capture_outputTrue,textTrue)print(result.stdout)print(result.stderr)returnresult.returncode0defreload_nginx():print([5/5] 重载 Nginx ...)subprocess.run([systemctl,reload,nginx],checkTrue)print(部署成功)defverify():print(\n 验证引用情况 )filesget_conf_files()forfpinfiles:withopen(fp,r)asf:contentf.read()countcontent.count(SNIPPET_FILE)ifcount0: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],checkFalse)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 步执行脚本chmodx /root/apply_block_rules.py python3 /root/apply_block_rules.py脚本会自动完成备份配置创建规则文件批量插入 include准确识别server {}块忽略upstream内server指令、注释检查 Nginx 语法语法通过则重载失败则自动回滚并重载旧配置输出验证信息第 5 步手动验证可选但建议5.1 查看哪些文件包含规则引用grep-rlblock_sensitive_paths.conf/etc/nginx/conf.d/5.2 查看每个文件的 include 数量grep-rcblock_sensitive_paths.conf/etc/nginx/conf.d/|grep-v:05.3 测试敏感路径拦截curl-Ihttp://127.0.0.1/actuatorcurl-Ihttp://127.0.0.1/actuator/health如果返回HTTP/1.1 444或 curl 报连接被关闭说明拦截成功。回退步骤如果脚本未自动回滚或需要手动恢复可执行以下操作查看备份目录ls-td/etc/nginx/conf.d.bak.*|head-n5恢复备份替换为实际备份目录名rm-rf/etc/nginx/conf.dcp-r/etc/nginx/conf.d.bak.20260821_173000 /etc/nginx/conf.d检查并重载nginx-tsystemctl reload nginx总结通过以上步骤我们可以在所有 Nginxserver块中统一加入敏感路径封锁规则让外部访问/actuator、/swagger-ui、/druid、/health、/metrics等路径时直接被关闭连接444有效隐藏敏感信息降低被扫描攻击的风险。整个方案具备以下特点自动化脚本自动备份、自动插入、自动检查、自动回滚。安全性只修改 Nginx 配置不涉及应用代码语法检查失败自动恢复。通用性适用于任何使用标准 Nginx 的 Linux 云服务器。无侵入不影响正常业务不干扰upstream定义。建议先在测试环境验证一遍再上生产环境执行确保万无一失。效果
返回列表