CDN(内容分发网络)的核心原理,是将网站内容缓存到分布在各地的边缘节点。当用户访问网站时,请求会被自动调度到距离最近、负载最合适的节点,由节点直接返回内容,而不必每次都访问源站服务器。
获取 EdgeOne 回源 IP 网段
为了让 CDN 的防护效果最大化,在使用 CDN 后隐藏回源域名并限制访问,是一项必要的操作(?)。一种比较有效的方法是:源站的回源域名仅允许 CDN 节点 IP 段访问,而其他访客只能通过 CDN 代理后的加速域名进行访问。这一点通过配置 Nginx 即可轻易实现。
腾讯云的EdgeOne CDN提供了CDN节点的IP段,需要在安全防护-源站防护中手动开启该功能。
需要注意的是,腾讯云 EdgeOne 会不定期更新回源 IP 网段,因此必须在 IP 段变更前及时更新服务器 Nginx 配置中允许回源的 IP 段,否则回源失败,CDN连不上源站就直接炸了。
参考边缘安全加速平台 EO 源站防护(获取/更新 EdgeOne 回源 IP 网段)文档,我们可以写一个 Python 程序来自动更新 IP 段(实则是由ChatGPT和Gemini帮我写的):
# pip install tencentcloud-sdk-python
# 可添加每日定时任务来自动执行该文件
# 直接在Nginx配置中用include引用生成的teo_real_ip.conf即可
import json
import os
from tencentcloud.common import credential
from tencentcloud.teo.v20220901 import teo_client, models
# --- 配置区 ---
SECRET_ID = "你的SecretId"
SECRET_KEY = "你的SecretKey"
ZONE_ID = "你的ZoneId"
# 生成的 Nginx 配置文件路径
CONF_FILE_PATH = "/www/server/nginx/conf/teo_real_ip.conf"
# --- --- ---
def fetch_teo_ips():
try:
cred = credential.Credential(SECRET_ID, SECRET_KEY)
client = teo_client.TeoClient(cred, "")
req = models.DescribeOriginACLRequest()
req.ZoneId = ZONE_ID
resp = client.DescribeOriginACL(req)
data = json.loads(resp.to_json_string())
# 获取当前 IP 和 即将生效的 IP (NextOriginACL)
# 建议两者都加上,确保在 IP 切换期间平滑过渡
acl_info = data.get("OriginACLInfo", {})
ipv4_list = acl_info.get("CurrentOriginACL", {}).get("EntireAddresses", {}).get("IPv4", [])
next_acl = acl_info.get("NextOriginACL")
if next_acl:
next_ipv4 = next_acl.get("EntireAddresses", {}).get("IPv4", [])
ipv4_list = list(set(ipv4_list + next_ipv4)) # 合并去重
return ipv4_list
except Exception as e:
print(f"获取 IP 失败: {str(e)}")
return None
def update_nginx_config(ips):
if not ips:
return
content = "# 腾讯云 EdgeOne 回源 IP 段自动更新\n"
content += "real_ip_header X-Forwarded-For;\n"
content += "real_ip_recursive on;\n\n"
for ip in ips:
content += f"set_real_ip_from {ip};\n"
with open(CONF_FILE_PATH, "w") as f:
f.write(content)
# 重载 Nginx (宝塔环境命令)
os.system("/etc/init.d/nginx reload")
print("TEO IP 段已更新,Nginx 已重载")
if __name__ == "__main__":
ips = fetch_teo_ips()
if ips:
update_nginx_config(ips)
代码理论上是没问题的,但是运行后报错提示区域没attribute。研究了一会才发现,腾讯云 EdgeOne 免费套餐并不提供源站防护功能,因此自然没有权限调用相关接口。
当然,GitHub 上其实有不少更新腾讯云 CDN IP 网段的仓库,考虑到 IP 段变更周期通常较长(数月一次),手动复制也不是不行。只是,仅仅是公开几个全网可查的回源 IP 段,腾讯云免费版套餐却无法调用,我只想说:
这很腾讯。
自动更新白名单 IP 段的方案在免费版套餐中暂时走不通(我们白嫖党是这样子的),上面的尝试先保留在此。
header鉴权
当 CDN 边缘节点未命中缓存,或请求的内容本身不允许缓存(如动态接口)时,边缘节点会向源站服务器回源获取数据,并将结果返回给用户。
因此,访客访问加速域名时,所有请求都会先到达 CDN 边缘节点;只有在缓存未命中的情况下,请求才会由边缘节点转发至源站服务器。
我们可以在 CDN 向源站回源的请求中加入特定的请求头字段,并在源站的 Web 服务器中校验该请求头作为“暗号”。
当请求携带正确的请求头时,说明该请求是由 CDN 节点回源发起的,可以正常放行;反之,则说明存在访客绕过 CDN 直接访问源站的行为,源站可直接返回 444 拒绝连接。
由于用户的所有访问请求都会先到达 CDN,再由 CDN 统一回源,因此通过 CDN 正常访问的请求,在回源阶段必然会携带该请求头,从而实现对源站的有效保护。
这里假设我们在 Header 中加入这样一个字段,用于 CDN 回源节点与源站 Nginx 之间的鉴权:
X-Origin-Token: Your_Secret_Code
整个流程大概是这样子的:
无对应的header字段:
浏览器
↓(没有 X-Origin-Auth)
源站 Nginx
↓
if ($http_x_origin_auth != "密钥") → return 444 → 关闭连接
有对应的header字段:
浏览器
↓
CDN 边缘节点
↓(EdgeOne规则引擎:CDN 在“回源请求”里自动加 X-Origin-Auth)
源站 Nginx
↓
校验通过 → 正常返回
配置
我们需要在 CDN 节点的回源请求中加入这个字段(字段名和内容可自定义,建议尽量复杂):


然后修改服务器的Nginx配置:
# --- EO CDN回源 header 鉴权 ---
# 检查回源请求头是否匹配
if ($http_x_origin_token != "Your_Secret_Code") {
# 如果不匹配,说明是绕过 CDN 的直连,直接断开连接不给响应
return 444;
}
# 获取真实 IP ,理论上请求都是来自 EdgeOne 的流量,保证了X-Forwarded-For真实性;
# 为了防止服务器的WAF因某些原因把CDN的回源ip给拦了,这里信任了0.0.0.0/0(生产环境慎用)
# real_ip_header X-Forwarded-For;
# set_real_ip_from 0.0.0.0/0;
# real_ip_recursive on;
理论上就ok了。
可以看到,直接用源站域名连接是超时的,而通过CDN访问则正常。


小结
要想彻底保护源站,最保险的方法还是限制 CDN IP 段,这是直接从底层逻辑进行防御了。黑客即便猜到了设置的 Header 暗号,如果他没 CDN 节点转发请求,也连不上的服务器。而使用回源鉴权对暗号呢,一旦有人截获了 Header 名字和内容,就可以直接伪造这个 Header 进行攻击。
当然,本文所描述的 Header 鉴权只是一种最简单、直接明文传输的初级方法,虽然有一点用,但是Header及密钥一旦泄露/被截获,就完犊子了。
有关回源鉴权的更多形式,还请参见这篇文章。










