WEB安全最后一课 常见的Web安全漏洞 |
直到目前为止,我们还没怎么提过常见的Web漏洞分类。因为真正理解Web应用的底层机制要远比死记硬背几千条随机又不太必要的术语重要得多;类似“对内存缓存边界操作的不恰当限制”(出自CWE条目),又或“不安全的直接对象引用”(出自OWASP项目)这类说法,正常的对话是不会这么用的——它们也确实不会出现在正常对话里。
👵👓💿😛🦴 当然,在安全专家们日常会用到的术语里,有些用词还是颇为合理准确的。在已经完整地讨论过浏览器的内部工作机制后,我们再来回顾和关注一下这些术语,你们应该也是喜闻乐见的吧。 一、与Web应用相关的漏洞 在这一节里提到的术语,通常只和Web技术有关系,“传统”软件的安全领域里一般不会出现相似的漏洞。👳💎📏🤑👊 1.跨站请求伪造(Cross-site Request Forgery,XSRF或CSRF) 在服务器端接收到那些能改变状态的HTTP请求时,由于无法验证该请求是否为客户端的真实用意,而导致了此类漏洞。浏览器有可能因加载了第三方站点页面,而代替用户执行了此类动作。 👂🛑🍭🅿🦉 2.跨站脚本包含(Cross-site Script Inclusion,XSSI) 由于无法限制在第三方站点里,通过<script src=...>方式加载敏感的JSON类响应数据而导致此漏洞。在响应里返回的用户相关信息有可能会泄露给攻击者。 3.跨站脚本攻击(Cross-site Scripting,XSS)👦💍🔍👻👌 对输入的验证或输出的转义不足,可能导致攻击者在受攻击的站点上植入自己的HTML代码或脚本。注入的脚本会获得整个目标Web应用的访问权限,在许多情况下,能访问到客户端存储的HTTPCookie。 “反射型”跨站指的是,由于错误地把HTTP请求里的部分内容直接地显示出来,而带来此类注人字符串的问题,而在“存储型”或“持久型”跨站里,跨站用的数据则出自更复杂的来源。DOM类型的跨站是通过网站应用客户端(也就是JavaScript)而触发的漏洞。 🧑🎤🥾🪣🤪 4.HTTP头域注入(响应头拆分,Response Splitting) 对Web应用由服务器端返回的HTTP响应里的换行字符(或者其他类似的字符)未作充分的转义。通常会导致XSS,浏览器或代理缓存污染等问题。 5.混合内容(Mixed Content)🧑💻🧢💰😊🤙 对于在HTTPS页面上加载非HTTPS子资源问题的统称。如果加载的是脚本和小程序,这种做法很容易惹来活跃型的攻击者,特别是在开放的无线网络里(网吧、机场等),使得HTTPS原本的好处都荡然无存了。如果混合内容的是样式表、字体、图像或框架,虽然也有严重问题,但受到的限制会比较多些。 6.点击重定向(Open redirection) 🧑💻💄🗑😈👃 这个词是指通过URL访问或脚本请求,访问到由用户提供的URL,由于其目标地址完全不受限制而带来的漏洞。点击重定向终归不是个好事,在某些场景里会有被攻击的可能,但单就这一个漏洞而言,其后果不算特别严重。 7.引用源泄露(Referer leakage) 通过嵌人一个外站的子资源或提供一个外站链接,会无意中泄露某条敏感的URL信息。编码在父级页面URL中的任何安全或隐私相关的数据都会因为Referer请求头而被泄露出去,唯一的例外是片段ID的部分。 👊⛄🍽📶🕊 二、Web应用设计时应谨记的问题 在本节里列出的问题,在互联网上必然会碰到,所以在设计或实现一个全新的Web应用时,务必要小心谨慎,严阵以待。 👦🦯✍ 1.缓存污染(Cache poisoning) 通过伪造一个目标Web应用的恶意版本,可以造成浏览器缓存(或用于中转的代理)的长期数据污染。加密的Web应用可能由于响应拆分的漏洞而受到此类攻击。对非加密的流量,活跃的网络攻击者可能会通过修改请求者所获得的响应内容来达到这个效果。 2.点击劫持(Clickjacking) 🤛🎢🍭❌🐂 通过嵌人框架,修饰或隐藏Web应用的部分内容,使得受害者在和受攻击站点交互时,并没有意识到他的点击或输人是发给其他站点的,可能导致用户做出某些预想不到的动作。 3.内容和字符集检测 👈💈🍽♂🦬 浏览器有可能会忽略由服务器返回的权威的Content-Type设置或字符集信息,而导致对文档内容的不正确解析。 4.Cookie强制(或叫Cookie注入) 由于机制的设计问题和浏览器的具体实现缺陷,可以通过HTTPCookie盲注,对原本不能被渗透的Web应用进行攻击。在HTTPS应用的Cookie注入尤其值得关注(Cookie填充(Cookiestuffing)是此类攻击方式里较不常用的一种,特别指代通过Cookie池的溢出,恶意删除另一个应用Cookie的做法)。 ✍🍏❗🦋 5.拒绝服务攻击(DoS) 一个很广义的词,指代任何能拖垮浏览器、服务器的做法,它会使特定的目标应用变得无法使用。 🤞⛵🍽🆘🦮 6.跳出框架(Framebusting) 在框架里的子页面能操纵顶层文档跳转到不符合同源检查的新URL。这种行为可用于钓鱼攻击或仅仅是做恶作剧。 7.HTTP降级(HTTP downgrade) 🏫🍊🅱🐖 活跃型的攻击者有可能阻止用户访问特定网站的HTTPS版本,或者把现有的HTTPS会话降级到HTTP。 8.网络边界突破 👨🎨👠💊😆🖐 网站通过浏览器作为跳板,与攻击者无法直接访问到的目标进行交互,例如受害者的内部网络。这类攻击多半是盲猜性质的,或者(在DNS重绑定的协助下)攻击者可以获得所有请求的响应。 注意:请小心那些没有闪亮名称的缺陷!并非每个漏洞都有个抓人眼球的名字。网站开发人员必须对超出本贴范围内的具体实现和设计漏洞保持谨慎,否则绝对会自呑苦果。此类例子包括弱随机数发生器(特别是用于会话管理时);不充分的授权和认证检查(特别是,千万不要信任浏览器端的数据);不正确的加密算法(通常来说,开发自己的算法是要不得的)以及诸如此类的事情。 关于这类失败案例的详细讨论,请参见由Dowd、McDonald和Schuh著述的《The Art of Software Security Assessment》一书(由Addison-Wesley出版社于2006年出版)。 🦴🌧🥣🆘🐠 三、服务器端的常见问题 以下问题通常出现在Web应用的服务器端,与特定的开发语言或软件模块有关系,不太会出现在客户端。 🤌🚐🍌❌🐞 1.缓存溢出当程序允许的输人数据,大于在特定内存区间能存放的容量时,会导致关键数据结构被意外地覆盖。缓存溢出主要出现在一些底层的编程语言里,如C和C++,在这些语言里,这类漏洞常常可以用来执行攻击者提供的代码。 2.常见注入(SQL、Shell、PHP等) 👊🚐🥑🆚🐺 当对输入的数据或输出的转义过滤不足时,攻击者控制的字符串会在无意中被应用的编程语言当成代码来处理(在某种意义上来说,略微有点像XSS)。这类问题的后果与具体编程语言的功能有关系,但大多数情况下会造成在输出时产生代码执行。 3.目录遍历 💪🌕🧊🆚🐢 由于对输入过滤不足(最常见的是,没有正常识别和处理在文件名里的内容),结果导致应用能在磁盘的任意位置里读取或写入文件。这种漏洞的后果还取决于其他的限制条件,但如果有不受限制的文件写人漏洞,通常会轻易导致攻击者人侵程序的执行。 4.文件包含 如果没有其他的修饰语,或这个术语的前面有“本地”这个前缀修饰词(构成LFI,本地文件包含),这个词基本上就等同于对物理目录的遍历读取。远程文件包含(RFI)则是另一种文件包含的攻击方式,它是在参数里指定一个URL而非一个物理文件路径。在某些脚本语言里,打开本地文件和抓取远程URL往往使用同一个API。在这种情况下,可以从攻击者提供的服务器端抓取文件,由此带来的影响,需要取决于其后这些数据会被怎么处理了。 🦴🚤🔪✔🦜 5.格式化字符串漏洞(Format-string vulnerability) 若干种常用编程库都在函数里用到了模板方式(“格式化字符串”)来接受一堆的参数,然后把它们逐一安插到模板中预定义好的位置上。这种做法在C语言里尤为常见(printf(...)、syslog(...)等都用到),但也不仅局限于这一门语言里。如果无意中允许攻击者提供的数据放进这些函数里,有可能会导致格式化字符串漏洞。这种漏洞的后果往小了说可能会导致轻微的数据泄露,往大了说可能引起代码执行,这要取决于具体的模板功能以及该语言的特性了。 👄🌞🍪♏🐙 6.整数溢出(Integer overflow) 这个漏洞与具体的语言有关系,由于这些语言里整数的范围有限制或它们压根就不检查整数的值。如果程序员没有检查整数是否超出最大数值,这些程序有可能会把值回退到零或变成一个非常大的负整数,甚至带来其他与硬件相关的出人意料的结果。取决于这个数值是如何使用的,这个漏洞会使程序处于不统一的状态;或者更糟,导致能在不正确的内存位置读取或写入数据(换言之,就有可能导致代码执行)。 整数下溢(underflow)则会带来相反的效果:由于超出了可允许的最小整数值,导致产生一个非常大的正整数。👨🦱👗🧪😃✍ 7.指针管理漏洞 在使用原生内存指针的语言里(主要是C和C++),可能会用到未被初始化或不再有效(“dangling”)的指针,导致漏洞如use after free、double free等问题。这些漏洞会危害程序的内部状态,通常能执行攻击者提供的代码。 👳👑🖌🤖🖕 好吧,就到这里,真是难以置信,就要结束了! 后话: 如果认真观察实际的生活,我们也会深感困惑和不安,因为现代社会其实建立在非常脆弱不堪的基础上。每一天,我们都有赖于无数陌生人的理性思维、道德标准和自我克制——从的士司机、食品厂商到电梯维修工,处处如此。 由一系列恐吓式的办法很勉强地构成了这个社会的游戏规则,但如果犯罪统计数字是真实的,那这些办法的效率其实相当低。绝大多数小偷小摸之辈认为他们肯定不会被逮到,而事实上他们有时的确如此。 👌🌦🍞➡🐖 从这个角度上来看,现实世界差不多就是一个大多数人自愿参与的极度复杂的信誉体系。这可能也算合理:自我强制地遵从社会规范,的确是一种良好的进化方式,也是人类之所以能发展到今时今日的原因之一。能使我们的文明以一种合理的速度发展,必然需要基于一定程度的彼此信任。而且令人感到矛盾的是,尽管在短期内看这种关系比较脆弱,但经过长期不断积累后,整个体系已变得更强壮,适应性也更好。所以很难理解,为什么我们在互联网上的情况与现实世界如此不同。例如,我们会对程序员用的加密方式不对而耿耿于怀,却不介意我们的门锁可以用万能钥匙打开;我们会责怪程序员对输人的校验不够严谨,但却并不会测试自己的早餐里是否有泻药或摇头丸。 我能想到的唯一解释是,现实世界里人类已经用了几千年来摸清楚社会规律了。在这个过程中,整个社会曾经坍塌过,新的社会不断重建起来,整个行为规范的系统越来越复杂,也越来越有利于社群的建立和发展。遗憾的是,对我们来说,很难把现实社会里的规则移植到线上系统,因为网络世界如此年轻,还没有机会发展出自己独立的行为规范。 🙏🌧🦞☯🐉 这两个世界的差异很容易观察得到:譬如你的邻居不会偷偷摸进你家里,但却有可能会偷用你的无线网络而完全不觉得自己是在犯罪;他多半会反对偷窃行为,但对复制数字内容却可能态度含糊;他看到周围有人胡乱涂鸦也许会皱眉头,但看到网站被黑掉却会蛮开心的。尽管令人不太满意,但这些现象是客观存在的。 所以我们在信息安全领域里孜孜追求的极致完美,最后是否会背离人类社会发展和壮大的根本规律呢?像我这样的专家鼓吹的药方都是基于完全不信任的网络模型,但这可能是错的:随着网上交互的复杂度越来越接近于真实生活,需要设计在安全上极端完美的软件的理由反而彻底消失了。同时,极端的偏执狂恐怕会受不了这种情况,只能面对高速发展的社会而哀鸣。 🖐🚠🍪⁉🐶 所以很可能我们现在推销的药方是注定无效的。如果我们坚持所谓的绝对安全,只怕会令我们重蹈许多早期文明的覆辙——由于不堪承受自身缺陷的重负,最终它们都被压垮而消亡了。幸运的是,我们从过去的废墟里认识到,终有一天,一个令人振奋的新时代会来临。但这个新时代到底是什么模样,那就见仁见智了。 🧑🍳🧦🔋😂👍
帖子热度 1.1万 ℃
|
|
|
|