django网站安全学习记录

CsrfMiddleware 的运行需要 Django 的会话框架。 (参阅第 14 章了解更多关于会话的内容。)如果你使用了自定义会话或者身份验证框架手动管理会话 cookies,该中间件将帮不上你的忙。

如果你的应用程序以某种非常规的方法创建 HTML 页面(例如:在 Javascript 的document.write语句中发送 HTML 片段),你可能会绕开了向表单添加隐藏字段的过滤器。 在此情况下,表单提交永远无法成功。 (这是因为在页面发送到客户端之前,CsrfMiddleware使用正则表达式来添加csrfmiddlewaretoken字段到你的HTML中,而正则表达式不能处理不规范的HTML。)如果你怀疑出现了这样的问题。使用你浏览器的查看源代码功能以确定csrfmiddlewaretoken是否插入到了表单中。

总结一下如何django防范CSRF

django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。

全局:

中间件 django.middleware.csrf.CsrfViewMiddleware

局部:

@csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。

@csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。

注意:from django.views.decorators.csrf import csrf_exempt,csrf_protect

默认setting文件中

MIDDLEWARE里的django.contrib.csrf.middleware.CsrfMiddleware是开启的

我们需要在视图函数中使用render传入request和模板,然后在html表单里面加上{% csrf_token %}即可开启csrf防御

 

Internet并不安全。

作为Web开发人员,我们有责任来对抗这些黑暗的力量。 每一个Web开发者都应该把安全看成是Web编程中的基础部分。 不幸的是,要实现安全是困难的。

Django试图减轻这种难度。 它被设计为自动帮你避免一些web开发新手(甚至是老手)经常会犯的错误。 尽管如此,需要弄清楚,Django如何保护我们,以及我们可以采取哪些重要的方法来使得我们的代码更加安全。

首先,一个重要的前提: 我们并不打算给出web安全的一个详尽的说明,因此我们也不会详细地解释每一个薄弱环节。 在这里,我们会给出Django所面临的安全问题的一个大概。

SQL注入

SQL注入 是一个很常见的形式,在SQL注入中,攻击者改变web网页的参数(例如 GET /POST 数据或者URL地址),加入一些其他的SQL片段。 未加处理的网站会将这些信息在后台数据库直接运行。

这种危险通常在由用户输入构造SQL语句时产生。 例如,假设我们要写一个函数,用来从通信录搜索页面收集一系列的联系信息。 为防止垃圾邮件发送器阅读系统中的email,我们将在提供email地址以前,首先强制用户输入用户名。

def user_contacts(request): user = request.GET['username'] sql = "SELECT * FROM user_contacts WHERE username = '%s';" % username # execute the SQL here...

备注

在这个例子中,以及在以下所有的“不要这样做”的例子里,我们都去除了大量的代码,避免这些函数可以正常工作。 我们可不想这些例子被拿出去使用。

尽管,一眼看上去,这一点都不危险,实际上却不尽然。

首先,我们对于保护email列表所采取的措施,遇到精心构造的查询语句就会失效。 想象一下,如果攻击者在查询框中输入 "' OR 'a'='a" 。 此时,查询的字符串会构造如下:

SELECT * FROM user_contacts WHERE username = '' OR 'a' = 'a';

由于我们允许不安全的SQL语句出现在字符串中,攻击者加入 OR 子句,使得每一行数据都被返回。

事实上,这是最温和的攻击方式。 如果攻击者提交了 "'; DELETE FROM user_contacts WHERE 'a' 'a'" ,我们最终将得到这样的查询:

SELECT * FROM user_contacts WHERE username = ''; DELETE FROM user_contacts WHERE 'a' = 'a';

哦!我们整个通信录名单去哪儿了? 我们整个通讯录会被立即删除

解决方案

尽管这个问题很阴险,并且有时很难发现,解决方法却很简单: 绝不信任用户提交的数据,并且在传递给SQL语句时,总是转义它。

Django的数据库API帮你做了。 它会根据你所使用的数据库服务器(例如PostSQL或者MySQL)的转换规则,自动转义特殊的SQL参数。

举个例子,在下面这个API调用中:

foo.get_list(bar__exact="' OR 1=1")

Django会自动进行转义,得到如下表达:

SELECT * FROM foos WHERE bar = '\' OR 1=1'

完全无害。

这被运用到了整个Django的数据库API中,只有一些例外:

  • 传给 extra() 方法的 where 参数。 (参考 附录 C。) 这个参数故意设计成可以接受原始的SQL。

  • 使用底层数据库API的查询。 (详见第十章)

以上列举的每一个示例都能够很容易的让您的应用得到保护。 在每一个示例中,为了避免字符串被篡改而使用 绑定参数 来代替。这样,本节开始的例子应该写成这样:

from django.db import connection def user_contacts(request): user = request.GET['username'] sql = "SELECT * FROM user_contacts WHERE username = %s" cursor = connection.cursor() cursor.execute(sql, [user]) # ... do something with the results

底层 execute 方法采用了一个SQL字符串作为其第二个参数,这个SQL字符串包含若干’%s’占位符,execute方法能够自动对传入列表中的参数进行转义和插入。 你应该用* always* 这种方式构造自定义的SQL。

不幸的是,您并不是在SQL中能够处处都使用绑定参数,绑定参数不能够作为标识符(如表或列名等)。 因此,如果您需要这样做—我是说—动态构建 POST 变量中的数据库表的列表的话,您需要在您的代码中来对这些数据库表的名字进行转义。 Django提供了一个函数, django.db.backend.quote_name ,这个函数能够根据当前数据库引用结构对这些标识符进行转义。

跨站点脚本 (XSS)

在Web应用中, 跨站点脚本 (XSS)有时在被渲染成HTML之前,不能恰当地对用户提交的内容进行转义。 这使得攻击者能够向你的网站页面插入通常以 <script> 标签形式的任意HTML代码。

攻击者通常利用XSS攻击来窃取cookie和会话信息,或者诱骗用户将其私密信息透漏给被人(又称 钓鱼 )。

这种类型的攻击能够采用多种不同的方式,并且拥有几乎无限的变体,因此我们还是只关注某个典型的例子吧。 让我们来想想这样一个极度简单的Hello World视图:

from django.http import HttpResponse def say_hello(request): name = request.GET.get('name', 'world') return HttpResponse('<h1>Hello, %s!</h1>' % name)

这个视图只是简单的从GET参数中读取姓名然后将姓名传递给hello.html模板。 因此,如果我们访问 http://example.com/hello/?name=Jacob ,被呈现的页面将会包含一以下这些:

<h1>Hello, Jacob!</h1>

但是,等等,如果我们访问 http://example.com/hello/?name=<i>Jacob</i> 时又会发生什么呢?

<h1>Hello, <i>Jacob</i>!</h1>

当然,一个攻击者不会使用<i>标签开始的类似代码,他可能会用任意内容去包含一个完整的HTML集来劫持您的页面。 这种类型的攻击已经运用于虚假银行站点以诱骗用户输入个人信息,事实上这就是一种劫持XSS的形式,用以使用户向攻击者提供他们的银行帐户信息。

如果您将这些数据保存在数据库中,然后将其显示在您的站点上,那么问题就变得更严重了。 例如,一旦MySpace被发现这样的特点而能够轻易的被XSS攻击,后果不堪设想。 某个用户向他的简介中插入JavaScript,使得您在访问他的简介页面时自动将其加为您的好友,这样在几天之内,这个人就能拥有上百万的好友。 在几天的时间里,他拥有了数以百万的朋友。

现在,这种后果听起来还不那么恶劣,但是您要清楚——这个攻击者正设法将  的代码而不是MySpace的代码运行在  的计算机上。 这显然违背了假定信任——所有运行在MySpace上的代码应该都是MySpace编写的,而事实上却不如此。

MySpace是极度幸运的,因为这些恶意代码并没有自动删除访问者的帐户,没有修改他们的密码,也并没有使整个站点一团糟,或者出现其他因为这个弱点而导致的其他噩梦。

解决方案

解决方案是简单的: 总是转义可能来自某个用户的任何内容。

为了防止这种情况,Django的模板系统自动转义所有的变量值。 让我们来看看如果我们使用模板系统重写我们的例子会发生什么

# views.py from django.shortcuts import render_to_response def say_hello(request): name = request.GET.get('name', 'world') return render_to_response('hello.html', {'name': name}) # hello.html <h1>Hello, {{ name }}!</h1>

这样,一个到“ http://example.com/hello/name=Jacob“ 的请求将导致下面的页面:

<h1>Hello, &lt;i&gt;Jacob&lt;/i&gt;!</h1>

我们在第四章涵盖了Django的自动转义,一起想办法将其关闭。 甚至,如果Django真的新增了这些特性,您也应该习惯性的问自己,一直以来,这些数据都来自于哪里呢? 没有哪个自动解决方案能够永远保护您的站点百分之百的不会受到XSS攻击。

邮件头部注入

邮件头部注入 :SQL注入的兄弟,是一种通过劫持发送邮件的Web表单的攻击方式。 攻击者能够利用这种技术来通过你的邮件服务器发送垃圾邮件。 在这种攻击面前,任何方式的来自Web表单数据的邮件头部构筑都是非常脆弱的。

让我们看看在我们许多网站中发现的这种攻击的形式。 通常这种攻击会向硬编码邮件地址发送一个消息,因此,第一眼看上去并不显得像面对垃圾邮件那么脆弱。

但是,大多数表单都允许用户输入自己的邮件主题(同时还有from地址,邮件体,有时还有部分其他字段)。 这个主题字段被用来构建邮件消息的主题头部。

如果那个邮件头部在构建邮件信息时没有被转义,那么攻击者可以提交类似 "hello\ncc:spamvictim@example.com" (这里的 "\n" 是换行符)的东西。 这有可能使得所构建的邮件头部变成:

To: hardcoded@example.com Subject: hello cc: spamvictim@example.com

就像SQL注入那样,如果我们信任了用户提供的主题行,那样同样也会允许他构建一个头部恶意集,他也就能够利用联系人表单来发送垃圾邮件。

解决方案

我们能够采用与阻止SQL注入相同的方式来阻止这种攻击: 总是校验或者转义用户提交的内容。

Django内建邮件功能(在 django.core.mail 中)根本不允许在用来构建邮件头部的字段中存在换行符(表单,收件地址,还有主题)。 如果您试图使用 django.core.mail.send_mail 来处理包含换行符的主题时,Django将会抛出BadHeaderError异常。

如果你没有使用Django内建邮件功能来发送邮件,那么你需要确保包含在邮件头部的换行符能够引发错误或者被去掉。 你或许想仔细阅读 django.core.mail 中的 SateMIMEText 类来看看Django是如何做到这一点的。

目录遍历

目录遍历 :是另外一种注入方式的攻击,在这种攻击中,恶意用户诱骗文件系统代码对Web服务器不应该访问的文件进行读取和/或写入操作。

例子可以是这样的,某个视图试图在没有仔细对文件进行防毒处理的情况下从磁盘上读取文件:

def dump_file(request): filename = request.GET["filename"] filename = os.path.join(BASE_PATH, filename) content = open(filename).read() # ...

尽管一眼看上去,视图通过 BASE_PATH (通过使用 os.path.join )限制了对于文件的访问,但如果攻击者使用了包含 .. (两个句号,父目录的一种简写形式)的文件名,她就能够访问到 BASE_PATH 目录结构以上的文件。对她来说,发现究竟使用几个点号只是时间问题,比如这样:../../../../../etc/passwd

任何不做适当转义地读取文件操作,都可能导致这样的问题。 允许  操作的视图同样容易发生问题,而且结果往往更加可怕。

这个问题的另一种表现形式,出现在根据URL和其他的请求信息动态地加载模块。 一个众所周知的例子来自于Ruby on Rails。 在2006年上半年之前,Rails使用类似于 http://example.com/person/poke/1 这样的URL直接加载模块和调用函数。 结果是,精心构造的URL,可以自动地调用任意的代码,包括数据库的清空脚本。

解决方案

如果你的代码需要根据用户的输入来读写文件,你就需要确保,攻击者不能访问你所禁止访问的目录。

备注

不用多说,你 永远 不要在编写可以读取任何位置上的文件的代码!

Django内置的静态内容视图是做转义的一个好的示例(在 django.views.static 中)。这是相关代码:

import os import posixpath # ...  path = posixpath.normpath(urllib.unquote(path)) newpath = '' for part in path.split('/'): if not part: # strip empty path components continue drive, part = os.path.splitdrive(part) head, part = os.path.split(part) if part in (os.curdir, os.pardir): # strip '.' and '..' in path continue newpath = os.path.join(newpath, part).replace('\\', '/')

Django不读取文件(除非你使用 static.serve 函数,但也受到了上面这段代码的保护),因此这种危险对于核心代码的影响就要小得多。

更进一步,URLconf抽象层的使用,意味着不经过你明确的指定,Django 决不会 装载代码。 通过创建一个URL来让Django装载没有在URLconf中出现的东西,是不可能发生的。

原文链接:https://www.cnblogs.com/lgh344902118/p/6955635.html

原创文章,作者:优速盾-小U,如若转载,请注明出处:https://www.cdnb.net/bbs/archives/17929

(0)
上一篇 2022年12月3日
下一篇 2022年12月3日

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

优速盾注册领取大礼包www.cdnb.net
/sitemap.xml