`
gaoyu
  • 浏览: 274696 次
  • 来自: 云南大理
社区版块
存档分类
最新评论

关于数据的 安全 问题

阅读更多
文章出处:http://djangobook.py3k.cn/chapter19/

第十九章 安全

Internet并不安全。
现如今,每天都会出现新的安全问题。我们目睹过病毒飞速地蔓延,大量被控制的肉鸡作为武器来攻击其他人,与垃圾邮件的永无止境的军备竞赛,以及许许多多站点被黑的报告。
作为web开发人员,我们有责任来对抗这些黑暗的力量。每一个web开发者都应该把安全看成是web编程中的基础部分。不幸的是,要实现安全是困难的。攻击者只需要找到一个微小的薄弱环节,而防守方却要保护得面面俱到。
Django试图减轻这种难度。它被设计为自动帮你避免一些web开发新手(甚至是老手)经常会犯的错误。尽管如此,需要弄清楚,Django如何保护我们,以及我们可以采取哪些重要的方法来使得我们的代码更加安全。
首先,一个重要的前提:我们并不打算给出web安全的一个详尽的说明,因此我们也不会详细地解释每一个薄弱环节。在这里,我们会给出Django所面临的安全问题的一个大概。
Web安全现状如果你从这章中只学到了一件事情,那么它会是:
在任何条件下都不要相信浏览器端提交的数据。
你从不会知道HTTP连接的另一端会是谁。可能是一个正常的用户,但是同样可能是一个寻找漏洞的邪恶的骇客。
从浏览器传过来的任何性质的数据,都需要近乎狂热地接受检查。这包括用户数据(比如web表单提交的内容)和带外数据(比如,HTTP头、cookies以及其他信息)。要修改那些浏览器自动添加的元数据,是一件很容易的事。
在这一章所提到的所有的安全隐患都直接源自对传入数据的信任,并且在使用前不加处理。你需要不断地问自己,这些数据从何而来。
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方法能够自动对传入列表中的参数进行转义和插入。
不幸的是,您并不是在SQL中能够处处都使用绑定参数,绑定参数不能够作为标识符(如表或列名等)。因此,如果您需要这样做—我是说—动态构建 POST 变量中的数据库表的列表的话,您需要在您的代码中来对这些数据库表的名字进行转义。Django提供了一个函数, django.db.backend.quote_name ,这个函数能够根据当前数据库引用结构对这些标识符进行转义。
跨站点脚本 (XSS)在Web应用中, 跨站点脚本 (XSS)有时在被渲染成HTML之前,不能恰当地对用户提交的内容进行转义。这使得攻击者能够向你的网站页面插入通常以 <script> 标签形式的任意HTML代码。
攻击者通常利用XSS攻击来窃取cookie和会话信息,或者诱骗用户将其私密信息透漏给别人(又称 钓鱼 )。
这种类型的攻击能够采用多种不同的方式,并且拥有几乎无限的变体,因此我们还是只关注某个典型的例子吧。让我们来想想这样一个极度简单的Hello World视图:
def say_hello(request):
    name = request.GET.get('name', 'world')
    return render_to_response("hello.html", {"name" : name})
这个视图只是简单的从GET参数中读取姓名然后将姓名传递给hello.html模板。我们可能会为这个视图编写如下所示的模板:
<h1>Hello, {{ name }}!</h1>
因此,如果我们访问 http://example.com/hello/?name=Jacob ,被呈现的页面将会包含一以下这些:1
<h1>Hello, Jacob!</h1>
但是,等等,如果我们访问 http://example.com/hello/?name=<i>Jacob</i> 时又会发生什么呢?然后我们会得到:1
<h1>Hello, <i>Jacob</i>!</h1>
当然,一个攻击者不会使用<i>标签开始的类似代码,他可能会用任意内容去包含一个完整的HTML集来劫持您的页面。这种类型的攻击已经运用于虚假银行站点以诱骗用户输入个人信息,事实上这就是一种劫持XSS的形式,用以使用户向攻击者提供他们的银行帐户信息。
如果您将这些数据保存在数据库中,然后将其显示在您的站点上,那么问题就变得更严重了。例如,一旦MySpace被发现这样的特点而能够轻易的被XSS攻击,后果不堪设想。某个用户向他的简介中插入JavaScript,使得您在访问他的简介页面时自动将其加为您的好友,这样在几天之内,这个人就能拥有上百万的好友。
现在,这种后果听起来还不那么恶劣,但是您要清楚——这个攻击者正设法将 他 的代码而不是MySpace的代码运行在 您 的计算机上。这显然违背了假定信任——所有运行在MySpace上的代码应该都是MySpace编写的,而事实上却不如此。
MySpace是极度幸运的,因为这些恶意代码并没有自动删除访问者的帐户,没有修改他们的密码,也并没有使整个站点一团糟,或者出现其他因为这个弱点而导致的其他噩梦。
解决方案解决方案是简单的:总是转义可能来自某个用户的任何内容。如果我们像如下代码来简单的重写我们的模板:
<h1>Hello, {{ name|escape }}!</h1>
这样一来就不总是那么的弱不禁风了。在您的站点上显示用户提交的内容时,您应该总是使用escape标签(或其他类似的东西)。
为什么Django没有为您完成这些呢?
在Django开发者邮件列表中,将Django修改成为能够自动转义在模板中显示的所有变量是一个老话题了。
迄今为止,Django模板都避免这种行为,因为这样就略微改变了Django应该相对直接的行为(展现变量)。这是一个棘手的问题,在评估上的一种艰难折中。增加隐藏隐式行为违反了Django的核心理念(对于Pythons也是如此),但是安全性是同等的重要。
所有这一切都表明,在将来某个适当的时机,Django会开发出某些形式的自动转义(或者很大程度上的自动转义)。在Django特性最新消息中查找正式官方文档是一个不错的主意,那里的东西总是要比本书中陈述的要更新的多,特别是打印版本。
甚至,如果Django真的新增了这些特性,您也应该习惯性的问自己,一直以来,这些数据都来自于哪里呢?没有哪个自动解决方案能够永远保护您的站点百分之百的不会受到XSS攻击。
伪造跨站点请求伪造跨站点请求(CSRF)发生在当某个恶意Web站点诱骗用户不知不觉的从一个信任站点下载某个URL之时,这个信任站点已经被通过信任验证,因此恶意站点就利用了这个被信任状态。
Django拥有内建工具来防止这种攻击。这种攻击的介绍和该内建工具都在第14章中进行进一步的阐述。
会话伪造/劫持这不是某个特定的攻击,而是对用户会话数据的通用类攻击。这种攻击可以采取多种形式:
中间人 攻击:在这种攻击中攻击者在监听有线(或者无线)网络上的会话数据。
伪造会话 :攻击者利用会话ID(可能是通过中间人攻击来获得)将自己伪装成另一个用户。
这两种攻击的一个例子可以是在一间咖啡店里的某个攻击者利用店的无线网络来捕获某个会话cookie,然后她就可以利用那个cookie来假冒原始用户。
伪造cookie :就是指某个攻击者覆盖了在某个cookie中本应该是只读的数据。第12章详细地解释了cookie的工作原理,cookie的一个显著特点就是浏览者和恶意用户想要背着您做些修改,是一件很稀松平常的事情。
Web站点以 IsLoggedIn=1 或者 LoggedInAsUser=jacob 这样的方式来保存cookie由来已久,使用这样的cookie是再简单不过的了。
但是,从更加细微的层面来看,信任存储在cookie中的任何东西都从来不是一个好主意,因为您从来不知道多少人已经对它一清二楚。
会话滞留 :攻击者诱骗用户设置或者重设置该用户的会话ID。
例如,PHP允许在URL(如 http://example.com/?PHPSESSID=fa90197ca25f6ab40bb1374c510d7a32 等)中传递会话标识符。攻击者诱骗用户点击某个带有硬编码会话ID的链接就会导致该用户恢复那个会话。
会话滞留已经运用在钓鱼攻击中,以诱骗用户在攻击者拥有的账号里输入其个人信息,之后攻击者就能够登陆自己的帐户来获取被骗用户输入的数据。
会话中毒 :攻击者通过用户提交设置会话数据的Web表单向该用户会话中注入潜在危险数据。
一个经典的例子就是一个站点在某个cookie中存储了简单的用户偏好(比如一个页面背景颜色)。攻击者能够诱骗用户点击某个链接来提交某种颜色,而实际上链接中已经包含了某个XXS攻击,如果这个颜色没有被转义,攻击者就可以继续向该用户环境中注入恶意代码。
解决方案有许多基本准则能够保护您不受到这些攻击:
不要在URL中包含任何session信息。
Django的session框架(见第12章)干脆不允许URL中包含session。
不要直接在cookie中存储数据,而是保存一个映射后台session数据的session ID。
如果使用Django内置的session框架(即 request.session ),它会自动进行处理。这个session框架仅在cookie中存储一个session ID,所有的session数据将会被存储在数据库中。
如果需要在模板中显示session数据,要记得对其进行转义。可参考之前的XSS部分,对所有用户提交的数据和浏览器提交的数据进行转义。对于session信息,应该像用户提交的数据一样对其进行处理。
任何可能的地方都要防止攻击者进行session欺骗。
尽管去探测究竟是谁劫持了会话ID是几乎不可能的事儿,Django还是内置了保护措施来抵御暴力会话攻击。会话ID被存在哈希表里(取代了序列数字),这样就阻止了暴力攻击,并且如果一个用户去尝试一个不存在的会话那么她总是会得到一个新的会话ID,这样就阻止了会话滞留。
请注意,以上没有一种准则和工具能够阻止中间人攻击。这些类型的攻击是几乎不可能被探测的。如果你的站点允许登陆用户去查看任意敏感数据的话,你应该 总是 通过HTTPS来提供网站服务。此外,如果你的站点使用SSL,你应该将 SESSION_COOKIE_SECURE 设置为 True ,这样就能够使Django只通过HTTPS发送会话cookie。
邮件头部注入邮件头部注入 :仅次于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 中)根本不允许在用来构建邮件头部的字段中存在换行符(表单,to地址,还有主题)。如果您试图使用 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中出现的东西,是不可能发生的。
暴露错误消息在开发过程中,通过浏览器检查错误和跟踪异常是非常有用的。Django提供了漂亮且详细的debug信息,使得调试过程更加容易。
然而,一旦在站点上线以后,这些消息仍然被显示,它们就可能暴露你的代码或者是配置文件内容给攻击者。
还有,错误和调试消息对于最终用户而言是毫无用处的。Django的理念是,站点的访问者永远不应该看到与应用相关的出错消息。如果你的代码抛出了一个没有处理的异常,网站访问者不应该看到调试信息或者 任何 代码片段或者Python(面向开发者)出错消息。访问者应该只看到友好的无法访问的页面。
当然,开发者需要在debug时看到调试信息。因此,框架就要将这些出错消息显示给受信任的网站开发者,而要向公众隐藏。
解决方案Django有一个简单的标志符,来控制这些出错信息显示与否。如果 DEBUG 被设置为 True ,错误消息就会显示在浏览器中。否则,Django会返回一个 HTTP 500(内部服务器错误)的消息, 并显示你所提供的出错页面。这个错误的模板叫 500.html ,并且这个文件需要保存在你的某个模板目录的根目录中。
由于开发者仍然需要在上线的站点上看到出错消息,这样的出错信息会向 ADMINS 设定选项自动发送email。
在Apache和mod_python下开发的人员,还要保证在Apache的配置文件中关闭 PythonDebug Off 选项,这个会在Django被加载以前去除出错消息。
安全领域的总结我们希望关于安全问题的讨论,不会太让你感到恐慌。Web是一个处处布满陷阱的世界,但是只要有一些远见,你就能拥有安全的站点。
永远记住,Web安全是一个不断发展的领域。如果你正在阅读这本书的停止维护的那些版本,请阅读最新版本的这个部分来检查最新发现的漏洞。事实上,每周或者每月花点时间挖掘web应用安全,并且跟上最新的动态是一个很好的主意。小小的投入,却能收获保护你的站点和用户的无价的回报。
接下来?下一章中,我们会谈论到一些使用Django的细节问题:如何部署一个站点,并具有良好的伸缩性
分享到:
评论

相关推荐

    数据安全治理白皮书5.0

    总之,数据安全治理白皮书5.0为当前数字经济环境下的数据安全问题提供了全面的参考。它所提倡的综合治理理念、全方位设计思路和技术驱动策略,对于企业和机构在数字化进程中实现安全可控的发展具有重要的指导作用。...

    JRT 0223—2021金融数据安全 数据生命周期安全规范.zip

    《JRT 0223—2021金融数据安全 数据生命周期安全规范》是针对金融行业数据安全的重要标准,旨在规范金融机构在数据全生命周期中的安全管理,确保金融数据的保密性、完整性和可用性。这一规范对金融行业的数据保护...

    浅析跨境电商领域的数据安全问题 (2).docx

    浅析跨境电商领域的数据安全问题 (2).docx浅析跨境电商领域的数据安全问题 (2).docx浅析跨境电商领域的数据安全问题 (2).docx浅析跨境电商领域的数据安全问题 (2).docx浅析跨境电商领域的数据安全问题 (2).docx浅析...

    大数据云计算环境下的数据安全问题与防护.pdf

    然而,随着云计算服务的广泛应用,数据安全问题日益突出,为确保数据安全,需要采取一系列有效的防护措施。 首先,我们来分析云计算的几个主要优势: 1. 投入成本较低:相较于传统的数据中心,云计算大大降低了...

    大数据导论:大数据安全单元测试与答案.docx

    棱镜门事件是一个典型的例子,揭示了大数据安全问题的严重性。该事件表明,美国国家安全局通过棱镜计划在全球范围内进行了广泛的电子监听,这不仅涉及国家间的通信安全,也侵犯了公民的隐私权。因此,选项B中认为...

    JRT 0197-2020金融数据安全 数据安全分级指南pdf.zip

    《JRT 0197-2020金融数据安全 数据安全分级指南》是针对我国金融行业数据安全制定的一项重要标准,旨在为金融机构提供一套系统化、规范化的数据安全管理框架,确保金融数据的安全性和合规性。该指南详细阐述了金融...

    大数据安全期末考试复习题 + 答案 + 我制作的一个html网页(点击题目就会出现答案,再次点击,答案消失)方便大家复习

    3、数据传输过程中面临的3大问题包括数据生命周期安全问题,基础设施安全问题,以及( ) A、 数据加密问题 B、 个人隐私安全问题 C、 信息通道问题 D、 传输协议问题 答案: B 4、大数据具有的4V特点是大量、...

    数据安全架构设计与实战.docx

    随着大数据时代的到来,数据安全问题日益凸显,给企业和个人带来了巨大的挑战。数据安全架构设计是保障企业数据安全的重要组成部分。数据安全架构设计的目的是为了确保数据的安全性和可靠性,防止数据泄露和攻击。...

    医院数据安全问题分析与解决方案.ppt

    医院数据安全问题分析与解决方案.ppt医院数据安全问题分析与解决方案.ppt医院数据安全问题分析与解决方案.ppt医院数据安全问题分析与解决方案.ppt医院数据安全问题分析与解决方案.ppt医院数据安全问题分析与解决方案...

    数字化医院数据安全问题分析与解决方案共57页.ppt

    数字化医院数据安全问题分析与解决方案共57页.ppt

    安全大讲堂之大数据安全培训系列文档.zip

    在当今信息化社会,大数据已成为企业和组织的核心资产,但随着数据量的爆炸性增长,大数据安全问题也日益凸显。"安全大讲堂之大数据安全培训系列文档"是华为内部进行的一次专业培训,旨在提高员工对大数据安全的认识...

    车联网数据安全监管制度研究报告2022.pdf

    2. 主体之间责任分配问题:车联网数据安全监管制度中,需要明确各个主体之间的责任分配,例如,谁是数据所有者,谁是数据处理者,谁是数据保护者等。 3. 技术挑战:车联网数据安全监管制度需要解决技术挑战,例如,...

    数据安全法规及标准建设.pdf

    这些事件反映出数据安全问题的普遍性和严重性。 全球监管环境也呈现出趋严的趋势。截至目前,全球已有107个国家和地区制定数据安全和隐私保护法律。其中,欧盟的《通用数据保护条例(GDPR)》在跨境数据流动限制、...

    大数据安全标准化白皮书

    随着大数据技术的广泛应用,数据安全问题日益突出,因此建立一套科学合理的安全标准体系显得尤为必要。 白皮书首先阐述了大数据安全标准化的需求。这包括对数据生命周期各阶段的安全管理,如数据加密、访问控制、...

    数据安全治理审计制度模板.docx

    常见的问题和风险包括未建立数据安全治理架构、缺乏数据战略规划、未制定安全管理制度及流程,以及风险评估不足等。这些问题可能导致法规不合规,影响数据安全体系的长期发展。 审计的主要方法和程序涉及到文档审查...

    数据安全管理工具需求描述

    随着数据安全法规的落地,银行业对数据安全问题的重视程度也逐渐增加,特别是个人隐私数据安全问题。为此,银行业需要对个人客户数据进行安全定级,根据定级结果明确不同用户的访问权限及是否有异常访问行为。 智能...

    企业数据安全解决方案的实践.pdf

    随着数据价值的凸显,数据安全问题也日益成为企业关注的焦点。在文件《企业数据安全解决方案的实践.pdf》中,详细探讨了数据安全的现状、数据泄露风险以及相应的解决方案,这些都是企业在实现数据价值最大化的同时...

    大数据云计算背景下的数据安全研究.pdf

    大数据云计算背景下的数据安全研究,主要围绕云计算与大数据技术带来的数据安全问题进行探讨。在分析了大数据云计算的技术特征后,论文进一步揭示了数据安全现存的问题,最后提出了保障数据安全的具体措施。 首先,...

Global site tag (gtag.js) - Google Analytics