当分发内容需要遵守版权协议或贸易合规要求时,CloudFront的地理限制(Geo Restriction)能在边缘节点直接拦截或放行来自特定国家的请求。这个功能的判定依据是客户端连接边缘节点时的源IP地址,而不是HTTP请求头里可能被伪造的X-Forwarded-For或CloudFront-Viewer-Country。下面这张图展示了请求到达边缘节点后,地理判定与缓存查找之间的先后关系。

地理限制的底层判定逻辑
CloudFront在地理限制中维护两种列表:允许列表(Whitelist)和拒绝列表(Blacklist)。每次请求到达任意边缘节点时,节点会先提取TCP连接的源IP,然后通过内部的地理IP数据库确定该IP所属国家。注意这里使用的是AWS自己维护的数据库,更新频率不会实时反映IP归属变化,因此如果一个国家的IP段刚被重新分配,可能存在数小时到数天的判定延迟。判定完成后,节点将国家代码与列表比对:如果国家在拒绝列表中,请求直接返回403状态码;如果在允许列表中,则继续后续的缓存和回源流程;如果两种列表都未配置,地理限制功能不生效。
未匹配情况是很多人容易混淆的地方。当你只配置了允许列表时,只有列表内的国家能够通过,其他所有国家都会被拒绝。但当你只配置了拒绝列表时,只有列表内的国家会被拒绝,其他所有国家都会放行。这并不意味着未知国家会被自动拦截,而是完全取决于你采用的是白名单还是黑名单模式。另外,CloudFront返回的403响应可以配合自定义错误页面来优化用户体验,但自定义错误页面的缓存行为需要单独配置,否则可能影响地理限制的判定效果。
还有一个关键点需要明确:地理限制发生在边缘节点处理请求的早期阶段,早于缓存查找和源站请求。也就是说,即使某个被拒绝国家的用户请求的内容已经缓存在边缘节点上,该请求也会在到达缓存之前被拦截,不会消耗缓存命中率统计。这个特性使得地理限制可以作为一种低成本的访问控制手段,比在源站实现过滤节省了大量回源流量。
通过控制台与AWS CLI配置地理限制
在CloudFront控制台中选择目标分发,进入“地理限制”标签页,可以看到“允许列表”和“阻止列表”两个选项。选择“阻止列表”后,在下方输入框中添加需要屏蔽的国家代码,例如CN、RU、IN,多个代码用逗号分隔。保存后CloudFront会立即将配置下发到所有边缘节点,通常几分钟内全球生效。需要注意的是,控制台目前只能添加国家级别,不支持地区或城市级别的限制,如果需要更细粒度,就要借助后续介绍的CloudFront Functions。
命令行方式适合自动化部署和批量更新。使用AWS CLI的update-distribution命令时,需要先获取当前分发的ETag和配置,修改GeoRestriction部分后再提交。下面是一个完整的bash脚本,演示如何把某个分发的阻止列表更新为包含CN和RU:
#!/bin/bash
DIST_ID="E1ABCDEFG12345"
# 获取当前配置和ETag
CONFIG=$(aws cloudfront get-distribution-config --id $DIST_ID)
ETAG=$(echo "$CONFIG" | jq -r '.ETag')
# 提取现有配置并修改GeoRestriction
NEW_CONFIG=$(echo "$CONFIG" | jq '.DistributionConfig | .Restrictions.GeoRestriction = {"RestrictionType":"blacklist","Quantity":2,"Items":["CN","RU"]}')
# 提交更新
aws cloudfront update-distribution --id $DIST_ID --if-match $ETAG --distribution-config "$NEW_CONFIG"
上面脚本中的jq操作会替换掉整个GeoRestriction对象,所以如果你之前有其他限制配置,需要先读取旧值再合并。另外,每次更新后ETag都会变化,重复执行时必须重新获取。生产环境中建议把这类操作封装到CI/CD流程里,避免手动修改带来的配置漂移。对于需要临时开放某个国家的情况,可以改为白名单模式并只保留目标国家,这样可以精确控制允许访问的范围。
使用CloudFront Functions实现更细粒度的地理控制
地理限制只能做全站级别的允许或拒绝,无法针对特定路径或文件类型区别对待。例如你希望屏蔽某个国家的用户访问/downloads目录下的安装包,但允许浏览产品页面,就需要在请求到达缓存之前改写或阻断请求。CloudFront Functions运行在边缘节点,执行延迟极低,非常适合做这类轻量级逻辑。下面这个函数会在viewer request事件中检查CloudFront提供的国家代码,如果匹配到被屏蔽国家且请求路径以/downloads/开头,就返回403。
function handler(event) {
var request = event.request;
var headers = request.headers;
// CloudFront会在viewer request中自动添加country头
var countryCode = headers['cloudfront-viewer-country'] ? headers['cloudfront-viewer-country'].value : '';
var uri = request.uri;
var blockedCountries = ['CN', 'RU', 'IN'];
if (blockedCountries.indexOf(countryCode) !== -1 && uri.startsWith('/downloads/')) {
return {
statusCode: 403,
statusDescription: 'Forbidden',
headers: {
'cache-control': {value: 'no-store'},
'content-type': {value: 'text/plain'}
},
body: 'Access denied for your region.'
};
}
return request;
}
cloudfront-viewer-country这个请求头是由CloudFront自动添加的,不需要源站参与,也不能通过客户端伪造。它的值来自边缘节点的地理IP数据库,与地理限制使用同一数据源,因此判定结果一致。在函数中调用该头字段时要注意,如果客户端通过VPN或代理访问,头字段反映的是代理出口IP的国家,而不是用户真实所在国家,这是所有基于IP的地理判定都无法避免的局限。
这个函数只作用于viewer request阶段,意味着请求在到达缓存之前就会被拦截。假如被拦截的请求之前已经缓存过响应,也不会影响函数的执行,因为函数先于缓存查找运行。如果需要在响应阶段根据国家修改内容,比如对某些国家返回不同的产品价格,可以使用viewer response事件,但viewer response阶段拿到的国家代码同样是基于请求阶段的IP,不会因为响应内容而改变。
CloudFront Functions的限制是最大代码大小10KB,执行时间不超过1ms,适合轻量判断。如果逻辑复杂到需要查询外部数据库或者做异步操作,应该改用Lambda@Edge,后者运行在区域边缘,支持Node.js和Python运行时,可以调用第三方地理数据库或者根据IP段动态计算。不过Lambda@Edge的冷启动延迟和成本都高于CloudFront Functions,对于简单的按国家屏蔽需求,Functions是更合适的选择。
地理限制与WAF地理匹配的差异及选择建议
AWS WAF同样提供地理匹配规则,可以在CloudFront分发上附加Web ACL,按国家代码允许或阻止请求。两者的核心区别在于执行层级和灵活性。CloudFront地理限制直接集成在分发配置中,无需额外费用,但只能做全站级别的黑白名单。WAF地理匹配规则可以与其他规则组合,例如同时检查国家代码和IP信誉、SQL注入特征,还能设置计数模式只观察不阻断,并且支持基于速率的限制。
如果只是简单地屏蔽几个国家,CloudFront地理限制就已经足够,而且配置更简单、延迟更低。如果还需要针对不同路径、不同HTTP方法、不同User-Agent做组合控制,或者需要详细的请求日志来审计哪些国家被拦截了多少次,那么WAF是更完整的选择。不过WAF会产生额外的请求费用和规则费用,对于高流量分发,成本需要提前评估。
实际使用中还有一种混合策略:用CloudFront地理限制做第一层粗粒度拦截,把绝大多数来自受限国家的请求在边缘节点直接丢弃,再用WAF对放行的流量做精细检测。这样既能降低WAF的处理压力,又能保留复杂规则的能力。但要注意两者的判定结果可能因为会话保持或IP数据库更新时间不同而出现短暂不一致,设计时不要把关键安全控制完全依赖其中任何一层。
最后提醒一点,地理限制不应被视为法律合规的充分条件。如果业务必须遵守特定国家的数据驻留或出口管制要求,需要在源站层面再次校验,因为CloudFront边缘节点虽然会拦截直接请求,但无法防止攻击者通过被允许国家的代理中转访问。结合签名URL、Token认证以及源站侧的IP白名单,才能构建更完整的访问控制体系。
AWS CloudFront地理限制Geo Restriction修改时间:2026-09-18 13:35:02