Django Web 应用程序安全性
保护用户数据是任何网站设计的重要组成部分。我们之前在文章Web 安全中解释了一些更常见的安全威胁——本文实际演示了 Django 内置保护如何处理这些威胁。
预备知识 | 阅读服务器端编程“网站安全”主题。完成 Django 教程主题,至少包括Django 教程第 9 部分:使用表单。 |
---|---|
目标 | 了解您需要做(或不需做)的主要事情,以保护您的 Django Web 应用程序。 |
概述
网站安全主题概述了服务器端设计中网站安全的含义,以及您应该防范的一些更常见威胁。该文章中的一个关键信息是,当 Web 应用程序信任来自浏览器的数据时,几乎所有攻击都会成功。
警告:您能学到的关于网站安全最重要的一课是永远不要信任来自浏览器的数据。这包括 URL 参数中的GET
请求数据、POST
数据、HTTP 标头和 Cookie、用户上传的文件等。始终检查并清理所有传入数据。始终假设最坏的情况。
对 Django 用户来说,好消息是许多更常见的威胁都由框架处理了!Django 中的安全(Django 文档)文章解释了 Django 的安全功能以及如何保护由 Django 支持的网站。
常见威胁/保护
本文不会重复 Django 文档,而是将在我们的 Django LocalLibrary 教程中演示一些安全功能。
跨站脚本 (XSS)
XSS 是一个术语,用于描述一类攻击,允许攻击者通过网站将客户端脚本注入其他用户的浏览器。这通常通过将恶意脚本存储在数据库中,然后检索并显示给其他用户来实现,或者通过让用户点击一个链接,导致攻击者的 JavaScript 在用户浏览器中执行。
Django 的模板系统通过转义 HTML 中“危险”的特定字符来保护您免受大多数 XSS 攻击。我们可以通过尝试使用我们在Django 教程第 9 部分:使用表单中设置的创建作者表单向我们的 LocalLibrary 网站注入一些 JavaScript 来演示这一点。
-
使用开发服务器启动网站(
python3 manage.py runserver
)。 -
在本地浏览器中打开网站并登录您的超级用户帐户。
-
导航到作者创建页面(其 URL 应该是:
http://127.0.0.1:8000/catalog/author/create/
)。 -
为新用户输入姓名和日期详细信息,然后将以下文本附加到姓氏字段:
<script>alert('Test alert');</script>
。注意:这是一个无害的脚本,如果执行,将在您的浏览器中显示一个警报框。如果在提交记录时显示警报,则该站点容易受到 XSS 威胁。
-
按提交保存记录。
-
保存作者后,它将显示如下。由于 XSS 保护,
alert()
不应运行。相反,脚本以纯文本显示。
如果您查看页面 HTML 源代码,您会看到脚本标签的危险字符已转换为无害的转义码等效项(例如,>
现在是>
)
<h1>
Author: Boon<script>alert('Test alert');</script>, David
(Boonie)
</h1>
使用 Django 模板可以保护您免受大多数 XSS 攻击。但是,可以关闭此保护,并且保护不会自动应用于通常不会由用户输入填充的所有标签(例如,表单字段中的help_text
通常不是用户提供的,因此 Django 不会转义这些值)。
XSS 攻击也可能源自其他不受信任的数据源,例如 Cookie、Web 服务或上传文件(只要数据在包含到页面中之前没有经过充分清理)。如果您要显示来自这些来源的数据,则可能需要添加自己的清理代码。
跨站请求伪造 (CSRF) 保护
CSRF 攻击允许恶意用户在其他用户不知情或未经同意的情况下,使用其凭据执行操作。例如,考虑一个黑客想要为我们的 LocalLibrary 创建更多作者的情况。
注意:显然我们的黑客不是为了钱!一个更有野心的黑客可以在其他网站上使用相同的方法执行更具破坏性的任务(例如,将钱转入他们自己的账户,等等)。
为了做到这一点,他们可能会创建一个像下面这样的 HTML 文件,其中包含一个作者创建表单(就像我们在上一节中使用的那个),该表单在文件加载后立即提交。然后他们会将文件发送给所有图书管理员,并建议他们打开文件(它包含一些无害的信息,真的!)。如果任何已登录的图书管理员打开了该文件,则该表单将以他们的凭据提交,并会创建一个新的作者。
<html lang="en">
<body onload="document.EvilForm.submit()">
<form
action="http://127.0.0.1:8000/catalog/author/create/"
method="post"
name="EvilForm">
<table>
<tr>
<th><label for="id_first_name">First name:</label></th>
<td>
<input
id="id_first_name"
maxlength="100"
name="first_name"
type="text"
value="Mad"
required />
</td>
</tr>
<tr>
<th><label for="id_last_name">Last name:</label></th>
<td>
<input
id="id_last_name"
maxlength="100"
name="last_name"
type="text"
value="Man"
required />
</td>
</tr>
<tr>
<th><label for="id_date_of_birth">Date of birth:</label></th>
<td>
<input id="id_date_of_birth" name="date_of_birth" type="text" />
</td>
</tr>
<tr>
<th><label for="id_date_of_death">Died:</label></th>
<td>
<input
id="id_date_of_death"
name="date_of_death"
type="text"
value="12/10/2016" />
</td>
</tr>
</table>
<input type="submit" value="Submit" />
</form>
</body>
</html>
运行开发 Web 服务器,并使用您的超级用户帐户登录。将上面的文本复制到一个文件中,然后在浏览器中打开它。您应该会收到一个 CSRF 错误,因为 Django 对此类事情有保护!
启用保护的方法是,您在表单定义中包含{% csrf_token %}
模板标签。然后,此令牌将像下面所示那样在您的 HTML 中呈现,其值对于当前浏览器上的用户是特定的。
<input
type="hidden"
name="csrfmiddlewaretoken"
value="0QRWHnYVg776y2l66mcvZqp8alrv4lb8S8lZ4ZJUWGZFA5VHrVfL2mpH29YZ39PW" />
Django 生成一个用户/浏览器特定的密钥,并将拒绝不包含该字段或包含用户/浏览器不正确字段值的表单。
要使用这种类型的攻击,黑客现在必须发现并包含特定目标用户的 CSRF 密钥。他们也不能使用“撒网”方法向所有图书管理员发送恶意文件,并希望其中一个会打开它,因为 CSRF 密钥是浏览器特定的。
Django 的 CSRF 保护默认开启。您应该始终在表单中使用{% csrf_token %}
模板标签,并对可能更改或添加数据到数据库的请求使用POST
。
其他保护
Django 还提供其他形式的保护(其中大部分难以演示或不特别有用)
- SQL 注入保护
-
SQL 注入漏洞使恶意用户能够在数据库上执行任意 SQL 代码,从而允许访问、修改或删除数据,而无论用户的权限如何。在几乎所有情况下,您都将使用 Django 的查询集/模型访问数据库,因此生成的 SQL 将由底层数据库驱动程序正确转义。如果您确实需要编写原始查询或自定义 SQL,那么您需要明确考虑防止 SQL 注入。
- 点击劫持保护
-
在此攻击中,恶意用户劫持了针对可见顶级站点的点击,并将其路由到其下方隐藏的页面。例如,此技术可能用于显示合法的银行站点,但在攻击者控制的不可见的
<iframe>
中捕获登录凭据。Django 包含 点击劫持 保护,形式为X-Frame-Options
中间件,在支持的浏览器中,它可以阻止站点在框架内呈现。 - 强制使用 TLS/HTTPS
-
可以在 Web 服务器上启用 TLS/HTTPS,以加密站点和浏览器之间的所有流量,包括否则将以纯文本形式发送的身份验证凭据(强烈建议启用 HTTPS)。如果启用了 HTTPS,Django 还提供了一些您可以使用的其他保护措施
SECURE_PROXY_SSL_HEADER
可用于检查内容是否安全,即使它来自非 HTTP 代理。SECURE_SSL_REDIRECT
用于将所有 HTTP 请求重定向到 HTTPS。- 使用HTTP 严格传输安全 (HSTS)。这是一个 HTTP 标头,它通知浏览器所有将来与特定站点的连接都应始终使用 HTTPS。结合将 HTTP 请求重定向到 HTTPS,此设置可确保在成功连接后始终使用 HTTPS。HSTS 可以通过
SECURE_HSTS_SECONDS
和SECURE_HSTS_INCLUDE_SUBDOMAINS
配置,也可以在 Web 服务器上配置。 - 通过将
SESSION_COOKIE_SECURE
和CSRF_COOKIE_SECURE
设置为True
来使用“安全”Cookie。这将确保 Cookie 仅通过 HTTPS 发送。
- 主机头验证
-
使用
ALLOWED_HOSTS
仅接受来自受信任主机的请求。
还有许多其他保护措施,以及上述机制使用的注意事项。虽然我们希望这能让您大致了解 Django 的功能,但您仍然应该阅读 Django 安全文档。
总结
Django 对许多常见威胁(包括 XSS 和 CSRF 攻击)具有有效的防护。在本文中,我们演示了 Django 在我们的 LocalLibrary 网站中如何处理这些特定威胁。我们还简要概述了一些其他保护措施。
这只是对网络安全的一次非常简短的探讨。我们强烈建议您阅读Django 中的安全以获得更深入的理解。
本模块关于 Django 的下一个也是最后一个步骤是完成评估任务。
另见
- Web 安全
- 实用安全实施指南
- Django 中的安全(Django 文档)