Django 开发中你不可不知的 7个Web 安全头

Web 是一个不断发展的平台,有很多向后兼容的问题。新的 web 安全实践通常来自于对存在缺陷的旧功能的认识。与其通过改变这些功能来破坏旧网站,还不如选择加入一些更安全的设置。你可以通过设置 HTTP 头来实现这一点。

Securityheaders.com 是一个由安全顾问 Scott Helme 运行的工具,它可以在这些安全头上创建一个报告。它为任何 URL 提供从 F 到 A+ 的评分,这是一种度量网站安全状况的简单方法。但是,像任何自动化报告一样,它需要人工解释报告的上下文。

(我也推荐 Mozilla Observatory 安全扫描器,但我不会在这里使用它,因为它的功能远远超过了安全头。)

举个例子,Yahoo在 securityheaders.com 上的得分是 A+ :

同时(在写这篇文章的时候) Google 的得分是 C:

本文是一个关于如何配置一个典型的 Django web 应用程序来获得 A+ 得分的指南。你可以击败谷歌,保护你的用户,给你的老板、客户或伙伴留下深刻印象!

我们将查看你需要设置的6个 HTTP 安全头信息来获得 A+ (在撰写本文时)分数。另外,我们还会提供一个额外的实验性的第7个安全头…

1. X-XSS-Protection

跨站点脚本攻击或 XSS 是一种攻击者可以用来将他们自己的代码注入到你的网站的跨站脚本。这可能会做一些恶意的事情,比如添加虚假内容或者监视你的用户窃取他们的密码。

由于 XSS 是网站上常见的一种缺陷,浏览器在某些情况下添加了检测和防止这种漏洞攻击的功能,并捆绑在"XSS Auditors"中。默认情况下,这些安全功能都是启用的,所以看起来像 XSS 攻击的一些脚本会被阻止,但是页面会继续工作。

将X-XSS-Protection HTTP 头设置为使用"块模式"以提供额外的安全性。这告诉浏览器完全屏蔽被检测到的 XSS 攻击的页面,以防它们包含其他不好的东西。例如,请参见 Scott Helme 的演示,其中 HTML 发送了一个 GET 参数并出现在被阻塞的页面上。

这提供了一点额外的保护,添加这个HTTP头是一个好主意。即使你的网站可以防御 XSS 攻击,如果它触发浏览器的 XSS auditor,攻击行为会被重构,以避免继续利用漏洞。

Django 内置了这个HTTP头,并且很容易激活。如果你没有设置该HTTP头,那么你在运行 manage.py check --deploy 时,会看到 security.W007警告。

启用说明:

·在你的设置文件中添加 SECURE_BROWSER_XSS_FILTER = True

请参阅 Django 文档中的更多内容,例如关于媒体文件的说明。

2. Strict-Transport-Security

HTTP Strict Transport Security 或 HSTS,是一种告诉浏览器只能通过 HTTPS 加载你的网站的 HTTP严格传输安全方案。一旦浏览器在一个网站上看到了标题,它就只会向该网站发出 HTTPS 请求。该HTTP头包含一个以秒为单位的最大使用时间,这限制了浏览器记忆此操作的时间。这可以防止中间人攻击或者 AITM 拦截 HTTP 请求并将恶意的内容注入你的网页中。

一般来说建议为Strict-Transport-Security HTTP头设置一个 max-age 值。除此之外,你还可以设置下面几个标志:

·includeSubDomains 包括你的域名的所有子域名

·一旦设置了这个标志,你就可以通过谷歌的预装载服务将你的域名提交到所有浏览器。在接受你的域名之后,每个浏览器的下一个版本将包括你的域名。

最近有一些 TLD,如.app 实现了自身的预加载,这意味着这些 TLD 只支持 HTTPS 站点。超级安全。

同样,这个头部是 Django 内置的。如果你没有设置 max-age 值你会看到 security.W004警告。如果你没有设置 includeSubDomains 标志 则会看到 security.W005警告,同样,如果你未设置 preload 标志,那么你将看到security.W021警告。

启用说明:

·SecurityMiddleware 的安装和设置同上

·将 SECURE_HSTS_SECONDS 设置为你想在头部指定的秒数

·(可选)设置SECURE_HSTS_INCLUDE_SUBDOMAINS 及SECURE_HSTS_PRELOAD 为True 激活他们各自的标志

这不是你可以简单启用的东西,特别是如果其他子域正在使用这些选项的话!只有当你拥有一个全新的域名时,它才会变得简单明了。Django 的 security.W004 甚至有如下说明:

…不小心启用 HSTS 可能会导致严重的、不可逆转的问题

如果过早激活它,就会阻止用户发出的合法的 HTTP 请求。浏览器会锁定这些用户,直到你删除标头和已经过去的 max-age 秒数。

因此,你应该慢慢提高 SECURE_HSTS_SECONDS,确保在每次设置完后检查有没有任何服务的中断。在较长的几天内的多个部署中进行此操作,等待用户的反馈。你可以从较小的秒数开始,比如30秒,然后慢慢增加到31536000秒(1年)。

添加标志取决于你的情况。如果设置为 1 从来没有什么意义,那就使用 SILENCED_SYSTEM_CHECKS 禁用各自的警告。

更多信息请参见 Django 的 HTTP Strict Transport Security 文档。

3. X-Content-Type-Options

如果服务器发送了错误的响应,浏览器会尝试猜测响应的内容类型,这个特性称为 MIME 嗅探。当浏览器猜测错误的内容类型时,就会事与愿违。例如,如果你的站点上用户上传的图像被解释为 HTML,那么这就会导致 XSS 漏洞的产生。

最初,每个浏览器都有不同的规则,但它们都是按照 WHATWG 规范对齐的。由于有很多规则,所以我们很难预测和测试!

设置 X-Content-Type-Options 头为 nosniff 禁用 MIME 嗅探(在大多数情况下)。因为一个构建良好的网站不需要这种行为,所以你应该总是使用 nosniff 设置这个头。

这个头也是构建在 Django 中的,如果你没有启用它,你会收到 security.W006 警告。

启用说明:

·SecurityMiddleware 的安装和设置同上

·在你的设置中将SECURE_CONTENT_TYPE_NOSNIFF 设置为 True

参见 X-Content-Type-Options Django 文档中的更多内容。

4. X-Frame-Options

点击劫持是一种攻击者欺骗你的用户点击你的网站上的东西的攻击技术。这通常是通过将你的站点嵌入到攻击者站点的

请看 Troy Hunt 的博客文章中的例子。它描述了一个银行应用程序,透明地放置在"Win an iPad"按钮前的一个框架中。当用户试图领取奖金时,他们实际上是在点击银行网站上的"转账"按钮。

有各种各样的技术,可以防止点击劫持,但最好的办法是添加 X-Frame-Options头。这使你可以禁用你的站点出现在

这个头也是 Django 中内置的。如果没有安装中间件,就会看到 security.W002警告; 如果没有设置最安全的选项 DENY,就会看到security.W019警告。

启用并阻止你的站点出现在

·在你的设置中将 X_FRAME_OPTIONS 设置为 DENY

有一些额外的功能可以允许指定的域名将使你的网站嵌入到

5. Referrer-Policy

Referer 头与用户来自的网站的 URL 进行通信。这对于分析非常有用,因为你可以通过记录这些值来发现你的网站的访问者来自哪里。

设置 Referrer-Policy 头允许我们告诉浏览器什么时候发送 Referrer 信息。

(注意: referrer 一词中间有两个"r"。最初的 HTTP 规范有一个错误,只有一个"r",没有人注意到,因此这个 HTTP头的拼写是 Referer。为了避免重复这个拼写错误,Referrer-Policy 的作者小心地加入了两个"r"。这更令人困惑。带一个"r"的"Referer"已经出现在维基词典中了,我认为我们应该坚持使用它。自行车棚本就应该是黄色的。)

这个头没有构建在 Django 中,但是你可以使用 Django-referrer-policy 软件包进行添加,这是由同为核心开发人员的 James Bennett 完成的。按照软件包文档中的说明添加其中间件和设置。

需要注意的是,这个 HTTP 头的"最安全"的值是 no-Referer ,这会破坏 Django 的 CSRF (参见 CSRF 文档中的"删除 Referer 头")。你可能不想这么做。

如果可以的话,我建议使用 same-origin,它只对相同域名的请求发送 Referer。这使得 CSRF 和内部分析能够在不泄漏 Referer 值到其他域名的情况下正常工作。

6. Content-Security-Policy

这是一个大问题。内容安全策略(Content Security Policy,CSP)是一种屏蔽某些内容的策略。这有助于阻止 XSS、点击劫持和其他类型的注入攻击。

默认情况下,浏览器允许网站从任何地方加载内容。这意味着如果攻击者成功地在你的网站上执行 XSS 攻击,他们可以嵌入来自互联网上任何地方的代码。CSP 是一组指令,用于定义允许列表,允许其他浏览器从这些允许列表中加载内容。这严格限制了此类攻击。

例如,从 MDN 文档中获取这个策略的内容如下:

这里有四个指令,用分号进行分隔。这告诉浏览器:

·默认情况下,只从当前域加载资源

·对于图片资源,浏览器则可以从任何域进行加载

·媒体资源只能从media1.com 及media2.com 进行加载 (而不是当前域名)

你可以在 Content-Security-Policy 标头中发送策略。

这个HTTP 安全头没有在 Django 中内置,但是可以使用 Mozilla 的 Django-csp 包进行设置。按照安装和配置指南进行操作。它包括一个中间件和许多设置来构建策略指令。

至于制定你们的政策,好吧,我确实说过这是一个大问题。CSP 规范中有许多不同的指令和选项,django-csp 使用了 24 种不同的设置。

我建议阅读 MDN 文档,并掌握其中的一些选项,但这里有一些指导方针。

新网站的设置

如果你在一个全新的网站上,没有加载任何外部资源,那么这种情况就很容易设置。你应该从限制性 CSP 开始,并在开发站点时启用这个 HTTP 头。

所有类型的外部资源都无法加载,当这种情况发生时,你会在浏览器的 开发者工具 控制台中看到错误。然后你可以调整你的设计或适当设置 CSP 。

你可以从 django-csp 的默认设置开始,内容只有 CSP_DEFAULT_SRC = ["'self'"]。这个默认设置阻碍大多数外部资源的加载。

或者你可以从一个更严格的 CSP 开始,例如 Google 的 Strict CSP Page 推荐的 CSP。这样可以更好地保护你的网站。

现有网站的设置

CSP 更难添加到现有的网站中,网站越大,任务越大。你应该迭代地完成这项工作。

第一步是做一个初始的 CSP。你可以使用上面的限制性建议之一,或者使用 CSP Toolkit 或 CSPIsAwesome 这样的工具进行更有根据的猜测。

然后,将其部署在仅报告模式中,可以通过设置 django-csp 的 CSP_REPORT_ONLY 和 CSP_REPORT_URI 来完成。你的用户的浏览器将检查但不强制执行策略,然后向你报告异常情况。这样的设置是很不错的,因为你不需要检查整个网站!

通过将 CSP_REPORT_ONLY 设置为 True 以及将 CSP_REPORT_URI设置为 webhook URL 来激活 django-csp 上的只读模式。这个 URL 将以 JSON 格式接收报告。你可以尝试自己接收报告,但我不推荐这样做。

相反,应该使用一个能够处理所有报告并将它们显示在一个漂亮的仪表板上的服务。我知道的两个做法分别是:

securityheaders.com 创建的名副其实的 report-uri.com

Sentry——用于调试服务器端错误的工具

一旦你有了这个报告,你可以迭代 CSP,直到你看到没有更多的异常请求。然后告诉浏览器通过禁用报告模式来强制执行策略。当你的站点发生变化或者受到 XSS 攻击时,报告仍然是有用的。

7. 额外的奖励——Feature-Policy

完成上面的 6 个头信息会让你在 securityheaders.com 上得到 A+ 的评价。这是最后一个额外的奖励标头,可以帮助你进一步保护你的网站,不过这个标头目前是实验性的。

功能策略是另一个策略,有点像 CSP,控制浏览器功能,如视频自动播放或网络摄像头访问。它允许你在你的站点或者

在撰写本文时,它还没有得到很好的支持。Chrome 是实现这一功能的主要浏览器,但它要求用户启用"实验性 web 功能"标志。这个标头的支持也在快速推进之中。也就是说,了解它并走在时代的前沿是件好事!

要在 Django 中启用它,可以使用 django-feature-policy 软件包(由衷地)。这需要另一个中间件并设置 FEATURE_POLICY。请参阅软件包的文档,以及 MDN 文档,了解每个特性的作用。

我建议完全禁用一些恼人的功能,如自动播放、摄像头、全屏、地理位置和麦克风(假设你的网站用不到这些功能)。这意味着你所嵌入的脚本,例如来自广告合作伙伴的脚本,不能用这些特性来骚扰你的用户。

虽然它不能保护很多用户,但是你可以开发带有"实验性 web 功能"标志的站点,以确保遵循这些最佳实践。当浏览器阻止某个功能时,开发者工具的控制台会显示日志消息。

由于这个标头是实验性的,如果你确实添加了它,那么请保持 django-feature-policy 是最新的。我正在定期更新它,以跟踪上游规范的更改。我最近发布了2.0.0,因为一些特性发生了变化(参见更新日志)。

总结

我希望这篇文章的内容能帮助你提升你的网络安全知识水平,并且你能找到将你的网站提升到 A+ 分数的时间!(或者至少以一种更明智的方式决定在哪个部分停止)

注:本文参考自medium.com/@ksarthak4ever

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20191006A0F5UG00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券