Python开发-Django安全

在 Web 应用的发展中,安全是最重要主题,Django 提供了多种保护手段和机制。

一、安全概览

Django 的安全性
Django 安全特性的概述。包含保障那些用 Django 建立的网站的安全性建议。

防御跨站脚本攻击(XSS)

发起 XSS 攻击的人可以向其他用户的浏览器诸如客户端脚本。这种攻击通常由存储在数据库中的恶意脚本实现,这些脚本会被检索出来并显示给其他用户;或者通过其他用户点击会令攻击者的 JavaScript 脚本在浏览器中执行的链接来实现。然而,倘若在数据加载到页面前未经过彻底地清理,那么 XSS 攻击可以来自任何不可信任的数据源,比如 cookies 或者 Web 服务器。

Django 模板可以保护您免受大多数 XSS 攻击。但是了解它提供了怎样的保护,以及有什么限制是很重要的。

对于 HTML 来说,Django 模板中的 转义特殊字符 是尤其危险的。虽然它保护用户免受大多数恶意输入的攻击,但并非万无一失。

比如,出现下面这种情况就会保护失效:

<style class={{ var }}>...</style>

如果 var 被设置为 ‘class1 οnmοuseοver=javascript:func()’ ,将导致未经授权的 JavaScript 脚本执行,这取决于浏览器如何渲染有缺陷的HTML。(引用属性值可以解决这个问题)

与此不相上下的还有在使用带有自定义模板标签的 is_safe ,safe 模板标签,mark_safe,以及关闭自动转义时要特别小心。

此外,如果使用模板系统输出了除 HTML 之外的内容,可能会有完全独立的字符和单词需要转义。

您在将 HTML 储存到数据库中时也要非常小心,特别是在检索和显示 HTML 的时候。

防御跨站点请求伪造(CSRF)

发起 CSRF 攻击的人可以使用其他用户的证书执行操作,且是在其不知情或不同意的情况下。

Django 内置了保护措施来防御大多数 CSRF 攻击,您需要在合适的地方 授权并使用它 。但和多数缓解性技术一样,它是有局限性的。比如可以全局禁用 CSRF 模块或者特定的视图。请三思而后行。如果您的网页还有脱离您控制的子域,还将会有其他 限制 。

CSRF 保护机制 通过检查每一个 POST 请求中的密文来实现。这保证恶意用户不能”复现”一个表单并用 POST 提交到你的网页,并让一个已登录用户无意中提交该表单。恶意用户必须知道特定于用户的密文(使用 cookie)。

在部署 HTTPS 时,CsrfViewMiddleware 会检查 HTTP 报文的 referer 首部是否设置为同源的 URL(包括子域和端口)。因为 HTTPS 提供了额外的安全性,所有通过转发不安全连接请求并在支持的浏览器中使用 HSTS 来确保连接在可用的地方使用了 HTTPS ,这一点是很重要的。

除非绝对需要,否则对视图进行标记 csrf_exempt 装饰器时要极其慎重。

防御 SQL 注入

SQL 注入能让恶意用户能在数据库中执行任意 SQL 代码。这将导致记录被删除或泄露。

Django 的 querysets 在被参数化查询构建出来时就被保护而免于 SQL 注入。查询的 SQL 代码与查询的参数是分开定义的。参数可能来自用户从而不安全,因此它们由底层数据库引擎进行转义。

Django 也为开发者提供了书写 原始查询 或执行 自定义 sql 的权力。应当尽可能少地使用这些方法,并且您应该小心并准确地转义一切用户可控的参数。另外,在使用 extra() 和 RawSQL 时应当小心谨慎。

防御访问劫持

访问劫持能让恶意网页覆盖另一个网页。可能会有毫不知情的用户被骗入目标网页并执行意料之外的操作。

Django 包含 访问劫持保护 ,以 X-Frame-Options middleware 的形式在支持它的浏览器中阻止一个网页被渲染在 frame 的内部。可在每个视图的基础上禁用保护,也可配置发送的确切头部值。

对于任何不会被第三方网站嵌入 frame 的网页,或者只允许使用一小部分的网页来说,强烈建议使用中间件。

SSL/HTTPS

通过 HTTPS 部署您的网页是保障安全的最佳办法。没有它,恶意用户就可以在客户端和服务器之间嗅探验证资格或其他信息,在某些情况下 – 比如 主动 网络攻击者 – 会修改发送中的数据。

如果您想得到 HTTPS 的保护,且已经在您的服务器上启用了,下面还有一些额外的步骤需要执行:

如有必要,设置 SECURE_PROXY_SSL_HEADER,确保您已经彻底的了解了它的警告提示。如果不这么做,将会导致 CSRF 漏洞,如果操作不正确,也是非常危险的。

设置 SECURE_SSL_REDIRECT 为 True,这样 HTTP 的请求就会被重定向到 HTTPS。

请注意 SECURE_PROXY_SSL_HEADER 下的警告。对于反向代理,设置主服务器去执行重定向到 HTTPS 会更简单安全。

使用 ‘secure’ cookies。

如果浏览器使用默认的 HTTP 来实现初始连接,可能会导致已有的 cookies 泄露。因此,您应当将 CSRF_COOKIE_SECURE 和 CSRF_COOKIE_SECURE 设置为 True。这样浏览器就会仅用 HTTPS 连接来发送 cookies。注意,这会使得 sessions 不能再通过 HTTP 工作,且 CSRF 防御机制将会阻止任何通过 HTTP 接收到的 POST 数据(当然把所有 HTTP 都弄成 HTTPS 是最好的)。

使用 HTTP 严格传输安全 (HSTS)

HSTS 是一个 HTTP 头部,它使得浏览器总是使用 HTTPS 来连接到某特定网页。结合转换 HTTP 到 HTTPS 的方法,一旦成功建立一个连接,就能保证之后的连接总受到 SSL 提供的额外安全保证。HSTS 要么在 Web 服务器上配置,要么通过 SECURE_HSTS_SECONDS, SECURE_HSTS_INCLUDE_SUBDOMAINS,以及 SECURE_HSTS_PRELOAD 来进行配置。

Host 头部验证

在某些情况下,Django 使用客户端提供的 Host 头部来构造 URLs。这些值虽被清理以阻止跨站脚本攻击,但伪造 Host 值还是可以用于跨站请求伪造,缓存毒化攻击,以及电子邮件中的有毒链接。

因为即使看起来安全的服务器配置也容易受到假的 Host 头部信息的影响,Django 依靠定义在 django.http.HttpRequest.get_host() 方法中的 ALLOWED_HOSTS 来验证 Host 头部。

这些验证仅通过 get_host() 来实现;如果您的代码直接从 request.META 得到 Host 头部,您就绕过了这种安全保护机制。

二、在 Django 中披露的安全问题

安全问题档案

Django 的开发团队致力于负责任地报告和披露与安全相关的问题,正如 Django 的安全政策 所概述的那样。

作为该承诺的一部分,我们保留了以下已修复和披露的历史问题清单。对于每个问题,下面的列表包括日期、简要描述、CVE 标识符 (如果适用)、受影响版本的列表、到完整披露的链接以及到适当补丁的链接。

一些重要的注意事项适用于这些信息:

受影响的版本列表只包括那些在披露时有稳定的、安全支持的版本的 Django。这意味着旧版本(其安全支持已经过期)和在披露时处于发布前(alpha/beta/RC)状态的版本可能会受到影响,但没有被列出。
Django 项目有时会发布安全公告,指出潜在的安全问题,这些问题可能是由于配置不当或 Django 本身以外的其他问题造成的。有些安全公告已经收到了 CVE,在这种情况下,它们会被列在这里,但由于它们没有附带的补丁或版本,所以只会列出描述、披露和 CVE。
Django 的安全流程下的问题
所有的安全问题都已经在 Django 的安全进程的版本下处理。这些版本列举如下。

December 7, 2021 - CVE-2021-44420
Potential bypass of an upstream access control based on URL paths. Full description

受影响的版本

  • Django 3.2 (patch)
  • Django 3.1 (patch)
  • Django 2.2 (patch)

三、点击劫持保护

点击劫持保护

点击劫持中间件和装饰器提供易于使用的保护,以防止 点击劫持 。 当恶意网站欺骗用户点击另一个网站的隐藏元素时,就会发生这种类型的攻击,该元素已被加载到一个隐藏的框架或 iframe 中。

点击劫持的一个例子

假设一家在线商店有一个页面,登录的用户可以点击”立即购买”来购买商品。用户为了方便,选择了保持登录商店。攻击者网站可能会在自己的一个页面上创建一个”I Like Ponies”按钮,并在一个透明的 iframe 中加载商店的页面,使”立即购买”按钮无形中覆盖在”I Like Ponies”按钮上。如果用户访问攻击者的网站,点击”I Like Ponies”将导致无意中点击”立即购买”按钮,并在不知情的情况下购买该商品。

防止点击劫持

现代浏览器尊重 X-Frame-Options HTTP 头,它表明是否允许在框架或 iframe 中加载资源。如果响应包含值为 SAMEORIGIN 的头,那么只有当请求来自同一个网站时,浏览器才会在框架中加载资源。如果头被设置为 DENY,那么无论请求是由哪个网站发出的,浏览器都会阻止资源在框架中加载。

Django 提供了一些方法来在你的网站的响应中包含这个头:

一个在所有响应中设置头的中间件。
一组可用于覆盖中间件或仅为某些视图设置头的视图装饰器。
X-Frame-Options HTTP 头只有在响应中还没有出现的情况下,才会被中间件或视图装饰者设置。

四、跨站请求伪造 CSRF 保护

跨站请求伪造保护

CSRF 中间件和模板标签提供了易于使用的保护,防止 跨站请求伪造 。 当一个恶意网站包含一个链接、一个表单按钮或一些 JavaScript,目的是在你的网站上执行一些操作,使用在浏览器中访问恶意网站的登录用户的凭证时,就会发生这种类型的攻击。 此外,还包括一种相关的攻击类型,”登录 CSRF”,即攻击网站欺骗用户的浏览器使用他人的凭证登录网站。

对 CSRF 攻击的第一道防线是确保 GET 请求(和其他”安全”方法,如 RFC 7231#section-4.2.1 所定义的)没有副作用。通过”不安全”方法的请求,如 POST、PUT 和 DELETE,则可以通过以下步骤来保护。

如何使用它
要在你的视图中利用 CSRF 保护,请遵循以下步骤:

CSRF 中间件默认在 MIDDLEWARE 配置中被激活。如果你覆盖了这个配置,请记住 ‘django.middleware.csrf.CsrfViewMiddleware’ 应该排在任何假设 CSRF 攻击已经被处理的视图中间件之前。

如果你禁用了它,这并不推荐,你可以使用 csrf_protect() 对你想要保护的特定视图进行保护(见下文)。

在任何使用 POST 表单的模板中,如果表单是针对内部 URL 的,请在 元素中使用 csrf_token 标签,例如:

<form method="post">{% csrf_token %}

对于以外部 URL 为目标的 POST 表单,不应该这样做,因为这会导致 CSRF 令牌泄露,从而导致漏洞。

在相应的视图函数中,确保 RequestContext 用于渲染响应,这样 {% csrf_token %} 才能正常工作。如果你使用的是 render() 函数、通用视图或 contrib 应用程序,你已经被覆盖了,因为这些都使用 RequestContext。

AJAX

虽然上述方法可以用于 AJAX POST 请求,但它有一些不便之处:你必须记住在每个 POST 请求中都要把 CSRF 令牌作为 POST 数据传递进来。出于这个原因,有一种替代方法:在每个 XMLHttpRequest 上,设置一个自定义的 X-CSRFToken 头(由 CSRF_HEADER_NAME 设置指定)为 CSRF 标记的值。这通常比较容易,因为许多 JavaScript 框架提供了钩子,允许在每个请求中设置头。

首先,你必须获得 CSRF 令牌。如何做取决于 CSRF_USE_SESSIONS 和 CSRF_COOKIE_HTTPONLY 配置是否启用。

当 CSRF_USE_SESSIONS 和 CSRF_COOKIE_HTTPONLY 为 False 时获取令牌¶
推荐的令牌来源是 csrftoken cookie,如果你已经为你的视图启用了上文所述的 CSRF 保护,则会设置该 cookie。

CSRF 令牌 cookie 默认命名为 csrftoken,但你可以通过 CSRF_COOKIE_NAME 配置来控制 cookie 的名称。

你可以通过这样的方式获得令牌:

function getCookie(name) {
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        const cookies = document.cookie.split(';');
        for (let i = 0; i < cookies.length; i++) {
            const cookie = cookies[i].trim();
            // Does this cookie string begin with the name we want?

            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
const csrftoken = getCookie('csrftoken');

五、登录加密

加密签名

Web 应用程序安全的黄金法则是永远不要信任来自不受信任来源的数据。有时,通过不受信任的媒介传递数据是有用的。经过加密签名的值可以通过不受信任的渠道传递,因为知道任何篡改都会被检测到。

Django 提供了用于签署值的低级 API 和用于设置和读取已签名 cookie 的高级 API,这是 Web 应用程序中签名的最常见用法之一。

你可能还发现签名对以下方面很有用:

生成”找回我的账户”URL 以发送给丢失密码的用户。
确认存储在表单隐藏字段中的数据未被篡改。
生成一次性的秘密 URL,允许临时访问受保护的资源,例如用户付费下载的文件。

保护 SECRET_KEY

当你使用 startproject 创建一个新的Django项目时,settings.py 文件会自动生成,并随机得到一个 SECRET_KEY 值。这个值是保证签名数据安全的关键——你必须保证这个值的安全,否则攻击者可以用它来生成自己的签名值。

使用低级 API

Django 的签名方法位于 django.core.signing 模块中。要签署一个值,首先要实例化一个 Signer 实例:

>>> from django.core.signing import Signer
>>> signer = Signer()
>>> value = signer.sign('My string')
>>> value
'My string:GdMGD6HNQ_qdgxYP8yBZAdAIV1w'

签名被附加在字符串的结尾,在冒号之后。你可以使用 unsign 方法检索原始值:

>>> original = signer.unsign(value)
>>> original
'My string'

如果你将非字符串值传递给 sign,该值将在被签署前被强制变成字符串,并且 unsign 结果将返回此字符串值:

>>> signed = signer.sign(2.5)
>>> original = signer.unsign(signed)
>>> original
'2.5'
If you wish to protect a list, tuple, or dictionary you can do so using the sign_object() and unsign_object() methods:

>>> signed_obj = signer.sign_object({'message': 'Hello!'})
>>> signed_obj
'eyJtZXNzYWdlIjoiSGVsbG8hIn0:Xdc-mOFDjs22KsQAqfVfi8PQSPdo3ckWJxPWwQOFhR4'
>>> obj = signer.unsign_object(signed_obj)
>>> obj
{'message': 'Hello!'}

六、安全中间件

安全中间件

如果你的部署情况允许,通常让你的前端 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 头。

Original: https://blog.csdn.net/huidaoli/article/details/121609683
Author: huidaoli
Title: Python开发-Django安全

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/735570/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球