中间件

本文档解释了 Django 附带的所有中间件组件。有关如何使用它们以及如何编写自己的中间件的信息,请参阅中间件使用指南

可用中间件

缓存中间件

class UpdateCacheMiddleware
class FetchFromCacheMiddleware

启用站点范围缓存。如果启用这些缓存,每个由 Django 提供支持的页面都将被缓存,只要CACHE_MIDDLEWARE_SECONDS设置定义的时间。请参阅缓存文档

“通用”中间件

class CommonMiddleware

为完美主义者增加了一些便利功能

  • 禁止访问 DISALLOWED_USER_AGENTS 设置中的用户代理,该设置应为已编译的正则表达式对象列表。

  • 根据 APPEND_SLASHPREPEND_WWW 设置执行 URL 重写。

    如果 APPEND_SLASHTrue 且初始 URL 未以斜杠结尾,且在 URLconf 中未找到,则会通过在末尾追加斜杠来形成一个新的 URL。如果在 URLconf 中找到了此新 URL,则 Django 会将请求重定向到此新 URL。否则,将按常规处理初始 URL。

    例如,如果没有 foo.com/bar 的有效 URL 模式,但有 foo.com/bar/ 的有效模式,则 foo.com/bar 将被重定向到 foo.com/bar/

    如果 PREPEND_WWWTrue,则缺少前导“www.”的 URL 将被重定向到带有前导“www.”的相同 URL。

    这两个选项都旨在规范化 URL。其理念是每个 URL 应存在于一个且仅一个位置。从技术上讲,URL foo.com/barfoo.com/bar/ 是不同的——搜索引擎索引器会将它们视为独立的 URL——因此,最佳做法是规范化 URL。

    如有必要,可以使用 no_append_slash() 装饰器将各个视图排除在 APPEND_SLASH 行为之外

    from django.views.decorators.common import no_append_slash
    
    
    @no_append_slash
    def sensitive_fbv(request, *args, **kwargs):
        """View to be excluded from APPEND_SLASH."""
        return HttpResponse()
    
  • 为非流式响应设置 Content-Length 标头。

CommonMiddleware.response_redirect_class

默认为 HttpResponsePermanentRedirect。子类化 CommonMiddleware 并覆盖该属性以自定义中间件发出的重定向。

BrokenLinkEmailsMiddleware

GZip 中间件

GZipMiddleware
max_random_bytes

默认为 100。子类 GZipMiddleware 并覆盖属性以更改压缩响应中包含的最大随机字节数。

注意

安全研究人员发现,当在网站上使用压缩技术(包括 GZipMiddleware)时,该网站可能会受到多种可能的攻击。

为了减轻攻击,Django 实施了一种称为Heal The Breach (HTB) 的技术。它向每个响应添加多达 100 个字节(请参阅 max_random_bytes)的随机字节,以降低攻击的有效性。

有关更多详细信息,请参阅 BREACH 论文 (PDF)breachattack.comHeal The Breach (HTB) 论文

在 Django 4.2 中更改

添加了对 BREACH 攻击的缓解措施。

django.middleware.gzip.GZipMiddleware 为理解 GZip 压缩(所有现代浏览器)的浏览器压缩内容。

此中间件应置于需要读取或写入响应正文的任何其他中间件之前,以便之后进行压缩。

如果满足以下任何条件,它将不会压缩内容

  • 内容正文长度小于 200 个字节。
  • 响应已设置 Content-Encoding 标头。
  • 请求(浏览器)未发送包含 gzipAccept-Encoding 标头。

如果响应具有 ETag 头部,则会将 ETag 设为弱以符合 RFC 9110#section-8.8.1

你可以使用 gzip_page() 装饰器对各个视图应用 GZip 压缩。

条件 GET 中间件

class ConditionalGetMiddleware

处理条件 GET 操作。如果响应没有 ETag 头部,则中间件会在需要时添加一个。如果响应具有 ETagLast-Modified 头部,并且请求具有 If-None-MatchIf-Modified-Since,则响应会被 HttpResponseNotModified 替换。

区域设置中间件

class LocaleMiddleware

根据请求中的数据启用语言选择。它为每个用户定制内容。请参阅 国际化文档

LocaleMiddleware.response_redirect_class

默认为 HttpResponseRedirect。子类化 LocaleMiddleware 并覆盖属性以自定义中间件发出的重定向。

消息中间件

MessageMiddleware[源代码]

启用基于 Cookie 和会话的消息支持。请参阅 消息文档

安全中间件

警告

如果您的部署情况允许,通常建议让您的前端 Web 服务器执行 SecurityMiddleware 提供的功能。这样,如果 Django 无法处理请求(例如静态媒体或用户上传的文件),它们将与对 Django 应用程序的请求具有相同的保护措施。

SecurityMiddleware

django.middleware.security.SecurityMiddleware 为请求/响应周期提供多项安全增强功能。每个功能都可以通过设置独立启用或禁用。

HTTP 严格传输安全

对于仅应通过 HTTPS 访问的网站,您可以通过设置 “Strict-Transport-Security” 标头 来指示现代浏览器拒绝通过不安全的连接(在给定时间段内)连接到您的域名。这会降低您面临某些 SSL 剥离中间人 (MITM) 攻击的风险。

SecurityMiddleware 如果将 SECURE_HSTS_SECONDS 设置为非零整数,它将为所有 HTTPS 响应设置此标头。

启用 HSTS 时,最好先使用较小的值进行测试,例如,SECURE_HSTS_SECONDS = 3600 表示一小时。每次 Web 浏览器从您的网站看到 HSTS 标头时,它都会拒绝使用非安全方式(使用 HTTP)与您的域名进行通信,持续给定的时间段。一旦您确认网站上的所有资产都以安全方式提供(即 HSTS 没有破坏任何内容),最好增加此值,以便保护不常访问的访问者(31536000 秒,即 1 年,很常见)。

此外,如果您将 SECURE_HSTS_INCLUDE_SUBDOMAINS 设置为 TrueSecurityMiddlewareincludeSubDomains 指令添加到 Strict-Transport-Security 标头。建议这样做(假设所有子域名都仅使用 HTTPS 提供),否则您的网站仍可能通过与子域名的不安全连接而受到攻击。

如果您希望将您的网站提交到 浏览器预加载列表,请将 SECURE_HSTS_PRELOAD 设置为 True。这会将 preload 指令附加到 Strict-Transport-Security 标头。

警告

HSTS 策略适用于您的整个域名,而不仅仅是您设置标头的响应的 URL。因此,只有当您的整个域名仅通过 HTTPS 提供时,您才应该使用它。

正确遵守 HSTS 标头的浏览器将拒绝允许用户绕过警告并连接到具有已过期、自签名或其他无效 SSL 证书的网站。如果您使用 HSTS,请确保您的证书状态良好并保持这种状态!

注意

如果您部署在负载均衡器或反向代理服务器后面,并且 Strict-Transport-Security 标头未添加到您的响应中,这可能是因为 Django 无法识别它处于安全连接中;您可能需要设置 SECURE_PROXY_SSL_HEADER 设置。

引用者策略

浏览器使用 引用者标头 作为向网站发送有关用户如何到达该网站的信息的一种方式。当用户单击链接时,浏览器会将链接页面的完整 URL 作为引用者发送。虽然这对于某些目的(例如弄清楚谁链接到您的网站)很有用,但它也可能通过通知一个网站用户正在访问另一个网站而引起隐私问题。

一些浏览器能够接受有关当用户单击链接时是否应该发送 HTTP Referer 标头的提示;此提示通过 引用者策略标头 提供。此标头可以向浏览器建议三种行为

  • 完整 URL:在 Referer 标头中发送整个 URL。例如,如果用户访问 https://example.com/page.html,则 Referer 标头将包含 "https://example.com/page.html"
  • 仅来源:仅在引用者中发送“来源”。来源由方案、主机和(可选)端口号组成。例如,如果用户访问 https://example.com/page.html,则来源将为 https://example.com/
  • 无引荐来源:根本不发送 Referer 头部。

此头部可以告知浏览器注意两种类型的条件

  • 同源与跨源:从 https://example.com/1.htmlhttps://example.com/2.html 的链接是同源的。从 https://example.com/page.htmlhttps://not.example.com/page.html 的链接是跨源的。
  • 协议降级:如果包含链接的页面通过 HTTPS 提供,但被链接的页面未通过 HTTPS 提供,则会发生降级。

警告

当您的网站通过 HTTPS 提供时,Django 的 CSRF 保护系统 要求存在 Referer 头部,因此完全禁用 Referer 头部会干扰 CSRF 保护。为了在禁用 Referer 头部时获得大部分好处,同时保持 CSRF 保护,请考虑仅启用同源引荐来源。

SecurityMiddleware 可以根据 SECURE_REFERRER_POLICY 设置(注意拼写:当用户单击链接时,浏览器会发送 Referer 头部,但指示浏览器是否这样做的头部拼写为 Referrer-Policy)为您设置 Referrer-Policy 头部。此设置的有效值为

no-referrer
指示浏览器不发送此网站上单击的链接的引荐来源。
no-referrer-when-downgrade
指示浏览器发送完整的 URL 作为引荐来源,但仅在未发生协议降级时才发送。
origin
指示浏览器仅发送源,而不是完整 URL,作为引荐来源。
origin-when-cross-origin
指示浏览器将完整 URL 作为引荐来源发送到同源链接,而仅将源发送到跨源链接。
same-origin
指示浏览器发送完整的 URL,但仅适用于同源链接。不会为跨源链接发送引荐来源。
strict-origin
指示浏览器仅发送源,而不是完整 URL,并在发生协议降级时不发送引荐来源。
strict-origin-when-cross-origin
指示浏览器在链接为同源且未发生协议降级时发送完整 URL;在链接为跨源且未发生协议降级时仅发送源;在发生协议降级时不发送引荐来源。
unsafe-url
指示浏览器始终将完整 URL 作为引荐者发送。

未知策略值

如果用户代理不知道策略值,未知,则可以指定多个策略值来提供后备。最后指定的已理解值优先。为了支持这一点,可以使用可迭代或逗号分隔的字符串与 SECURE_REFERRER_POLICY

跨源开启者策略

一些浏览器能够根据 跨源开启者策略 (COOP) 标头值将顶级窗口与其他文档隔离,方法是将它们放入单独的浏览上下文组中。如果以这种方式隔离的文档打开跨源弹出窗口,则弹出窗口的 window.opener 属性将为 null。使用 COOP 隔离窗口是针对跨源攻击的纵深防御保护,特别是那些允许从加载到共享浏览上下文中提取数据(如 Spectre)的攻击。

SecurityMiddleware 可以根据 SECURE_CROSS_ORIGIN_OPENER_POLICY 设置,为您设置 Cross-Origin-Opener-Policy 标头。此设置的有效值为

same-origin
将浏览上下文专门隔离到同源文档。跨源文档不会加载到同一浏览上下文中。这是默认且最安全的选择。
same-origin-allow-popups
将浏览上下文隔离到同源文档或那些未设置 COOP 或通过设置 COOP 为 unsafe-none 来选择退出隔离的文档。
unsafe-none
允许将文档添加到其开启者的浏览上下文组,除非开启者本身的 COOP 为 same-originsame-origin-allow-popups

X-Content-Type-Options: nosniff

一些浏览器会尝试猜测它们获取的资产的内容类型,覆盖 Content-Type 标头。虽然这有助于显示服务器配置不当的网站,但它也可能构成安全风险。

如果您的网站提供用户上传的文件,恶意用户可以上传一个经过特殊设计的,当您期望它成为无害内容时,会被浏览器解释为 HTML 或 JavaScript 的文件。

要防止浏览器猜测内容类型并强制其始终使用 Content-Type 标头中提供的类型,您可以传递 X-Content-Type-Options: nosniff 标头。如果 SECURE_CONTENT_TYPE_NOSNIFF 设置为 TrueSecurityMiddleware 将对所有响应执行此操作。

请注意,在大多数 Django 不参与提供用户上传文件的情况中,此设置对您没有帮助。例如,如果您的 MEDIA_URL 由您的前端 Web 服务器(nginx、Apache 等)直接提供,那么您需要在那里设置此标头。另一方面,如果您使用 Django 执行诸如要求授权才能下载文件之类的操作,并且您无法使用 Web 服务器设置标头,此设置将非常有用。

SSL 重定向

如果您的网站同时提供 HTTP 和 HTTPS 连接,大多数用户最终默认使用不安全的连接。为了获得最佳安全性,您应该将所有 HTTP 连接重定向到 HTTPS。

如果您将 SECURE_SSL_REDIRECT 设置为 True,SecurityMiddleware 将永久(HTTP 301)将所有 HTTP 连接重定向到 HTTPS。

注意

出于性能原因,最好在 Django 外部,在前端负载均衡器或反向代理服务器(如 nginx)中执行这些重定向。 SECURE_SSL_REDIRECT 适用于无法选择此选项的情况。

如果 SECURE_SSL_HOST 设置有值,所有重定向都将发送到该主机,而不是最初请求的主机。

如果您的网站上有一些页面应该通过 HTTP 提供,而不是重定向到 HTTPS,您可以在 SECURE_REDIRECT_EXEMPT 设置中列出正则表达式以匹配这些 URL。

注意

如果您部署在负载均衡器或反向代理服务器后面,并且 Django 似乎无法判断请求实际上是否已经安全,您可能需要设置 SECURE_PROXY_SSL_HEADER 设置。

会话中间件

class SessionMiddleware

启用会话支持。请参阅 会话文档

站点中间件

class CurrentSiteMiddleware

向每个传入 HttpRequest 对象添加表示当前站点的 site 属性。请参阅 站点文档

身份验证中间件

class AuthenticationMiddleware

向每个传入 HttpRequest 对象添加表示当前登录用户的 user 属性。请参阅 Web 请求中的身份验证

class RemoteUserMiddleware

用于利用 Web 服务器提供的身份验证的中间件。有关使用详细信息,请参阅 如何使用 REMOTE_USER 进行身份验证

class PersistentRemoteUserMiddleware

仅在登录页面启用时用于利用 Web 服务器提供的身份验证的中间件。有关使用详细信息,请参阅 仅在登录页面上使用 REMOTE_USER

CSRF 保护中间件

CsrfViewMiddleware

通过向 POST 表单添加隐藏表单字段并检查请求是否具有正确的值,来增加对跨站点请求伪造的保护。请参见 跨站点请求伪造保护文档

X-Frame-Options 中间件

XFrameOptionsMiddleware[源代码]

通过 X-Frame-Options 头实现简单的 点击劫持保护

中间件排序

以下是有关各种 Django 中间件类排序的一些提示

  1. SecurityMiddleware

    如果您要启用 SSL 重定向,则它应该位于列表的顶部,因为这样可以避免运行大量其他不必要的中间件。

  2. UpdateCacheMiddleware

    在修改 Vary 头 (SessionMiddlewareGZipMiddlewareLocaleMiddleware) 的中间件之前。

  3. GZipMiddleware

    在任何可能更改或使用响应正文的中间件之前。

    UpdateCacheMiddleware 之后:修改 Vary 头。

  4. SessionMiddleware

    在任何可能引发异常以触发错误视图(例如 PermissionDenied)的中间件之前,如果您正在使用 CSRF_USE_SESSIONS

    UpdateCacheMiddleware 之后:修改 Vary 头。

  5. ConditionalGetMiddleware

    在任何可能更改响应的中间件之前(它设置 ETag 标头)。

    GZipMiddleware 之后,因此它不会在压缩内容上计算 ETag 标头。

  6. LocaleMiddleware

    最顶层的其中一个,在 SessionMiddleware(使用会话数据)和 UpdateCacheMiddleware(修改 Vary 标头)之后。

  7. CommonMiddleware

    在任何可能更改响应的中间件之前(它设置 Content-Length 标头)。在 CommonMiddleware 之前出现的并且更改响应的中间件必须重置 Content-Length

    接近顶部:当 APPEND_SLASHPREPEND_WWW 设置为 True 时,它会重定向。

    SessionMiddleware 之后,如果您正在使用 CSRF_USE_SESSIONS

  8. CsrfViewMiddleware

    在任何假定已处理 CSRF 攻击的视图中间件之前。

    RemoteUserMiddleware 或任何其他可能执行登录(因此在调用中间件链之前轮换 CSRF 令牌)的身份验证中间件之前。

    SessionMiddleware 之后,如果您正在使用 CSRF_USE_SESSIONS

  9. AuthenticationMiddleware

    SessionMiddleware 之后:使用会话存储。

  10. MessageMiddleware

    SessionMiddleware 之后:可以使用基于会话的存储。

  11. FetchFromCacheMiddleware

    在任何修改 Vary 标头的中间件之后:该标头用于为缓存哈希键选择一个值。

  12. FlatpageFallbackMiddleware

    应位于底部附近,因为它是一种最后手段类型的中间件。

  13. RedirectFallbackMiddleware

    应位于底部附近,因为它是一种最后手段类型的中间件。

返回顶部