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

是否存在Django配置可阻止JS调用外部API并设置域名白名单?

实现Django外部资源域名白名单校验

当然可以通过在settings.py中定义白名单,来限制HTML模板中可加载的外部域名资源。下面提供两种实用方案,适配不同协作场景:

方案一:自定义模板标签(推荐,主动校验)

这种方式要求前端开发者通过自定义标签引用外部脚本,从源头控制非法资源加载,适合多人协作的项目场景。

  1. 在settings.py中配置白名单
# settings.py
ALLOWED_EXTERNAL_SCRIPT_DOMAINS = [
    "example.com",
    "cdn.jsdelivr.net",
    "cdnjs.cloudflare.com"
]
# 可选:开启后允许白名单域名的所有子域名
ALLOW_EXTERNAL_SUBDOMAINS = True
  1. 创建自定义模板标签
    在你的Django应用下新建templatetags/external_scripts.py文件:
from django import template
from django.conf import settings
from urllib.parse import urlparse

register = template.Library()

@register.simple_tag
def allowed_script(src):
    # 相对路径或本地资源直接放行
    if not src.startswith(('http://', 'https://')):
        return f'<script src="{src}"></script>'
    
    parsed_url = urlparse(src)
    domain = parsed_url.netloc.lower()
    
    # 校验域名是否在白名单内
    allowed = False
    for allowed_domain in settings.ALLOWED_EXTERNAL_SCRIPT_DOMAINS:
        allowed_domain = allowed_domain.lower()
        if settings.ALLOW_EXTERNAL_SUBDOMAINS:
            if domain.endswith(f'.{allowed_domain}') or domain == allowed_domain:
                allowed = True
                break
        else:
            if domain == allowed_domain:
                allowed = True
                break
    
    if allowed:
        return f'<script src="{src}"></script>'
    else:
        # 可选:返回空内容或抛出模板语法错误
        return ''  # 也可改为 raise template.TemplateSyntaxError(f"Domain {domain} not allowed")
  1. 在模板中使用
    先加载标签库,再用自定义标签替代原生script标签:
{% load external_scripts %}

{% allowed_script "https://example.com/script.js" %}
{% allowed_script "https://unallowed.com/script.js" %} {# 该标签会输出空内容,即资源被阻止 #}

方案二:响应中间件(被动校验,无需修改模板)

如果不想改动现有模板写法,可以通过中间件在响应返回前扫描HTML内容,自动移除非法的script标签。

  1. 安装HTML解析依赖
pip install beautifulsoup4
  1. 编写中间件
    在项目的middleware.py中添加:
from django.conf import settings
from urllib.parse import urlparse
from bs4 import BeautifulSoup

class ExternalScriptWhitelistMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        
        # 仅处理HTML类型的响应
        if 'text/html' not in response.get('Content-Type', ''):
            return response
        
        soup = BeautifulSoup(response.content, 'html.parser')
        scripts = soup.find_all('script', src=True)
        
        for script in scripts:
            src = script['src']
            if not src.startswith(('http://', 'https://')):
                continue
            
            parsed_url = urlparse(src)
            domain = parsed_url.netloc.lower()
            allowed = False
            
            for allowed_domain in settings.ALLOWED_EXTERNAL_SCRIPT_DOMAINS:
                allowed_domain = allowed_domain.lower()
                if settings.ALLOW_EXTERNAL_SUBDOMAINS:
                    if domain.endswith(f'.{allowed_domain}') or domain == allowed_domain:
                        allowed = True
                        break
                else:
                    if domain == allowed_domain:
                        allowed = True
                        break
            
            if not allowed:
                script.decompose()  # 移除非法的script标签
        
        response.content = str(soup).encode(response.charset)
        return response
  1. 注册中间件
    在settings.py的MIDDLEWARE列表中添加中间件路径:
MIDDLEWARE = [
    # ... 其他已有中间件
    'your_app.middleware.ExternalScriptWhitelistMiddleware',
]

额外注意事项

  • 若需要校验CSS等其他外部资源,可扩展上述逻辑,处理<link>标签的href属性。
  • 本地开发时,建议将localhost、127.0.0.1加入白名单,避免影响调试。
  • 方案二的中间件会增加响应处理耗时,高流量场景优先选择方案一。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 03:50:24