#!/bin/bash
# 侧重正反面攻防:带有熔断机制的 Cloudflare IP 自动同步脚本 (高内聚版)
CONF_FILE="/opt/apps/openresty/openresty/conf/conf.d/cloudflare_ips.conf"
TEMP_FILE="/tmp/cloudflare_ips.conf.tmp"
CONTAINER_NAME="openresty-test"
# 1. 初始化文件并写入【功能声明】(解决人工维护的认知断层)
> $TEMP_FILE
echo "# ==========================================" >> $TEMP_FILE
echo "# [全局防御] Cloudflare 真实 IP 透传与信任链" >> $TEMP_FILE
echo "# 更新时间: $(date)" >> $TEMP_FILE
echo "# ==========================================" >> $TEMP_FILE
echo "real_ip_header CF-Connecting-IP;" >> $TEMP_FILE
echo "real_ip_recursive on;" >> $TEMP_FILE
echo "" >> $TEMP_FILE
# 2. 拉取最新动态 IP 数据并追加到同一个文件中
curl -s -m 10 https://www.cloudflare.com/ips-v4 | sed -e 's/^/set_real_ip_from /' -e 's/$/;/' >> $TEMP_FILE
echo "" >> $TEMP_FILE
curl -s -m 10 https://www.cloudflare.com/ips-v6 | sed -e 's/^/set_real_ip_from /' -e 's/$/;/' >> $TEMP_FILE
# 3. 熔断校验
LINES=$(wc -l < $TEMP_FILE)
if [ "$LINES" -lt 15 ]; then
echo "数据拉取异常,触发熔断。"
exit 1
fi
# 4. 覆盖与重载
cat $TEMP_FILE > $CONF_FILE
docker exec $CONTAINER_NAME nginx -t
if [ $? -eq 0 ]; then
docker exec $CONTAINER_NAME nginx -s reload
echo "配置模块已整体更新并生效。"
else
echo "语法错误!"
exit 1
fi第三方分析:
这套原始脚本在基础闭环(获取、校验、重载)上已经具备了良好的工程雏形,尤其是引入了行数熔断机制。然而,站在正反面攻防与黑天鹅事件的极端视角下,配合“降低行政权重偏见(摆脱硬编码约束)”、“提高垂直拉升敏感度(快速响应异常)”与“强化实时同步”的深层技术要求,该脚本依然存在致命的隐患链。
以下是对当前架构的深度剖析及重构方案:
一、 隐患剖析与黑天鹅风险分析
1. 反面攻防漏洞:脏数据注入与配置污染(黑天鹅)
- 现象:原始脚本仅靠
wc -l < $TEMP_FILE判断行数是否大于15。 - 黑天鹅场景:如果 Cloudflare 的 API 节点发生故障(例如返回 502 Bad Gateway 页面,或者被中间人劫持返回长篇 HTML 报错),
curl依然会成功返回 200 或抓取到大量错误文本。此时行数远超 15 行,sed会将 HTML 标签处理为set_real_ip_from <html>;并直接写入正式配置文件。 - 后果:由于是先覆盖文件再执行
nginx -t,一旦语法错误,虽然脚本会退出,但错误的配置已经残留在生产目录中。当下一次容器重启或别处触发重载时,OpenResty 将直接崩溃挂掉。
2. 行政权重偏见:容器名称硬编码
- 现象:脚本中硬编码了
CONTAINER_NAME="openresty-test"。 - 风险:在进行版本升级、容器重建或跨机器迁移时,容器名后缀(如 test)是由系统随机或按规则生成的。一旦后缀变更,脚本的
docker exec将全部失效,导致实时同步链条彻底断裂。
3. 垂直拉升敏感度缺失:缺乏原子化回滚
- 现象:配置校验失败后,仅输出了“语法错误!”,没有对已污染的
$CONF_FILE进行任何恢复操作。高度敏感的系统需要具备“毫秒级就地恢复”的能力,容不得半点人工介入的延时。
4. 链路盲区:WordPress 容器的“最后一公里”
- 现象:只解决了 OpenResty 层的 IP 信任,忽略了 OpenResty 到 WordPress 容器之间的反向代理逻辑。
- 风险:如果 OpenResty 传给 WordPress 的是其自身的容器内网 IP(如
172.18.0.x),WordPress 后台记录的依然是错误 IP。
二、 强化版自动同步脚本 (防御重构版)
基于以上分析,对脚本进行重构。此版本实现了数据清洗、动态容器识别、原子化备份回滚以及严格格式熔断:
#!/bin/bash
# ==============================================================================
# 强化版 Cloudflare IP 自动同步与黑天鹅防御脚本
# 适用环境: OpenResty / WordPress 容器化架构
# ==============================================================================
CONF_FILE="/opt/apps/openresty/openresty/conf/conf.d/cloudflare_ips.conf"
BACKUP_FILE="/tmp/cloudflare_ips.conf.bak"
TEMP_FILE="/tmp/cloudflare_ips.conf.tmp"
# 1. 动态获取 OpenResty 容器名(消除硬编码偏见,增强环境自适应)
CONTAINER_NAME=$(docker ps --filter "name=-openresty" --format "{{.Names}}" | head -n 1)
if [ -z "$CONTAINER_NAME" ]; then
echo "[错误] 未检测到运行中的 OpenResty 容器,同步终止。"
exit 1
fi
# 2. 实时拉取动态 IP 数据
echo "[动态同步] 开始从官方源获取最新数据..."
RAW_V4=$(curl -s -m 15 https://www.cloudflare.com/ips-v4)
RAW_V6=$(curl -s -m 15 https://www.cloudflare.com/ips-v6)
# 3. 黑天鹅防御:严格的正则表达式清洗(过滤任何非严格 CIDR 格式的脏数据/HTML)
VALID_V4=$(echo "$RAW_V4" | grep -E '^([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]+$')
VALID_V6=$(echo "$RAW_V6" | grep -E '^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}/[0-9]+$')
COUNT_V4=$(echo "$VALID_V4" | grep -c '^' || echo 0)
COUNT_V6=$(echo "$VALID_V6" | grep -c '^' || echo 0)
# 4. 提高敏感度的多维熔断机制(不仅看总行数,还要确保 v4/v6 核心资产数据完整)
if [ "$COUNT_V4" -lt 10 ] || [ "$COUNT_V6" -lt 5 ]; then
echo "[熔断触发] 提取到有效的 IPv4($COUNT_V4) 或 IPv6($COUNT_V6) 数量不足,疑为异常数据,取消本次同步。"
exit 1
fi
# 5. 构造临时配置文件
{
echo "# =================================================="
echo "# [全局防御] Cloudflare 真实 IP 透传信任链 (由脚本自动维护)"
echo "# 最新数据同步时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "# =================================================="
echo "real_ip_header CF-Connecting-IP;"
echo "real_ip_recursive on;"
echo ""
echo "$VALID_V4" | sed -e 's/^/set_real_ip_from /' -e 's/$/;/'
echo ""
echo "$VALID_V6" | sed -e 's/^/set_real_ip_from /' -e 's/$/;/'
} > $TEMP_FILE
# 6. 安全备份现有生产配置(防患未然的后退一步)
if [ -f "$CONF_FILE" ]; then
cp "$CONF_FILE" "$BACKUP_FILE"
fi
# 7. 原子替换并实施垂直拉升校验
cat $TEMP_FILE > $CONF_FILE
docker exec $CONTAINER_NAME nginx -t > /dev/null 2>&1
if [ $? -eq 0 ]; then
# 校验通过,实时重载生效
docker exec $CONTAINER_NAME nginx -s reload
echo "[成功] 最新数据已平滑同步,容器 [$CONTAINER_NAME] 配置成功重载。"
rm -f $TEMP_FILE $BACKUP_FILE
else
# 校验失败,实施毫秒级防御性回滚,保护源站不崩溃
echo "[核心警告] Nginx 语法校验失败!检测到潜在配置污染,启动安全回滚!"
if [ -f "$BACKUP_FILE" ]; then
cat $BACKUP_FILE > $CONF_FILE
docker exec $CONTAINER_NAME nginx -s reload
echo "[回滚] 已成功恢复至上一次稳定版配置。"
else
rm -f $CONF_FILE
echo "[应急] 无历史备份,已清空故障配置文件以确保服务可启动。"
fi
rm -f $TEMP_FILE
exit 1
fi三、 正反面攻防多角度延伸分析
为了确保 WordPress 后台拿到的 IP 100% 准确,必须跳出脚本本身,从整体架构的攻防两端进行全盘审视:
1. 正面攻防:OpenResty 至 WordPress 的信任链传递
在 OpenResty 的 WordPress 站点的 proxy.conf 或 location / 块中,必须显式向上游(WordPress 容器)传递已被清洗修复的 $remote_addr。
请确保包含以下配置:
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;逻辑闭环:当配置了
real_ip_recursive on;且匹配到 Cloudflare IP 后,Nginx 的$remote_addr变量会被自动替换为客户端的真实访客 IP。此时再通过X-Real-IP传给 WordPress,WordPress 就能直接获取到准确的访客数据。
2. WordPress 侧的多角度兼容(黑天鹅兜底)
部分 WordPress 插件或主题在多层反向代理下,可能会直接抓取 HTTP_X_FORWARDED_FOR 的首位或末位。如果发现后台登录 IP 仍然显示为 Docker 网关 IP(如 172.x.x.x),需要在 WordPress 根目录的 wp-config.php 中,在 wp-settings.php 引入之前,加入如下垂直干预代码:
// 强化层:识别反向代理带来的真实IP
if (isset($_SERVER['HTTP_X_REAL_IP'])) {
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_REAL_IP'];
} elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
// 存在多级代理时,合理拆分并取第一个非受信任的合法IP
$arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$_SERVER['REMOTE_ADDR'] = trim($arr[0]);
}3. 反面被动防御:绕过 CDN 直连源站攻击
- 潜在风险:黑客如果通过扫描 IP 段直接发现了你的 VPS 公网 IP,就可以绕过 Cloudflare 直接向 OpenResty 发起请求。此时,即便写了
CF-Connecting-IP透传,黑客也可以在 Header 中伪造任意的CF-Connecting-IP注入虚假日志,实施投毒或绕过应用层审计。 - 发散防御对策:
- Nginx 默认空主机头兜底:禁止通过 IP 直接访问网站,未绑定域名的请求直接返回 444。
- 源站防火墙闭环:如果业务完全托管于 Cloudflare,建议配合 vps 的系统防火墙(UFW/Firewalld),设置 只允许来自 Cloudflare IP 段的流量访问 VPS 的 80/443 端口。这样即使源站 IP 泄露,非 CF 节点的直接扫描也会在网络层被丢弃,达成终极的主动防御。