本文详解 Django 中通过配置 SESSION_COOKIE_DOMAIN 精确限定 Cookie 作用域的方法,解决因误配带前导点(如 .dev.fox.com)导致的跨子域名 Cookie 泄露问题,并提供动态设置方案以实现按登录域名隔离会话。
本文详解 django 中通过配置 `session_cookie_domain` 精确限定 cookie 作用域的方法,解决因误配带前导点(如 `.dev.fox.com`)导致的跨子域名 cookie 泄露问题,并提供动态设置方案以实现按登录域名隔离会话。
在 Web 应用中,Cookie 的作用域(Domain)直接决定其是否会被浏览器发送至特定主机或其子域名。Django 默认将 SESSION_COOKIE_DOMAIN 设为 None,此时 Cookie 仅作用于当前请求的完整主机名(如 app.dev.fox.com)。但一旦显式配置为带前导点的值(例如 '.dev.fox.com'),浏览器便会将其视为“匹配所有以 .dev.fox.com 结尾的域名”,从而导致 abc.dev.fox.com、app.dev.fox.com、甚至 dev.fox.com 共享同一份会话 Cookie——这严重违背安全隔离原则,尤其在多租户、微前端或 Firebase 身份认证集成场景下风险突出。
✅ 正确做法:移除前导点,启用精确匹配
关键规则是:不带前导点的域名表示严格匹配;带前导点的域名表示通配匹配子域名。因此,要阻止跨子域名共享,必须确保 SESSION_COOKIE_DOMAIN 值不含开头的 .。
# ❌ 错误:允许 .dev.fox.com 及所有子域名(如 app.dev.fox.com, abc.dev.fox.com)共享 Cookie SESSION_COOKIE_DOMAIN = '.dev.fox.com' # ✅ 正确:仅作用于 dev.fox.com(注意:无前导点) SESSION_COOKIE_DOMAIN = 'dev.fox.com' # ✅ 正确:仅作用于 app.dev.fox.com(严格匹配该完整域名) SESSION_COOKIE_DOMAIN = 'app.dev.fox.com'
⚠️ 注意:Django 会自动忽略 SESSION_COOKIE_DOMAIN 中的前导点(即 'dev.fox.com' 和 '.dev.fox.com' 在 Django 内部处理逻辑中等效),但浏览器行为由 RFC 6265 严格定义:只有显式带前导点的 Cookie Domain 才触发子域名匹配。因此,实际生效的是你传给浏览器的 Set-Cookie: Domain= 字段值,而 Django 的 SESSION_COOKIE_DOMAIN 会原样写入该字段——故务必手动移除点号。
? 动态设置 Cookie Domain(按登录域名隔离)
若需支持用户在不同子域名(如 app.dev.fox.com 与 abc.dev.fox.com)独立登录且互不干扰,应根据 request.get_host() 动态设定 SESSION_COOKIE_DOMAIN。推荐在中间件中完成:
# middleware.py
from django.conf import settings
from django.utils.deprecation import MiddlewareMixin
class DynamicSessionDomainMiddleware(MiddlewareMixin):
def process_request(self, 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:
request.session.cookie_domain = host
else:
# 默认降级为 None(仅当前 host)
request.session.cookie_domain = None
然后在 settings.py 中注册中间件(置于 SessionMiddleware 之后):
MIDDLEWARE = [
# ... 其他中间件
'django.contrib.sessions.middleware.SessionMiddleware',
'myapp.middleware.DynamicSessionDomainMiddleware', # ← 关键位置
# ...
]
✅ 优势:每个请求的会话 Cookie 将被精准绑定到当前访问域名,彻底杜绝跨子域污染。
? 安全提示:务必对 host 进行白名单校验(如上例),禁止直接使用未过滤的 request.get_host(),否则可能引发 Cookie 注入攻击。
? 补充说明:Firebase Token 场景下的协同处理
你提到 Token 来自 Firebase Authentication。请注意:Firebase ID Token 本身是 JWT,不依赖 Cookie;但若你在后端验证该 Token 后创建 Django 会话,则上述 SESSION_COOKIE_DOMAIN 配置直接影响该会话的安全边界。建议同步检查:
- 前端调用 Firebase SDK 登录时,确保 signInWithPopup / signInWithRedirect 的 authDomain 与后端 Cookie Domain 一致;
- 若使用自定义域(如 auth.fox.com),需统一配置 SESSION_COOKIE_DOMAIN = 'auth.fox.com';
- 对于跨域请求(如前端在 app.dev.fox.com 调用 api.dev.fox.com 接口),还需配置 CSRF_COOKIE_DOMAIN 和 SESSION_COOKIE_SAMESITE = 'Lax' 或 'Strict' 以增强防护。
✅ 总结
| 目标 | 实现方式 |
|---|---|
| 禁止子域名共享 Cookie | SESSION_COOKIE_DOMAIN = 'exact.domain.com'(无前导点) |
| 动态适配登录域名 | 中间件 + request.session.cookie_domain = host(配合白名单) |
| 兼顾安全性与兼容性 | 校验 Host 头、设置 SameSite、分离认证与会话生命周期 |
正确配置 Cookie Domain 是构建可信多子域架构的基础一环。一次精准的字符串调整(去掉那个小小的 .),即可将安全隐患转化为强隔离保障。











