
本文详解如何通过正确配置 session_cookie_domain 避免 django 应用在多子域名环境下意外共享会话 cookie,实现基于登录域名的动态、精准 cookie 作用域隔离。
本文详解如何通过正确配置 session_cookie_domain 避免 django 应用在多子域名环境下意外共享会话 cookie,实现基于登录域名的动态、精准 cookie 作用域隔离。
在多子域名部署场景中(如 app.dev.fox.com、abc.dev.fox.com),开发者常误设 SESSION_COOKIE_DOMAIN = '.dev.fox.com'(带前导点),导致浏览器将 Cookie 发送给所有匹配 *.dev.fox.com 的子域名——这不仅违背安全隔离原则,还可能引发跨子域会话污染、权限越权或 Firebase 身份令牌误用等风险。
根本原因在于 Cookie 域名规范:RFC 6265 明确规定,以点开头的域名(如 .dev.fox.com)表示“该域名及其所有子域名”,而不带前导点的完整域名(如 app.dev.fox.com)则严格限定 Cookie 仅在该确切主机名下生效,不会向上匹配父域或同级子域。
✅ 正确做法:移除前导点,使用精确的、不含通配符的域名
提供使用 django-unfold (v0.56+) 构建高级 Django 管理界面的专业指导。当用户提及 django-unfold、unfold admin 等内容时使用此技能。
# settings.py # ❌ 错误:允许所有子域共享(如 app.dev.fox.com 和 abc.dev.fox.com 共享同一 session) SESSION_COOKIE_DOMAIN = '.dev.fox.com' # ✅ 正确:Cookie 仅对指定主机有效 SESSION_COOKIE_DOMAIN = 'app.dev.fox.com' # 仅 app.dev.fox.com 可读写 # ✅ 若需支持 www 子域,也必须显式声明 SESSION_COOKIE_DOMAIN = 'www.dev.fox.com'
动态适配登录域名(进阶需求)
若需根据用户实际访问的 Host 动态设置 Cookie 域(例如:访问 app.dev.fox.com 时 Cookie 写入 app.dev.fox.com,访问 abc.dev.fox.com 时写入 abc.dev.fox.com),Django 默认不支持运行时覆盖 SESSION_COOKIE_DOMAIN,但可通过中间件 + set_cookie() 手动控制:
# middleware.py
from django.utils.deprecation import MiddlewareMixin
class DynamicSessionDomainMiddleware(MiddlewareMixin):
def process_response(self, request, response):
host = request.get_host().split(':')[0] # 忽略端口
# 仅对已认证请求且响应含 session cookie 时生效
if request.user.is_authenticated and 'sessionid' in response.cookies:
# 强制重设 session cookie 域为当前 host
response.set_cookie(
'sessionid',
value=response.cookies['sessionid'].value,
domain=host,
path='/',
secure=request.is_secure(),
httponly=True,
samesite='Lax',
)
return response
并在 MIDDLEWARE 中注册:
MIDDLEWARE = [
# ... 其他中间件
'myapp.middleware.DynamicSessionDomainMiddleware',
]
⚠️ 重要注意事项:
- SESSION_COOKIE_DOMAIN 为 None(默认)时,Cookie 将自动绑定到请求的 Host 头,这是最安全的默认行为,推荐优先使用;仅当需跨子域(如 api.dev.fox.com 与 app.dev.fox.com 共享会话)时才显式设置;
- Firebase ID Token 本身无域限制,其安全性依赖于后端验证逻辑与 Cookie 隔离策略协同——切勿仅靠前端 token 判断权限;
- 修改后务必清除浏览器旧 Cookie 并重启 Django 服务,避免缓存干扰测试;
- 生产环境启用 SECURE_COOKIE = True 时,SESSION_COOKIE_SECURE 必须为 True,否则 Cookie 将被浏览器拒绝发送。
总结:防止子域名 Cookie 共享的关键,在于摒弃模糊的 .domain.com 写法,转而采用精确的 host.domain.com 或利用 Django 默认的 None 行为。动态场景下,中间件干预是可控、可审计的可靠方案。安全始于细节——每个 Cookie 的 Domain 属性,都应是明确的、最小化的信任边界。










