You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测Django API请求来自本站还是外部客户端

Django+DRF 差异化限流实现方案

前置问题修复:请求元数据异常

REMOTE_ADDR为空通常是服务前置了Nginx、CDN等反向代理,Django未配置代理信任规则导致无法获取真实客户端IP,并非字段本身不可用,先做如下配置修复:

  • 在settings.py中配置SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')、USE_X_FORWARDED_HOST = True,同时将反向代理所属网段加入INTERNAL_IPS列表,Django会自动从代理传入的X-Forwarded-For头中提取真实客户端IP,填充到REMOTE_ADDR字段。
  • 注意:仅配置自身可控的可信代理网段,不要信任任意来源传入的X-Forwarded-For头,否则会存在IP伪造、限流被绕过的风险。

客户端身份可靠识别方案

HTTP_REFERER、User-Agent这类字段可被随意伪造、也可能被浏览器/代理层拦截,完全不适合作为客户端身份判断依据。针对同根域名下的Angular客户端,推荐以下两种可防伪造的识别方案,可根据安全等级需求选其一或组合使用:

方案1:带签名的自定义请求头(实现成本最低)

在Angular客户端全局HTTP拦截器中为所有发往后端的请求添加自定义标识头,同时增加签名校验避免头被伪造:

  • 前后端部署时共享一个仅内部可见的签名密钥,Angular端发起请求时,生成当前时间戳,将时间戳拼接密钥做哈希运算,分别将X-Client-Type: angular-web、X-Client-Ts: <当前时间戳>、X-Client-Sign: <哈希值>三个头加入请求。
  • Django层添加轻量中间件,校验三个规则:时间戳与服务器当前时间差不超过300秒、签名哈希匹配、客户端类型头值正确,全部满足则判定为来自自有Angular客户端的合法请求。
  • 跨域配置中,将上述自定义头加入CORS_ALLOW_HEADERS列表,允许Angular所属域名的请求携带这些头。

方案2:根域HttpOnly Cookie校验(防伪造能力更强)

由于Angular客户端与后端同属*.mydomain.com根域,可利用Cookie的同域特性做身份校验:

  • 后端提供一个客户端初始化接口,Angular应用首次加载时先调用该接口,后端在响应中设置根域级HttpOnly Cookie:Set-Cookie: client_verify_token=<随机生成的校验串>; Domain=.mydomain.com; HttpOnly; Secure; SameSite=Strict,校验串存入服务端缓存,有效期与前端会话时长对齐。
  • 后续同域请求会自动携带该Cookie,后端校验缓存中存在对应有效token则判定为自有Angular客户端请求。
  • 该方案的优势是HttpOnly Cookie无法被前端JS读取,外部请求无法直接获取有效校验串,伪造门槛远高于自定义头方案,且不需要前端实现签名逻辑。

DRF自定义限流实现

完成身份识别逻辑后,继承DRF自带的SimpleRateThrottle实现两类限流规则即可:

from rest_framework.throttling import SimpleRateThrottle
from myapp.utils import is_legitimate_angular_request  # 导入前面实现的客户端校验逻辑

class AngularClientThrottle(SimpleRateThrottle):
    scope = "angular_client"
    def get_cache_key(self, request, view):
        if is_legitimate_angular_request(request):
            ident = self.get_ident(request)
            return self.cache_format % {"scope": self.scope, "ident": ident}
        return None

class ExternalRequestThrottle(SimpleRateThrottle):
    scope = "external_request"
    def get_cache_key(self, request, view):
        if not is_legitimate_angular_request(request):
            ident = self.get_ident(request)
            return self.cache_format % {"scope": self.scope, "ident": ident}
        return None

在settings.py中注册限流类并配置对应阈值:

REST_FRAMEWORK = {
    "DEFAULT_THROTTLE_CLASSES": [
        "myapp.throttles.AngularClientThrottle",
        "myapp.throttles.ExternalRequestThrottle",
    ],
    "DEFAULT_THROTTLE_RATES": {
        "angular_client": "1000/min",  # 自有Angular客户端配置更高限流阈值
        "external_request": "30/min",  # curl等外部请求配置更严格的阈值
    }
}

避坑说明

  • 所有用于客户端识别的标识字段,必须做服务端签名/有效性校验,禁止仅凭明文头、Cookie值判断身份,否则任何人都可以通过curl添加相同头直接绕过限流规则。
  • 如果服务链路中包含CDN,需要在CDN配置中透传自定义的校验头,否则请求到达Django层时头会被CDN过滤,导致识别逻辑失效。
  • 禁止使用User-Agent作为判断依据,该字段可被任意客户端随意修改,curl通过-A参数即可模拟任意浏览器UA,无任何校验价值。

内容的提问来源于stack exchange,提问作者gmcc051

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 11:30:48