
本文详解如何通过正确配置 session_cookie_domain 避免 django 应用在多子域名环境下意外共享会话 cookie,并支持动态、精准的域名绑定策略。
本文详解如何通过正确配置 session_cookie_domain 避免 django 应用在多子域名环境下意外共享会话 cookie,并支持动态、精准的域名绑定策略。
在多子域名架构(如 app.dev.fox.com、abc.dev.fox.com)中,若未谨慎配置 Cookie 域名,Django 默认可能将 Session Cookie 设置为宽泛的通配域(例如 .dev.fox.com),导致用户在某一子域名登录后,其会话凭据被其他同级或下级子域名自动继承——这不仅违背安全隔离原则,更可能引发越权访问、CSRF 风险及跨租户数据泄露。
根本原因在于 Cookie 域名规范:根据 RFC 6265,当 Domain 属性以点开头(如 .dev.fox.com)时,浏览器会将其解释为“匹配所有以 dev.fox.com 结尾的域名”,包括 app.dev.fox.com、xyz.app.dev.fox.com 等;而不带前导点的域名(如 app.dev.fox.com)则仅精确匹配该主机名,不会向上或向下扩展。
因此,解决思路非常明确:禁用通配语义,采用精确域名绑定。
✅ 正确配置方式(静态场景)
在 settings.py 中,移除 SESSION_COOKIE_DOMAIN 的前导点:
提供使用 django-unfold (v0.56+) 构建高级 Django 管理界面的专业指导。当用户提及 django-unfold、unfold admin 等内容时使用此技能。
# ❌ 错误:启用子域名共享 SESSION_COOKIE_DOMAIN = '.dev.fox.com' # ✅ 正确:仅限指定主域名(无前导点) SESSION_COOKIE_DOMAIN = 'app.dev.fox.com' # 仅 app.dev.fox.com 可读写该 Cookie
同样适用于 Firebase 登录后调用 set_cookie() 的场景:确保所有自定义 Cookie(如身份令牌)也显式指定不含前导点的 domain 参数:
response.set_cookie(
key='firebase_token',
value=token,
domain='app.dev.fox.com', # 关键:无前导点
httponly=True,
secure=True,
samesite='Lax'
)
? 动态域名适配(推荐生产实践)
若需支持多租户或多环境(如用户分别访问 app.dev.fox.com 和 abc.dev.fox.com),应避免硬编码域名,改用运行时解析请求 Host 头:
# settings.py 或中间件中
from django.conf import settings
def get_dynamic_cookie_domain(request):
host = request.get_host().split(':')[0] # 忽略端口
# 可选:白名单校验,防止 Host 注入
allowed_domains = {'app.dev.fox.com', 'abc.dev.fox.com', 'staging.dev.fox.com'}
if host in allowed_domains:
return host
return None # 或抛出异常/回退默认值
# 在视图中设置 Cookie 时使用
def login_view(request):
# ... Firebase 验证逻辑
response = redirect('home')
response.set_cookie(
key='sessionid',
value=request.session.session_key,
domain=get_dynamic_cookie_domain(request),
httponly=True,
secure=settings.DEBUG is False,
samesite='Lax'
)
return response
⚠️ 重要注意事项:
- Django 的 SESSION_COOKIE_DOMAIN 不支持运行时动态值(仅启动时读取),因此会话 Cookie 的动态控制必须在视图或响应层手动处理;
- 务必配合 SECURE_SSL_REDIRECT=True 和 SESSION_COOKIE_SECURE=True(生产环境),确保 Cookie 仅通过 HTTPS 传输;
- 若使用 Nginx/Apache 反向代理,请确认 X-Forwarded-Host 头可信且已配置 USE_X_FORWARDED_HOST = True,否则 request.get_host() 可能返回代理地址而非原始域名;
- 所有跨子域名的前端 AJAX 请求需显式设置 credentials: 'include',且后端响应需携带 Access-Control-Allow-Origin(不可为 *)和 Access-Control-Allow-Credentials: true。
通过上述配置,可彻底实现子域名级会话隔离:用户在 app.dev.fox.com 登录,其 Cookie 仅对该域名有效;切换至 abc.dev.fox.com 则视为全新会话,完全符合零信任与最小权限设计原则。










