Appearance
网站按地区限制访问怎么做?IP白名单和区域封锁实战
很多业务都有"按地区控制访问"的需求:版权内容只允许国内观看、后台只允许公司 IP 登录、活动只对某些省市开放……这些需求背后都有同一个技术点——通过 IP 归属地判断用户位置。今天把几种常见的实现方案和坑都讲清楚。
一、典型的地区控制场景
- 内容版权限制:视频、音乐、电子书按国家/地区授权,非授权地区直接返回"所在地区不可观看";
- 后台安全:管理后台只允许公司办公网段的 IP 访问,其他 IP 一律拦截;
- 活动限定:电商大促只对指定省市开放,防黄牛跨区抢购;
- 合规要求:某些行业(如外汇、彩票类)需要限制特定地区用户访问;
- 防攻击:海外攻击源多,直接封禁境外 IP 能挡掉一大半扫描和暴力破解。
二、实现方案
方案一:Nginx 层做地区判断(推荐)
在 Nginx 里用 IP 归属地模块,请求进来先查归属地,命中黑名单地区直接返回 403。优点是在入口就挡掉,不消耗后端资源。
nginx
# 需要安装 ngx_http_geoip2_module 并准备 IP 归属地数据库
geoip2 /etc/nginx/geoip/GeoLite2-City.mmdb {
$geoip2_data_country_code country iso_code;
$geoip2_data_city_name city names zh-CN;
}
# 禁止非中国地区访问 /admin 后台
location /admin {
if ($geoip2_data_country_code != "CN") {
return 403;
}
proxy_pass http://backend;
}方案二:应用层调用 IP 查询 API(灵活,适合动态规则)
如果地区规则经常变(比如活动期间临时开放某省),在应用层做更灵活。以 Python 为例:
python
import requests
from flask import request, abort
def get_ip_location(ip):
"""调用 IP9 免费接口查询归属地"""
resp = requests.get(f"https://ip9.com.cn/get?ip={ip}", timeout=3)
data = resp.json()
if data.get("ret") == 200:
return data["data"]
return None
ALLOWED_PROVS = {"北京", "上海", "广东"} # 活动开放省份
@app.before_request
def check_region():
ip = request.headers.get("X-Forwarded-For", request.remote_addr).split(",")[0]
info = get_ip_location(ip.strip())
if info and info.get("country") == "中国" and info.get("prov") in ALLOWED_PROVS:
return # 放行
abort(403, description="当前地区暂未开放")方案三:后台 IP 白名单
后台安全最简单的做法:只放行白名单 IP。
python
ADMIN_WHITELIST = {"203.0.113.10", "203.0.113.11"} # 公司出口 IP
@app.before_request
def check_admin_whitelist():
if request.path.startswith("/admin"):
ip = request.headers.get("X-Forwarded-For", request.remote_addr).split(",")[0]
if ip.strip() not in ADMIN_WHITELIST:
abort(403)注意:如果公司出口是动态 IP(家庭宽带拨号),白名单会误伤。更稳的做法是"白名单网段 + 登录二次验证"双保险。
三、必须避开的坑
1. 拿不到真实 IP
网站前面挂了 CDN 或负载均衡后,remote_addr 是 CDN 节点 IP,不是用户 IP。必须:
python
# 优先取 X-Forwarded-For,但要防伪造
ip = request.headers.get("X-Forwarded-For", request.remote_addr)
real_ip = ip.split(",")[0].strip()防伪造:X-Forwarded-For 用户可以自己伪造,只信 CDN 回源加的自定义头(如 X-Real-IP,且要在 CDN 配置里禁止用户传入)。
2. 移动网络误伤
手机基站分配的 IP 归属地可能在省内飘,用 4G/5G 的合法用户偶尔会被误判。别做"一刀切封禁",给误判留申诉通道,或者对移动网络(ISP 类型)放宽规则。
3. IPv6 用户
现在很多家庭宽带和手机已经是 IPv6,只查 IPv4 会漏掉。查询接口要 IPv4/IPv6 都支持——IP9 的接口 https://ip9.com.cn/get?ip=2400:3200::1 可以直接查 IPv6。
4. 代理绕过
用 VPN/代理可以轻松改"归属地",所以地区限制防的是"普通人",不是"高手"。对安全要求高的场景,地区判断只是第一道门槛,还要配合设备指纹、行为分析。
四、性能考虑
每个请求都实时查接口会有延迟和限流压力,生产环境建议:
- 本地缓存:IP 归属地短期不变,缓存 10-60 分钟;
- 只对敏感路径做检查:没必要全站每个请求都查,只查
/admin、下单接口等关键路径; - 升级付费版:免费版 60 次/分钟,高并发场景用 VIP 版(18 万次/分钟),或直接用 GeoIP 离线库。
总结
按地区限制访问的完整链路是:拿到真实 IP → 查询归属地 → 匹配规则 → 放行或拦截。小流量用免费 API 完全够,大流量建议 Nginx 离线库或付费接口。不管哪种方案,记住三个关键词:真实 IP、缓存、别一刀切。
IP9 官网:https://www.ip9.com.cn