• 测试目标:www.ty2c.com(春日花园SpringGarden,Halo 2.25.4 + 1Panel OpenResty + 阿里云 + Cloudflare)

  • 测试时间:2026-07-18

  • 测试性质:站长本人授权的自有资产测试

  • 测试视角:① 公网访客/攻击者视角(经 Cloudflare 边缘)② 绕过 CDN 直连源站视角

  • 测试工具:Playwright 隐身爬虫、wrk 4.2.0 阶梯压测、自研源站直连压测脚本、openssl/curl/dig 手工探测


一、总体结论

维度 评级 说明
应用层安全(注入/XSS/CORS/重定向) ✅ 良好 未发现可利用漏洞
CDN 边缘防护 ✅ 良好(偏严) 自动化流量全部被人机挑战拦截,但误杀了 RSS 订阅
源站暴露面 🔴 高危 源站 IP 已知且允许任意直连,CF 防护可被整体绕过
抗压能力(经 CF) ✅ 优秀 攻击流量无法到达源站
抗压能力(直连源站) 🔴 弱 约 25 并发即达拐点,30 RPS 吞吐封顶,100 并发 p99 达 7.4 秒
配置卫生 ⚠️ 一般 响应头重复冲突、失效统计脚本、TLS 旧版本、邮件安全记录缺失

一句话总结:Cloudflare 把前门守得很好,但源站后门(8.***.***.**5)没锁——任何人知道这个 IP 就能让 CF 的所有防护失效,而源站本身只能扛约 30 RPS。


二、问题清单(按严重度排序)

🔴 P0-1 源站 IP 暴露且未限制直连(高危)

证据:

curl --resolve www.ty2c.com:443:*.***.***.*** https://www.ty2c.com/
→ HTTP 200,完整返回首页(标题"春日花园SpringGarden",109 KB)

源站证书包含 ty2c.com / *.ty2c.com,SNI 匹配即正常应答,未校验回源来源。

影响:

  • 攻击者绕过 Cloudflare 的 WAF、人机挑战、DDoS 防护,直接打击源站;

  • 实测源站直连约 25 并发 / 30 RPS 即饱和(见压测章节),一台普通电脑即可让站点瘫痪;

  • 源站 IP 此前已在公开页面中泄露过(浏览器控制台请求记录),应视为"已公开信息"。

解决方案(三选一,推荐 ①+② 组合):

① 阿里云安全组只放行 Cloudflare 回源 IP(最根本):

  • 登录阿里云 ECS 控制台 → 安全组 → 入方向规则;

  • 删除 80/443 端口的 0.0.0.0/0 放行规则;

  • 添加规则:端口 443,授权对象为 Cloudflare 官方 IP 段(https://www.cloudflare.com/ips/ 列出的 15 个 IPv4 段,如 173.245.48.0/20、103.21.244.0/22 等);

  • 同时检查 1Panel 的防火墙(UFW/firewalld),两层都做更稳。

② 开启 CF Authenticated Origin Pulls(mTLS 双向认证):

  • CF 控制台 → SSL/TLS → 源服务器 → Authenticated Origin Pulls 开启;

  • 在 1Panel 网站配置中加载 CF 源站客户端证书,OpenResty 配置:

  ssl_client_certificate /path/to/cf-origin-pull-ca.pem;
  ssl_verify_client on;
  • 效果:即使有人直连源站 IP,没有 CF 客户端证书一律握手失败。

③ Cloudflare Tunnel(cloudflared):源站完全不暴露公网端口,最彻底但改造最大。


🟠 P1-1 RSS/Atom 订阅被 CF 人机挑战误杀(中危,功能故障)

证据:

https://www.ty2c.com/rss.xml   → 403(cf-mitigated: challenge)
https://www.ty2c.com/atom.xml  → 403(cf-mitigated: challenge)
https://www.ty2c.com/robots.txt → 200(正常)

所有非浏览器流量(curl、RSS 阅读器、API 客户端、搜索引擎部分爬虫)都会收到 403 挑战页。本次测试中 Playwright 隐身浏览器也未能通过挑战。

影响:RSS 阅读器(Feedly、Inoreader、Follow 等)无法订阅你的博客;第三方 API 调用、Webhook、部分搜索引擎爬虫同样受阻。

解决方案:CF 控制台 → 安全性 → WAF → 自定义规则,添加跳过规则:

(http.request.uri.path eq "/rss.xml") or (http.request.uri.path eq "/atom.xml")
or (http.request.uri.path eq "/sitemap.xml") or (http.request.uri.path eq "/robots.txt")
→ 操作:跳过(Skip)→ 跳过所有安全功能/仅跳过托管质询

另外检查是否开启了"Under Attack 模式"或"Bot Fight Mode 质询全部":如果不是处于被攻击状态,建议把安全级别从"高/质询全部"调回"中",只对威胁分高的访客质询。


🟠 P1-2 统计脚本配置错误:http://localhost/script.js(中危,功能故障+混合内容)

证据:首页 HTML 中发现:

<script defer src="http://localhost/script.js" data-website-id="efc7d680-c7fb-469c-b9a8-141672463616"></script>

这是 Umami 统计脚本,但地址写成了 localhost。

影响:

  • 每个访客的浏览器都会向访客自己电脑的 80 端口发请求 → 统计完全失效,控制台报错;

  • http:// 引用属于混合内容,拉低浏览器安全评分;

  • 个别访客本地若恰好跑了服务,行为不可预期。

解决方案:Halo 后台 → 插件(Umami 统计插件或自定义代码注入处)→ 把 http://localhost/script.js 改为你的 Umami 实际地址,例如 https://umami.ty2c.com/script.js;如果没部署 Umami,直接删除这行。


🟡 P2-1 安全响应头重复且取值冲突(低危)

证据(直连源站响应头,CF 边缘看不到这一层):

X-Frame-Options: SAMEORIGIN      ← Halo 应用发出
X-Frame-Options: DENY            ← OpenResty/1Panel 又加了一次
Strict-Transport-Security: ...(重复 2 次)
X-Content-Type-Options: nosniff(重复 2 次)
Referrer-Policy: ...(重复 2 次)

同一头部出现两个不同值时,浏览器行为取决于实现,属于配置缺陷。

解决方案:在 1Panel → 网站 → 配置文件 中,删掉 OpenResty 里重复的 add_header 指令(保留应用层发出的即可),或反过来在应用层关闭、只在 Nginx 层统一管理。建议全站统一为:X-Frame-Options: DENY(或 SAMEORIGIN,如 console 需要 iframe 则 SAMEORIGIN)。


🟡 P2-2 /actuator/health 端点公网可访问(低危)

证据:https://www.ty2c.com/actuator/health → 200 {"groups":["liveness","readiness"],"status":"UP"}(其余 actuator 端点已正确跳转登录页)。

影响:泄露服务存活状态,可被用于攻击前的存活探测与攻击效果监测;信息量少,风险低。注意:Halo 2.21.10 及更早版本存在 actuator 相关访问控制漏洞(CVE-2025-15141),你当前的 2.25.4 不受影响。

解决方案:在 1Panel OpenResty 配置中加一条 location 拦截:

location = /actuator/health { return 404; }

(如 1Panel 健康检查依赖它,可改为仅内网允许。)


🟡 P2-3 CF 边缘仍允许 TLS 1.0/1.1(低危)

证据:openssl s_client -tls1 成功协商 TLSv1(TLS 1.2/1.3 均正常,证书为 Google Trust Services 签发,有效期至 2026-10-14)。

解决方案:CF 控制台 → SSL/TLS → 边缘证书 → 最低 TLS 版本设为 TLS 1.2(2026 年的今天几乎没有合法访客使用 TLS 1.0/1.1)。


🟡 P2-4 域名邮件安全记录不完整(低危)

证据:

ty2c.com TXT:仅 DMARC 记录(v=DMARC1; p=none),无 SPF 记录
MX 记录:无

影响:你的域名不收发邮件,但没有"拒绝一切"的 SPF,攻击者可伪造 @ty2c.com 发件人钓鱼,DMARC p=none 只监控不拦截。

解决方案(Cloudflare DNS 中添加):

ty2c.com      TXT   "v=spf1 -all"
_dmarc.ty2c.com TXT 把现有 p=none 改为 p=reject(观察 1~2 个月无异常后)

🟢 P3-1 版本指纹泄露(提示)

首页 <meta name="generator" content="Halo 2.25.4"/> 暴露精确版本,主题路径 /themes/theme-sky-blog-3/ 暴露所用主题。当前 2.25.4 是最新版(2026-06-24 发布),暂无已知未修复漏洞,风险可控;保持"新版本发布后 1 周内升级"的习惯即可。

🟢 P3-2 待你本地复核:80 端口直连被重置(提示)

测试沙箱中 http://www.ty2c.com/(80 端口)TCP 连接被重置、无任何 HTTP 响应,而对照的其他 CF 站点 80 端口正常 301 跳转。可能是沙箱出口限制,也可能是你的 CF/回源配置导致。请在自己电脑上执行 curl -I http://www.ty2c.com/ 复核:正常应返回 301 → https://...;若也被重置,检查 CF 的"始终使用 HTTPS"是否开启、以及安全组 80 端口策略。


三、压力测试详情

3.1 Cloudflare 边缘压测(公网攻击者视角)

工具:wrk 4.2.0,阶梯 1→10→50→100→200 并发,每级 10s,目标 https://www.ty2c.com/

并发 有效 RPS p90 p99 结果
1 3 1610ms 1970ms 全部被人机挑战拦截(403)
10–200 11–45 1.5–1.7s 1.9s 同上,错误率=挑战率,源站零感知

结论:自动化攻击流量在 CF 边缘即被拦停,无法到达源站。CF 防护本身工作正常——但这也意味着上面 P0-1 的源站直连通道是唯一的软肋。

3.2 源站直连压测(绕过 CF 视角)

工具:自研脚本(SNI 伪装直连 8.***.***.**5:443),阶梯 1→10→25→50→100 并发,每级 8s

  并发 |     RPS |   Avg |   P50 |   P90 |   P99 |  错误率
----------------------------------------------------------------------
     1 |     1.8 | 584.7 | 569.8 | 620.9 | 699.0 |   0.0%
    10 |    18.6 | 557.6 | 549.8 | 597.9 | 724.5 |   0.0%
    25 |    28.8 | 931.3 | 864.6 | 1316.4| 2356.2|   0.0%  ◀ 拐点:p99加速增长
    50 |    29.1 | 1896.2| 1890.1| 2815.1| 3627.6|   0.0%  ◀ 拐点:吞吐饱和+延迟激增
   100 |    32.0 | 3629.4| 3622.4| 5220.3| 7399.3|  0.78%  ◀ 拐点:全面恶化

拐点分析:

  • 吞吐天花板:约 29–32 RPS(并发 25 时触顶,之后增加并发几乎不再提升吞吐);

  • 最佳并发承载:≤ 10(此时 p99 仅 725ms);

  • 并发 25 起 p99 延迟翻了 3 倍;并发 100 时 p99 达 7.4 秒,开始出现失败;

  • 注:测试从境外节点发起,约 500ms 的基础网络延迟放大了绝对值,但吞吐封顶 30 RPS 的相对结论不受影响——动态请求(首页未走 CF 缓存时)就是这台机器的真实容量。

容量结论与建议:

  1. 源站真实承载 ≈ 30 RPS / 25 并发,一台攻击主机即可打满 → P0-1 修复(锁死源站)是当务之急;

  2. 让 CF 尽量缓存静态资源,减少回源:CF → 缓存 → Cache Rules,对 /themes/*、/upload/*、图片/JS/CSS 设置较长的 Edge TTL(你之前卡在"边缘 TTL 无法设置",正确入口是 Cache Rules 里新建规则 → Edge TTL → 忽略 Cache-Control 自定义时长,而不是在 Page Rules 旧界面里找);

  3. Halo 侧可考虑开启页面静态化/缓存插件,降低动态渲染开销。


四、做得好的地方(通过项)

  • ✅ SQL 注入:搜索参数注入单引号无报错泄露(Halo 参数化查询);

  • ✅ XSS 反射:<script>alert(1)</script> 未原样反射;

  • ✅ CORS:未对任意 Origin 放行;

  • ✅ 开放重定向:/login?redirect_uri=外域 未跳转;

  • ✅ HTTP 方法:TRACE 405 / PUT 403 / OPTIONS 404;

  • ✅ 敏感文件:/.git/HEAD、/.env、/backup.zip 均不可读;

  • ✅ 后台保护:/console、/actuator/env 等敏感端点均跳转登录页,且 CF 边缘对 /login、/console 也施加挑战;

  • ✅ Halo 版本为最新 2.25.4,已免疫已知 CVE(如 CVE-2025-15141、CVE-2024-43793);

  • ✅ HSTS preload、证书自动续期、DNS 已全量托管 Cloudflare。


五、修复优先级行动清单


1 阿里云安全组:443/80 仅放行 Cloudflare IP 段(P0-1) 15 分钟
2 CF WAF:放行 /rss.xml、/atom.xml、/sitemap.xml(P1-1) 5 分钟
3 修复或删除 localhost 的 Umami 脚本(P1-2) 5 分钟
4 CF 最低 TLS 版本调为 1.2(P2-3) 2 分钟
5 添加 SPF -all、DMARC 升级 p=reject(P2-4) 5 分钟
6 1Panel 清理重复 add_header(P2-1) 10 分钟
7 拦截 /actuator/health(P2-2) 5 分钟
8 CF Cache Rules 配置静态资源 Edge TTL(3.2 建议2) 15 分钟
9 本地复核 80 端口(P3-2) 2 分钟
10 (进阶)开启 Authenticated Origin Pulls / 迁移 CF Tunnel 1–2 小时


报告完。测试过程中未对站点造成持续影响:CF 边缘压测全部挑战拦截;源站直连压测最高 100 并发 × 8 秒,结束后服务自恢复。

: Halo 访问控制错误漏洞 CVE-2025-15141(影响 ≤2.21.10): https://www.knowsafe.com/ti/info/0/1004200
: Halo 版本发布更新日志(2.25.4,2026-06-24): https://releases.halo.run/changelog


附录:修复完成记录(2026-07-19 全部完工)

步骤 修复项 状态 验证方式
1 阿里云安全组:443 仅放行 CF 15 个 IP 段;删除 80/443/8090 全网放行;清理 3306/6379/445 等高危裸露端口 ✅ 外部直连源站 443/8090 均无法建立连接
2 CF WAF 跳过规则放行 /rss.xml、/atom.xml、/sitemap.xml;安全级别回调 ✅ 外部请求 /rss.xml 返回 200 及完整 XML
3 删除自定义头部注入中的 http://localhost/script.js(Umami 配置修复) ✅ 站长确认
4 CF 最低 TLS 版本调为 1.2 ✅ 外部 TLS1.0/1.1 握手被拒,1.2/1.3 正常
5 新增 SPF v=spf1 -all;DMARC 升级 p=reject ✅ dig 复查两条 TXT 记录生效
6 Nginx 层统一安全响应头,proxy_hide_header 消除与 Halo 的重复冲突 ✅ 源站本地 curl 每类头部仅出现一次
7 Nginx location ^~ /actuator { return 404; } ✅ 源站本地 curl 返回 404
8 CF Cache Rules:静态文件后缀边缘缓存 1 个月 ✅ 浏览器 cf-cache-status: HIT
9 复核 80 端口 ✅ 本地 curl 返回 301 → https,之前为测试端误报

修复后状态:源站仅接受 Cloudflare 回源,DDoS/CC 攻击无法绕过 CDN 直击源站;静态资源由 CF 边缘节点直接响应,源站动态渲染压力大幅降低;RSS 订阅、邮件防伪、TLS 基线、响应头卫生全部达标。

后续维护建议:

  • Halo 新版本发布后 12 周内升级;

  • 阿里云安全组保持"最小放行"习惯,新开端口前三思;

  • 更新主题/图片后前台未变时,到 CF → 缓存 → 清除缓存;

  • 建议每年(或每次大改版后)重新跑一次本报告的测试流程。


附录二:加固后故障排障实录(2026-07-19)

现象:加固完成后,博客前台全部正常,但 /console 与 /uc 打开后界面全部显示 core.xxx.xxx 原始英文键名,期间曾伴随整页 "404 Not Found openresty"。

排查路径(供以后参考的标准流程):

  1. 源站本地测试 http://127.0.0.1:8090/ → 200,Halo 本体健康;

  2. --resolve 全链路测试(SNI+Host)→ 200,nginx 反代健康;

  3. 检查 CF 缓存规则 → 发现"忽略缓存控制+1个月TTL"会缓存 404,已补"状态代码 TTL:404/500 无缓存"并全站清除缓存,但症状未消失;

  4. 查 access.log → 定案:每次打开控制台都出现 GET /actuator/globalinfo 404。

根因:第 7 步加固时将 /actuator 整路径 return 404,但 Halo 控制台/用户中心启动时必须调用 /actuator/globalinfo 获取语言(locale)等全局信息,拿不到就不加载翻译。

修复:nginx 配置改为仅放行必需接口,其余继续屏蔽:

location = /actuator/globalinfo {
    proxy_pass http://127.0.0.1:8090;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}
location ^~ /actuator {
    return 404;
}

经验教训:

  1. 屏蔽路径前先确认无功能依赖(日志是最好的老师);

  2. CF 缓存规则"忽略缓存控制+长 TTL"必须搭配"状态代码 TTL:错误页不缓存",否则故障窗口期的 404 会被长期缓存"投毒";

  3. 排障分层验证:Halo 直连 → nginx 全链路 → CF 边缘 → 日志,逐层缩小范围。