中间件¶
这篇文档解释了所有 Django 自带的中间件组件。关于如何使用它们以及如何编写自己的中间件,请参见 中间件使用指南。
可用的中间件¶
缓存中间件¶
-
class
UpdateCacheMiddleware
¶
-
class
FetchFromCacheMiddleware
¶
启用全站缓存。如果启用了这些功能,那么每一个 Django 驱动的页面都会在 CACHE_MIDDLEWARE_SECONDS
配置定义的时间内被缓存。参见 缓存文档。
“通用”中间件¶
-
class
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()
Changed in Django 3.2:增加了对
no_append_slash()
装饰器的支持。设置非流响应的
Content-Length
头。
-
CommonMiddleware.
response_redirect_class
¶
默认为 HttpResponsePermanentRedirect
。子类化 CommonMiddleware
,并重写该属性来定制中间件发出的重定向。
-
class
BrokenLinkEmailsMiddleware
¶
- 向
manager
发送失效链接通知邮件(参见 发送错误)。
GZip 中间件¶
-
class
GZipMiddleware
¶
警告
安全研究人员最近发现,当在网站上使用压缩技术(包括 GZipMiddleware
)时,网站可能会受到一些可能的攻击。在你的网站上使用 GZipMiddleware
之前,你应该仔细考虑你是否会受到这些攻击。如果你对你是否受到影响有 任何 怀疑,你应该避免使用 GZipMiddleware
。更多细节,请看 the BREACH paper (PDF) 和 breachattack.com 。
django.middleware.gzip.GZipMiddleware
为能理解 GZip 压缩的浏览器(所有现代浏览器)压缩内容。
这个中间件应该放在任何其他需要读取或写入响应体的中间件之前,这样压缩就会在之后发生。
如果以下任何一项为真,它将不会压缩内容:
- 内容主体长度小于 200 字节。
- 响应已经设置了
Content-Encoding
头。 - 请求(浏览器)没有发送包含
gzip
的Accept-Encoding
头。
如果响应有 ETag
头,则 ETag 会变得很弱,以符合 RFC 7232#section-2.1。
你可以使用 gzip_page()
装饰器对单个视图应用 GZip 压缩。
条件 GET 中间件¶
-
class
ConditionalGetMiddleware
¶
处理有条件的 GET 操作。如果响应没有 ETag
头,中间件会根据需要添加一个。如果响应有 ETag
或 Last-Modified
头,而请求有 If-None-Match
或 If-Modified-Since
,则响应被一个 HttpResponseNotModified
替换。
本地化中间件¶
-
class
LocaleMiddleware
¶
可以根据请求的数据选择语言。它为每个用户定制内容。请参阅 国际化文档。
-
LocaleMiddleware.
response_redirect_class
¶
默认为 HttpResponseRedirect
。子类化 LocaleMiddleware
并重写该属性,以自定义中间件发出的重定向。
安全中间件¶
警告
如果你的部署情况允许,通常让你的前端 Web 服务器执行“安全中间件”提供的功能是个好主意。这样一来,如果有一些请求不是由 Django 服务的(比如静态资源或用户上传的文件),它们将和对你的 Django 应用的请求有同样的保护。
-
class
SecurityMiddleware
¶
django.middleware.security.SecurityMiddleware
为请求/响应周期提供了若干安全增强功能。每一项都可以通过设置独立地启用或禁用。
SECURE_BROWSER_XSS_FILTER
SECURE_CONTENT_TYPE_NOSNIFF
SECURE_HSTS_INCLUDE_SUBDOMAINS
SECURE_HSTS_PRELOAD
SECURE_HSTS_SECONDS
SECURE_REDIRECT_EXEMPT
SECURE_REFERRER_POLICY
SECURE_SSL_HOST
SECURE_SSL_REDIRECT
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
头。
警告
HSTS 策略适用于你的整个域,而不仅仅是你设置响应头的 URL。因此,你应该只在你的整个域名只通过 HTTPS 服务时使用它。
适当尊重 HSTS 头的浏览器将拒绝允许用户绕过警告,并连接到使用过期、自签名或其他无效 SSL 证书的网站。如果你使用 HSTS,请确保你的证书处于良好状态,并保持这种状态!
注解
如果你部署在负载平衡器或反向代理服务器后面,而 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 服务的,就会发生降级。
警告
当你的网站通过 HTTPS 提供服务时, Django 的 CSRF 保护系统 需要 Referer
头存在,所以完全禁用 Referer
头会干扰 CSRF 保护。要想在保留 CSRF 保护的同时,获得禁用 Referer
头的大部分好处,可以考虑只启用同源引用。
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
- 指示浏览器发送完整的 URL,但只针对同源链接。对于跨源链接,将不发送 referrer。
strict-origin
- 指示浏览器只发送起源,而不是完整的 URL,并在协议降级时不发送 referrer。
strict-origin-when-cross-origin
- 当链接为同源且不发生协议降级时,指示浏览器发送完整的 URL;当链接为跨源且不发生协议降级时,只发送起源;当发生协议降级时,不发送 referrer。
unsafe-url
- 指示浏览器始终发送完整的 URL 作为 referrer。
未知政策值
当一个策略值被用户代理认为 未知 时,可以指定多个策略值以提供后备。最后一个被理解的指定值优先。为了支持这一点,可以在 SECURE_REFERRER_POLICY
中使用一个可迭代对象或逗号分隔的字符串。
X-Content-Type-Options: nosniff
¶
一些浏览器会试图猜测它们获取的资源的内容类型,覆盖 Content-Type
头。虽然这可以帮助显示配置不当的服务器的网站,但也会带来安全风险。
如果你的网站提供用户上传的文件,恶意用户可能会上传一个特制的文件,当你认为它是无害的东西时,该文件会被浏览器解释为 HTML 或 JavaScript。
为了防止浏览器猜测内容类型,并迫使它总是使用 Content-Type
头中提供的类型,你可以传递 X-Content-Type-Options: nosniff 头。 如果 SECURE_CONTENT_TYPE_NOSNIFF
设置为 True
,SecurityMiddleware
将对所有的响应进行这样的操作。
需要注意的是,在大多数部署情况下,Django 并不参与服务用户上传的文件,这个设置对你没有帮助。例如,如果你的 MEDIA_URL
是由你的前端 Web 服务器(nginx,Apache等)直接提供服务的,那么你会希望在那里设置这个头。另一方面,如果你使用 Django 来做一些事情,比如需要授权才能下载文件,而你又不能用你的 Web 服务器来设置头,那么这个设置就会很有用。
X-XSS-Protection: 1; mode=block
¶
一些浏览器有能力阻止看起来是 XSS 攻击 的内容。它们的工作原理是在页面的 GET 或 POST 参数中寻找 JavaScript 内容。如果 JavaScript 在服务器的响应中被重放,页面就会被阻止渲染,并显示一个错误页面。
X-XSS-Protection 头 用于控制 XSS 过滤器的操作。
要在浏览器中启用 XSS 过滤器,并强制其始终阻止可疑的 XSS 攻击,你可以通过 X-XSS-Protection: 1; mode=block
头。如果 SECURE_BROWSER_XSS_FILTER
设置为 True
,SecurityMiddleware
将对所有响应进行此操作。
警告
浏览器 XSS 过滤器是一种有用的防御措施,但不能完全依赖它。它不能检测所有的 XSS 攻击,而且不是所有的浏览器都支持头。确保你仍然 验证和消毒 所有输入,以防止 XSS 攻击。
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
AuthenticationMiddleware
¶
将代表当前登录的用户的 user
属性添加到每个传入的 HttpRequest
对象中。见 Web 请求中的验证。
-
class
RemoteUserMiddleware
¶
用于利用 Web 服务器提供的认证的中间件。详细使用方法请看 使用 REMOTE_USER 进行身份验证。
-
class
PersistentRemoteUserMiddleware
¶
当仅在登录页面启用时,利用 Web 服务器提供的认证的中间件。详细使用方法参见 仅在登录界面使用 REMOTE_USER。
CSRF 保护中间件¶
-
class
CsrfViewMiddleware
¶
通过在 POST 表单中添加隐藏的表单字段,并检查请求的正确值,增加对跨站点伪造请求的保护。请参阅 跨站点伪造请求保护文档。
中间件顺序¶
下面是关于各种 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
之后:使用会话存储。 -
SessionMiddleware
之后:可以使用基于会话的存储。 -
在任何修改
Vary
头的中间件之后:该头用于为缓存哈希键选取一个值。 -
应该是接近底部,因为这是一种最后的中间件。
-
应该是接近底部,因为这是一种最后的中间件。