中间件¶
这篇文档解释了所有 Django 自带的中间件组件。关于如何使用它们以及如何编写自己的中间件,请参见 中间件使用指南。
可用的中间件¶
缓存中间件¶
启用全站缓存。如果启用了这些功能,那么每一个 Django 驱动的页面都会在 CACHE_MIDDLEWARE_SECONDS 配置定义的时间内被缓存。参见 缓存文档。
“通用”中间件¶
- class CommonMiddleware[source]¶
- response_redirect_class¶
默认为
HttpResponsePermanentRedirect。子类化CommonMiddleware,并重写该属性来定制中间件发出的重定向。
为完美主义者增加了一些便利:
禁止
DISALLOWED_USER_AGENTS配置中的用户代理访问,它应该是一个编译的正则表达式对象列表。根据
APPEND_SLASH和PREPEND_WWW的配置进行 URL 重写。如果
APPEND_SLASH为True,并且初始的 URL 没有以斜线结尾,而且在 URLconf 中也没有找到,那么就会在最后附加一个斜线形成一个新的 URL。如果在 URLconf 中找到了这个新的 URL,那么 Django 会将请求重定向到这个新的 URL。否则,初始的 URL 就会被照常处理。例如,
foo.com/bar将被重定向到foo.com/bar/,如果你没有foo.com/bar的有效 URL 模式,但 有foo.com/bar/的有效模式。如果
PREPEND_WWW为True,缺乏前导“www. ”的 URL 将被重定向到带有前导“www. ”的同一 URL。这两个选项都是为了规范 URL。其理念是,每个 URL 应该存在于一个地方,而且只有一个地方。从技术上讲,URL
foo.com/bar与foo.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头。
向
manager发送失效链接通知邮件(参见 如何管理错误报告)。
GZip 中间件¶
- class GZipMiddleware[source]¶
- max_random_bytes¶
默认为 100。如果需要更改包含在压缩响应中的最大随机字节数,请子类化
GZipMiddleware并重写该属性。
Note
安全研究人员揭示了当在网站上使用压缩技术(包括 GZipMiddleware)时,该网站可能会暴露于多种可能的攻击。
为了减轻攻击风险,Django 实施了一种称为 Heal The Breach (HTB) 的技术。它在每个响应中添加了最多 100 字节(参见 max_random_bytes)的随机字节,以减弱攻击的效果。
有关更多详细信息,请参阅 BREACH 论文 (PDF)、breachattack.com 和 Heal The Breach (HTB) 论文。
django.middleware.gzip.GZipMiddleware 为能理解 GZip 压缩的浏览器(所有现代浏览器)压缩内容。
这个中间件应该放在任何其他需要读取或写入响应体的中间件之前,这样压缩就会在之后发生。
如果以下任何一项为真,它将不会压缩内容:
内容主体长度小于 200 字节。
响应已经设置了
Content-Encoding头。请求(浏览器)没有发送包含
gzip的Accept-Encoding头。
如果响应具有 ETag 标头,则会将 ETag 标记为弱标记,以符合 RFC 9110 Section 8.8.1。
You can apply GZip compression to individual views using the
gzip_page() decorator.
条件 GET 中间件¶
处理有条件的 GET 操作。如果响应没有 ETag 头,中间件会根据需要添加一个。如果响应有 ETag 或 Last-Modified 头,而请求有 If-None-Match 或 If-Modified-Since,则响应被一个 HttpResponseNotModified 替换。
You can handle conditional GET operations with individual views using the
conditional_page() decorator.
本地化中间件¶
- class LocaleMiddleware[source]¶
- response_redirect_class¶
默认为
HttpResponseRedirect。子类化LocaleMiddleware并重写该属性,以自定义中间件发出的重定向。
可以根据请求的数据选择语言。它为每个用户定制内容。请参阅 国际化文档。
消息中间件¶
启用基于 cookie 和会话的消息支持。参见 消息文档。
安全中间件¶
Warning
如果您的部署情况允许,通常是一个好主意让您的前端 Web 服务器执行由 SecurityMiddleware 提供的功能。这样,如果有不由 Django 处理的请求(如静态媒体或用户上传的文件),它们将具有与请求到您的 Django 应用程序相同的保护。
django.middleware.security.SecurityMiddleware 为请求/响应周期提供了若干安全增强功能。每一项都可以通过设置独立地启用或禁用。
HTTP 严格传输安全¶
对于只能通过 HTTPS 访问的网站,你可以通过设置 "Strict-Transport-Security" 头 来指示现代浏览器拒绝通过不安全的连接连接到你的域名(在给定的时间内)。这可以减少你受到一些 SSL 剥离中间人(MITM)的攻击。
如果你将 SECURE_HSTS_SECONDS 设置为一个非零的整数值,SecurityMiddleware 将为你在所有 HTTPS 响应中设置这个头。
启用 HSTS 时,建议首先使用一个小的测试值,例如,将 SECURE_HSTS_SECONDS = 3600 设置为一小时。每次 Web 浏览器看到来自您网站的 HSTS 标头时,它将拒绝在给定的时间段内与您的域名进行非安全通信(使用 HTTP)。一旦您确认您的网站上的所有资源都以安全方式提供(即 HSTS 没有引发任何问题),则建议增加此值,以便不经常访问的访问者也受到保护(常见的值是 31536000 秒,即 1 年)。
此外,如果你将 SECURE_HSTS_INCLUDE_SUBDOMAINS 设置为 True,SecurityMiddleware 将在 Strict-Transport-Security 头中添加 includeSubDomains 指令。建议这样做(假设所有的子域都只使用 HTTPS 服务),否则你的网站仍然可能通过不安全的连接到子域而受到攻击。
如果你希望将你的网站提交到 浏览器预加载列表 ,请将 SECURE_HSTS_PRELOAD 设置为 True。这样就会把 preload 指令附加到 Strict-Transport-Security 头。
Warning
HSTS 策略适用于你的整个域,而不仅仅是你设置响应头的 URL。因此,你应该只在你的整个域名只通过 HTTPS 服务时使用它。
适当尊重 HSTS 头的浏览器将拒绝允许用户绕过警告,并连接到使用过期、自签名或其他无效 SSL 证书的网站。如果你使用 HSTS,请确保你的证书处于良好状态,并保持这种状态!
Note
如果你部署在负载平衡器或反向代理服务器后面,而 Strict-Transport-Security 头没有被添加到你的响应中,这可能是因为 Django 没有意识到它是在一个安全的连接上;你可能需要设置 SECURE_PROXY_SSL_HEADER 设置。
Referrer 政策¶
浏览器使用 referer 头 作为向网站发送关于用户如何到达那里的信息的一种方式。当用户点击一个链接时,浏览器将发送链接页面的完整 URL 作为 referrer。虽然这对某些目的来说可能很有用——例如查明谁在链接到你的网站——但它也可能引起隐私问题,因为它告诉一个网站,一个用户正在访问另一个网站。
一些浏览器能够接受关于是否应该在用户点击链接时发送 HTTP Referer 头的提示;这种提示通过 Referrer-Policy 头 提供。这个头可以向浏览器建议三种行为中的任何一种:
完整 URL:在
Referer头中发送整个URL。例如,如果用户访问https://example.com/page.html,Referer头将包含"https://example.com/page.html"。仅起源:只发送 referrer 中的“起源”。起源由方案、主机和(可选)端口号组成。例如,如果用户访问的是
https://example.com/page.html,起源就是https://example.com/。无 referrer:完全不发送
Referer头。
有两种类型的情况,这个头可以告诉浏览器要注意:
同源与跨源:从
https://example.com/1.html到https://example.com/2.html的链接为同源链接。从https://example.com/page.html到https://not.example.com/page.html的链接为跨源链接。协议降级:如果包含链接的页面是通过 HTTPS 服务的,但被链接的页面不是通过 HTTPS 服务的,就会发生降级。
Warning
当您的网站通过 HTTPS 提供服务时,Django 的 CSRF 保护系统 需要存在 Referer 标头,因此完全禁用 Referer 标头将干扰 CSRF 保护。为了获得禁用 Referer 标头的大部分好处,同时保留 CSRF 保护,请考虑仅启用同源引用。
SecurityMiddleware 可以根据 SECURE_REFERRER_POLICY 设置,为你设置 Referrer-Policy 头(注意拼写:当用户点击链接时,浏览器会发送一个 Referer 头,但指示浏览器是否这样做的头是拼写为 Referrer-Policy)。该设置的有效值为:
no-referrer指示浏览器对在本网站上点击的链接不发送 referrer。
no-referrer-when-downgrade指示浏览器发送完整的 URL 作为 referrer,但只有在没有发生协议降级的情况下。
origin指示浏览器只发送起源,而不是完整的 URL 作为 referrer。
origin-when-cross-origin指示浏览器发送完整的 URL 作为同源链接的 referrer,而只发送起源给跨源链接。
same-origin Instructs the browser to send a full URL, but only for
same-origin links. No referrer will be sent for cross-origin links.
strict-origin Instructs the browser to send only the origin, not the full
URL, and to send no referrer when a protocol downgrade occurs.
strict-origin-when-cross-origin当链接为同源且不发生协议降级时,指示浏览器发送完整的 URL;当链接为跨源且不发生协议降级时,只发送起源;当发生协议降级时,不发送 referrer。
unsafe-url指示浏览器始终发送完整的 URL 作为 referrer。
未知政策值
当一个策略值被用户代理认为 未知 时,可以指定多个策略值以提供后备。最后一个被理解的指定值优先。为了支持这一点,可以在 SECURE_REFERRER_POLICY 中使用一个可迭代对象或逗号分隔的字符串。
跨域开启策略¶
一些浏览器可以通过根据 Cross-Origin Opener 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-origin或same-origin-allow-popups的设置。
X-Content-Type-Options: nosniff¶
一些浏览器会试图猜测它们获取的资源的内容类型,覆盖 Content-Type 头。虽然这可以帮助显示配置不当的服务器的网站,但也会带来安全风险。
如果你的网站提供用户上传的文件,恶意用户可能会上传一个特制的文件,当你认为它是无害的东西时,该文件会被浏览器解释为 HTML 或 JavaScript。
To prevent the browser from guessing the content type and force it to
always use the type provided in the Content-Type header, you can pass
the X-Content-Type-Options: nosniff header. SecurityMiddleware will
do this for all responses if the SECURE_CONTENT_TYPE_NOSNIFF setting
is True.
请注意,在大多数部署情况下,如果 Django 不涉及提供用户上传的文件,这个设置不会对您有所帮助。例如,如果您的 MEDIA_URL 直接由您的前端 Web 服务器(nginx、Apache 等)提供服务,那么您需要在那里设置此标头。另一方面,如果您正在使用 Django 来执行某些操作,比如要求授权以下载文件,并且无法在 Web 服务器中设置标头,那么这个设置将会有用。
SSL 重定向¶
如果你的网站同时提供 HTTP 和 HTTPS 连接,大多数用户最终会默认使用不安全的连接。为了达到最佳的安全性,你应该将所有的 HTTP 连接重定向到 HTTPS。
如果你将 SECURE_SSL_REDIRECT 设置为 True,SecurityMiddleware 将永久(HTTP 301)重定向所有 HTTP 连接到 HTTPS。
Note
出于性能方面的考虑,最好在 Django 之外,在前端负载均衡器或反向代理服务器(如 nginx )中做这些重定向。 SECURE_SSL_REDIRECT 是为了在部署情况下,这不是一个选项。
如果 SECURE_SSL_HOST 设置有一个值,所有的重定向将被发送到该主机,而不是最初要求的主机。
如果你的网站上有几个页面应该通过 HTTP 提供,而不是重定向到 HTTPS,你可以在 SECURE_REDIRECT_EXEMPT 设置中列出正则表达式来匹配这些 URL。
Note
如果你部署在负载均衡器或反向代理服务器后面,而 Django 似乎无法判断一个请求是否真的已经安全,你可能需要设置 SECURE_PROXY_SSL_HEADER 配置。
会话中间件¶
启用会话支持。参见 会话文档。
站点中间件¶
将代表当前站点的 site 属性添加到每个传入的 HttpRequest 对象中。参见 站点文档。
验证中间件¶
将 user 属性添加到每个传入的 HttpRequest 对象中,表示当前已登录的用户。请参阅 Web 请求中的身份验证。
- class LoginRequiredMiddleware[source]¶
子类化中间件并覆盖以下属性和方法以自定义未认证请求的行为。
- redirect_field_name¶
默认为
"next"。
- get_login_url()[source]¶
返回未认证请求将重定向到的 URL。此结果是
login_required()装饰器上设置的login_url``(如果不是 ``None),或settings.LOGIN_URL。
- get_redirect_field_name()[source]¶
返回包含用户成功登录后应重定向到的 URL 的查询参数的名称。此结果是
login_required()装饰器上设置的redirect_field_name``(如果不是 ``None),或redirect_field_name。如果返回None,则不会添加查询参数。
将所有未认证请求重定向到登录页面,除了使用 login_not_required() 排除的视图。登录页面默认为 settings.LOGIN_URL,但可以自定义。
通过将其添加到 MIDDLEWARE 设置中 之后 AuthenticationMiddleware 来启用此中间件:
MIDDLEWARE = [
"...",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.auth.middleware.LoginRequiredMiddleware",
"...",
]
使用 login_not_required() 使视图公开,允许未认证请求。例如:
from django.contrib.auth.decorators import login_not_required
@login_not_required
def contact_us(request): ...
使用 login_required() 装饰器自定义认证视图的登录 URL 或字段名称,分别设置 login_url 或 redirect_field_name。例如:
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import View
@login_required(login_url="/books/login/", redirect_field_name="redirect_to")
def book_dashboard(request): ...
@method_decorator(
login_required(login_url="/books/login/", redirect_field_name="redirect_to"),
name="dispatch",
)
class BookMetrics(View):
pass
确保你的登录视图不需要登录。
为了防止无限重定向,请确保你已 启用未认证请求 到你的登录视图。
用于利用 Web 服务器提供的身份验证的中间件。有关使用详细信息,请参阅 使用 REMOTE_USER 进行身份验证。
中间件用于在仅在登录页面启用时利用 Web 服务器提供的身份验证。有关使用详细信息,请参阅 仅在登录界面使用 REMOTE_USER。
CSRF 保护中间件¶
通过在 POST 表单中添加隐藏的表单字段,并检查请求的正确值,增加对跨站点伪造请求的保护。请参阅 跨站点伪造请求保护文档。
You can add Cross Site Request Forgery protection to individual views using the
csrf_protect() decorator.
X-Frame-Options 中间件¶
Content Security Policy middleware¶
Adds support for Content Security Policy (CSP), which helps mitigate risks such as Cross-Site Scripting (XSS) and data injection attacks by controlling the sources of content that can be loaded in the browser. See the 概况 documentation for details on configuring policies.
This middleware sets the following headers on the response depending on the available settings:
Content-Security-Policy, based onSECURE_CSP.Content-Security-Policy-Report-Only, based onSECURE_CSP_REPORT_ONLY.
中间件顺序¶
下面是关于各种 Django 中间件类的排序的一些提示:
-
如果你要开启 SSL 重定向,它应该排在列表的最前面,因为这样可以避免运行一堆其他不必要的中间件。
-
在修改
Vary头(SessionMiddleware、GZipMiddleware、LocaleMiddleware)之前。 -
在任何可能改变或使用响应体的中间件之前。
在
UpdateCacheMiddleware之后:修改Vary头。 -
在任何可能引发异常触发错误视图的中间件之前(如
PermissionDenied),如果你使用的是CSRF_USE_SESSIONS。在
UpdateCacheMiddleware之后:修改Vary头。 -
在任何可能改变响应的中间件之前(它设置
ETag头)。在
GZipMiddleware之后,这样它就不会在 gzip 压缩后的内容上计算ETag头。 -
最上面的一个,仅次于
SessionMiddleware(使用会话数据)和UpdateCacheMiddleware(修改Vary头)。 -
在任何可能改变响应的中间件之前(它设置
Content-Length头)。出现在CommonMiddleware之前并改变响应的中间件必须重置Content-Length。靠近顶部:当
APPEND_SLASH或PREPEND_WWW设置为True时,它会重定向。在
SessionMiddleware之后,如果你使用CSRF_USE_SESSIONS。 -
在任何假设 CSRF 攻击已经被处理的视图中间件之前。
在
RemoteUserMiddleware,或任何其他可能执行登录的认证中间件,从而旋转 CSRF 令牌,然后再向下调用中间件链。在
SessionMiddleware之后,如果你使用CSRF_USE_SESSIONS。 -
SessionMiddleware之后:使用会话存储。 -
在
AuthenticationMiddleware之后:使用用户对象。 -
SessionMiddleware之后:可以使用基于会话的存储。 -
在任何修改
Vary头的中间件之后:该头用于为缓存哈希键选取一个值。 ContentSecurityPolicyMiddlewareCan be placed near the bottom, but ensure any middleware that accesses csp_nonce is positioned after it, so the nonce is properly included in the response header.
-
应该是接近底部,因为这是一种最后的中间件。
-
应该是接近底部,因为这是一种最后的中间件。