WEB安全第十六课 应对恶意脚本 |
在前面的内容里,我们讨论了许多浏览器安全机制——现在再回过头来看,可以说这些安全机制几乎都有一个共同的目标:阻止同一个浏览器里恶意内容与其他合法网页之间的不合理交互。这个目标确实重要但也相当狭隘,因为攻击者突破无关网站边界的手段肯定花样百出,所以他们的拿手好戏也绝不止于此。
🦴🚠🍍♏🐙 所有浏览器都需要面对一个设计上的挑战,那就是攻击者可以干扰用户的使用或冒充第三方站点,而无需涉及真正的目标站点。例如,对攻击者来说如果能用JavaScript代码在屏幕上创建一个未修饰窗口(undecorated windows),也许在窗口里打开一个地址栏貌似没问题并诱使用户相信窗口里的内容也是来自可信站点的,实际上要比在fuzzybunnies.com返回的内容里去注人恶意内容要更容易一些。 但对用户来说很不幸的是,浏览器对早期Web这类与跨域内容隔离无关,实际上是采用更易受攻击的JavaScript API来干扰或迷惑用户的问题并未投入足够的重视。这种情况在短时间内也不太可能有改观了:浏览器厂商一边要修复在浏览器具体实现里相对来说更严重的包含各种缺陷的代码,另一方面又忙着推出各种闪亮登场的新功能,以吸引Web应用开发人员、用户和主流媒体,厂商们的开发资源就这样被摊薄了。 1.拒绝服务攻击 🧠🎠🍌🈸🐶 攻击者可以拖跨浏览器或使浏览器完全无法操作是影响Web使用最常见最明显但也最不受重视的问题,这就是拒绝服务(Denial-of-Service,DoS)攻击,在页面组件和混搭盛行的当下,这个问题可能导致令人不安的意外效果。 为什么大多数浏览器容易受到拒绝服务攻击,主要是由于设计上欠缺计划性:无论是底层的文档格式,还是脚本语言的功能,都没有考虑过要合理地限制CPU或内存的占用。换而言之,任何足够复杂的HTML文件或JavaScript死循环都能使底层的操作系统陷于瘫痪。更糟糕的是,各种限制资源消耗的做法,以及用户访问恶意页面浏览器失控后再回复正常的处理,还受到了各种抵制。 👨🚒👗📷😒👃 例如,以前HTML5 API提案的各位作者们就完全没有对如何预防资源耗尽的攻击提出任何方案,他们甚至不认可有这种需要。这些专家们的观点是,如果现在提出任何限制,会阻碍往后5到10年内Web的发展。而相对应的,浏览器厂商也会因为缺乏标准级别的指引而拒绝采取行动。 某些人很功利主义地认为,完全无需考虑提议什么DoS防御手段,因为这根本没意义——有很多种方式能把浏览器搞崩溃呀,干嘛要操心其中特定的一种呢?很难和这种观点对话,但得说这预言倒是日益成真了:可以进行DoS攻击的要素越来越多,所以短期内也确实越来越不可能完全解决这个问题。 👩✈️👞📏😫🙌 注意: 公平来说,某些操作的运算复杂度并非导致浏览器崩溃的唯一原因。其他因素还包括页面渲染和脚本执行过程之间也需要保持同步。这种设计使网站开发人员不需要考虑代码的重入问题和线程安全,这样对降低代码复杂度和提高安全性都有好处。 🧑🚀🎒🔭😶✊ 遗憾的是,这种处理也使得单个页面就可以锁死整个浏览器,或至少有巨大的影响。 不论这些考虑是怎样的,即使浏览器厂商拒绝承认DoS风险是个问题,但这类攻击的后果是不容忽视的。对使用者个人来说,如果浏览器被挂死,会带来巨大的数据丢失的风险(这种数据丢失可能发生在浏览器里也可能是任何其他间接受到此类攻击影响的应用)。而且,在某些社交网络站点里,攻击者只要向受害者共享一个恶意的页面组件甚至更简单地,仅是提供一张精心挑选的图片,就可以把受害者踢出登录状态,使得该用户再也无法访问服务了。 👨🎨👖🖌🥱👆 使浏览器无法工作的常见伎俩包括:加载复杂的XHTML或SVG文件,反复弹出大量浏览器窗口,运行需要分配内存的JavaScript死循环程序,制造大量的postMessage(...)调用队列等等。尽管这些例子都和具体实现相关,但每种浏览器上都有若干途径能达成这些效果。即使Chrome已经使用了独立的渲染进程来分隔无关的页面,仍然很容易把整个浏览器给拖垮掉:因为仍然需要用顶级进程来调度和各种脚本相关的,会消耗大量内存和CPU的任务。 由于上述这些情况,也不奇怪尽管大家普遍不重视浏览器里的DoS攻击问题,但大多数浏览器厂商还是开始引入某些应对之策。当然这些策略也并非很统一,往往是针对某种被广泛滥用的特定API,有时候是为了消除一些非恶意但常见的编程错误。不管怎么说,让我们来快速地看一下这些措施吧。 1.1执行时间和内存使用的限制🧒🧥🛋😊✊ 之前也提到的,诸多类型的JavaScript操作都需要和界面有一定程度的同步,大多数浏览器厂商为了保险起见,也会尽量使脚本的运行和其他的浏览器代码保持同步。这种设计有个明显的缺陷:当JavaScript引擎在处理有问题的while(l)循环时,浏览器里其他大部分的功能会完全没有响应。Opera和Chrome浏览器的最顶层用户界面基本上还是能响应的,就是有点慢,但在大多数其他浏览器里,甚至无法通过常规的UI去关掉浏览器窗口了。 由于脚本代码很容易在无意中造成死循环,为了协助开发人员,IE浏览器、Firefox、Chrome和Safari都强制对连续或接近连续执行的脚本设定一个较为合理的时间限制。如果脚本使得浏览器停止响应的时间超过若干秒,用户会看到一个提示窗口,提示可以中断脚本的执行。选择了这一选项的后果就和出现了程序未处理的异常相类似,也就是说,会中断目前的执行流程。 ✊🦼🍏🅿🐞 很遗憾,这种限制对防御恶意脚本并不是特别靠谱。例如,无论用户怎么选择,恶意脚本仍有可能通过定时器或事件处理程序再®新执行,另外还可以间歇性地暂时释放CPU,CPU状态空闲下来后计数器就会被重置,这样就可以从源头上避免触发浏览器的死循环提示了。另外还可以按之前提过的那样,有很多种消耗CPU资源但又不会使它变成死循环的做法:譬如渲染复杂的XHTML、SVG或XSLT文件,一样可以中断浏览器的响应但又不需要听命于任何检查。 除了执行的时间,浏览器还会尝试控制执行脚本的内存占用。调用栈的大小与浏览器的设定有关,一般在500到65535之间,如果碰到深度的递归操作,浏览器会无条件终止这种行为。而脚本堆大小的分配则不同,它基本没什么限制;每个页面就可以分配和消耗掉上GB的内存。实际上,早期版本里的内存限制(如IE6浏览器限制每页只能占用16MB内存)在新版本里都被移除了。 1.2连接限制 🤌🚂🍊☯🪰 在许多Web应用里,每个页面里的内容并不只是地址栏看到的那个URL所对应的HTML文档,还有许多其他单独加载的子资源,如图片、样式表和脚本。给这些元素单独建立一个HTTP连接在效率上会比较慢,HTTP协议通过扩展提供了持续会话和请求管道。但即使有这些改善,性能依然有个顽固的问题。HTTP协议是根据收到的请求的先后顺序来依次返回响应的,所以如果加载某个子资源(不管它原本多微不足道)的时间比较长,所有后续资源的加载也都会被延误。 要解决这一问题并优化不能使用持续会话和管道机制时的性能,所有的浏览器都可以向目标服务器发出若干个HTTP连接。这样,浏览器就能同时发出多个并行的请求。 👨🚒🧥🩺🤖💅 不幸的是,这个并行连接的做法对目标网站来说可能代价沉重,特别是那些依赖传统fork()方式的架构。因此,为了限制有意或无意的分布式DoS攻击,需要限制浏览器对每个主机的并行连接数量,通常默认设置在4到16个之间。更进一步来说,为防止攻击者把浏览器搞得过载(或影响到周边其他网络设备的性能),也会限定浏览器到所有目标服务器的总连接数只能为单台服务器连接数的几倍而已。 注意:在很多具体实现中,每个主机的连接限制是根据域名而不是IP地址确定的。因此,攻击者还是可以在自己的域名服务器里设定多条假的DNS记录指向不相关的IP,突破第一条限制。当然全局的连接限制仍然有效。 尽管同一时间内HTTP会话的数量受到限制,但对有效的活动会话能保持多长时间却没有特别限制(也就是可以一直保持连接,直到达到系统内核的TCP/IP超时设置)。这种设计也使得攻击者如果访问若干刻意响应缓慢的目标服务器,就能耗尽全局连接数,使得用户无法再处理其他有用的事了。 💪🌡🫖💲🐒 1.3过滤弹出窗口 网页可以使用window.open(...)和window.showModalDialog(...)这两种API弹出新的浏览器窗口,新窗口的地址可以为任意可接受的URL。在这两种情况下,都可以设定新窗口里的浏览器不要显示某些界面组件。window.oper(...)的简单用法类似这样: 👆🗺🦀♂🐮
除了这两种JavaScript方法之外,还可以用某些HTML元素的编程接口来创建新窗口。例如,可以调用HTML链接的click()方法或调用表单的submit()方法。如果相关的代码包括target参数,结果就是弹出以这个target名称命名的新窗口。 可以想见,大家很快就发现网页能随意弹出新窗口其实大有问题。在20世纪90年代末期,此时还处于早期发展阶段的在线广告商们觉得,有必要不惜代价地吸引大家来观看他们的广告,即使这么做会令用户非常厌恶和唾弃。他们好像真心觉得,为显示个花里胡哨的广告就弹出个新窗口,确实是个做生意和交道新朋友的好点子啊!#j347: 🙏⛴🌶🅱🦄 弹出式窗口(pop-up)和隐形弹出窗口(pop-under)0很快就成为互联网上最臭名昭著和最为人垢病的问题。理由也确实非常充分:尤其是隐形弹出窗口,有可能你上网几个小时之后,浏览器已经在后台偷偷打开了一堆的广告窗口。 由于饱受投诉,浏览器厂商也开始出手干预了,他们加了一项简单的限制:如果不在白名单里的页面要偷偷弹出一个新窗口,浏览器会默默地直接忽略这种行为。在用户点击鼠标或类似的动作之后,如果触发了事件处理程序确实会弹出窗口,则不属此例。例如,当JavaScript在响应onclick事件时,window.open(...)就能被调用并获得执行,但还要稍微多等一小段时间(在IE浏览器和WebKit里,必须等事件处理器里的任务结束时,才能弹出新的窗口。而其他浏览器则会优雅地等个1秒钟左右。) 🙌🚂🥭♏🐺 拦截弹出窗口在刚开始时确实对扼制弹出式广告有效果,但最终证明这效果也相当有限:很多网站会等用户点击了页面的什么地方(为了点击一个链接或仅是翻页)之后才弹出新窗口。另一些则干脆采用更霸道的做法,直接来个全屏广告,必须先点击前面的广告页面,才能看到下面实际上要访问的页面。 除了在广告页面领域里的军备竞赛之外,window.open(...)从DoS角度看也挺有意思。创建无数个新窗口,耗尽操作系统能允许的最大UI句柄数量,也是一种搞垮浏览器和其他应用的好办法。如果能限制浏览器打开的窗口数量,从理论上来说肯定是有价值的防护。但别想得美了:令人难以置信的是,只有IE和Chrome才会合理地限制单次点击可以弹出的window.open(...)数量。而在其他浏览器里,一旦临时允许某个动作可以弹出新窗口,攻击者就可以像疯子一样胡乱打开任意数量的窗口。#j340: 1.4对话框的使用限制🧑⚕️🛍🪦😊🤌 除了窗口的问题之外,来自网页的脚本还可以打开某些浏览器自身或操作系统处理的对话框,也是一个令人头大的问题。对当下的Web应用来说,这些对话框几乎没什么用,但对话框依然是浏览器安全里非常有意思的一环。涉及对话框调用的API包括用于展示简单的文本信息的window.alert(...);用于请求基本用户输入的Window.prompt(...)和window.confirm(...);以及调用操作系统打印功能的window.print(...)。还有一些和特定厂商有关较不引人瞩目的扩展,如Mozilla的window,sidebar.addPanel(...)和window,sidebar.addSearchEngine(...)(分別用于创建书签和注册新的搜索引擎)。 除了上面提到的几种JavaScript方法,另外还有若干种间接派生出对话框的做法。例如,可以通过调用文件上传按钮的click()方法,或访问一个可下载的文件时,通常都会弹出系统提供的那个文件选择对话框。访问需要HTTP认证的URL时,通常也会弹出浏览器的提示框。 👏🚠🥩❗🦕 那么,对话框为什么值得关注呢?对话框和通过代码弹出的新窗口相比,还是颇有差异的。与基本上属于异步的window.open(...)API不同,对话框会终止JavaScript和其他动作的执行(如访问的跳转和事件的传递),这样就能有效地防止创建大量新的对话框,避免耗尽资源程序瘫痪。但对话框的行为模式也有不利的一面:除非用户把对话框关掉,否则就无法和浏览器的其他部分交互了。 这导致一个很有意思的漏洞。如果旧对话框刚一关掉就又立马弹出一个新的对话框,会使用户完全没办法访问浏览器的正常UI部分,甚至没法关掉浏览器窗口或离开有问题的恶意页面。恶意脚本的作者有时候能通过滥用这一漏洞,迫使受惊吓的普通用户必须先执行一些危险的动作(如下载和运行一些不受信任的可执行文件),才能允许下一步动作:如果不这么做,在脚本发起的安全提示框里,无论用户点击的是哪个选项,都会反复看到同一个对话框。 大概由于恶意脚本确实有可能会利用这种对话框机制,浏览器厂商也开始尝试某些较为不会造成系统崩溃的提示方式。譬如在Chrome里,常见的模态窗口都带有一个复选框,允许用户禁止本页面利用有攻击性的API,再继续弹出提示框(当然除非重新加载一次页面)。在Opera里,则可以停止执行本页面的脚本。在Opera和近期版本的Firefox里,浏览器窗口里只有在文档显示相关的区域范围内,常用对话框才是模态的,用户仍然可以选择关闭标签页或在地址栏里输人其他的URL。当然这类改进的覆盖范围颇为有限。 👮♂️👒💉🤮🦴 注意:很多浏览器对话框在解释这个提示窗口来自哪里以及派什么用场时都非常笨拙。在某些场景里,例如显示在图14-1里的一个Firefox对话框,其效果显得非常滑稽——这种可笑的处理会带来严重的后果。恶意脚本如果弹出一个貌似来自操作系统本身,,看起来很权威正式的对话框,很容易就把那些没有经验的用户搞糊涂了。也确实不难想象为啥“黑客”这么做能成功了。 🧑🍳👜🔭😘👀 在执行页面的onbeforeunload(离开网页前确认)事件之前,Firefox会弹出一个令人极度困惑、用意含糊不清的提示。该处理器原本是为页面作者提供了一个机会,解释如果离开当前页面会带来怎样的后果(如丢失未保存的数据),并向用户最后确认,需要执行哪个动作。在截图里,第一行和最后一行的文字其实来自浏览器本身;而中间两行的“解释”实际上是由(匿名!)恶意站点提供的。这个提示框本身带来的安全危害很有限,但这是个典型的坏UI设计样例。遗憾的是,IE里也有几乎完全一样的此类对话框,而其他的浏览器也好不到哪里去。 👩🪖🖥🤩👊 #f464: 2.窗口定位和外观问题🧑⚕️🧥🖌💀🖕 好吧好吧——我们不要再谈DoS漏洞这个了无新意又不受待见的主题了。有许多和UI相关的各种API 而window.open(...)就是最让人感兴趣的一个。从之前的讨论里,我们可以知道这个不起眼的函数不但能让Web应用弹出新窗口,还可以把新窗口定位在特定的屏幕位置上。其他几种方法,还能让窗口以特定的方式在屏幕上移动、缩放或堆叠在一起。最后,可以用window.close()把脚本不再需要的窗口优雅地关掉。 与其他能控制UI的各种特性相似,这些API很快也成了痛苦之源。之前一系列令人捧腹的创意包括把窗口的部分或全部放到屏幕以外的区域来创建“隐形”窗口,或把窗口缩到非常小,所以现在这些函数都要求新建的窗口至少要有一定的面积,并且必须显示在桌面可视区域内(但仍然可以创建一个新窗口,让它不断绕着屏幕移动,一旦鼠标尝试关闭窗口,窗口就自动跳开。不过这类事情我们前面也看过很多了,已经见惯不怪,除了叹口气,确实没啥可做的)。 👦👔🔍🤮🙏 3.用户界面的时差攻击 到目前为止,讨论过的问题可能确实都比较难修复,但至少从理论上来说,都还是有可能解决的。然而,还有一个非常荒谬的问题:会不会目前的网页脚本模式从根本上就是有违人类的本能呢?我这么说并非单纯指通过网页形式开展的社工漏洞,用于攻击那些心不在焉容易受骗的用户;而是说,有没有可能由于人类自身认知的局限性,使得脚本甚至有可能骗过那些小心谨慎也有技术背景的受害者呢? 这个问题颇为得罪人,实在不宜多问,然而答案可能确乎如此。我们以一个专注的普通人为例,通常在发出视觉刺激到产生自主运动响应(voluntary motor response)之间会有100到300毫秒的延迟。但人类其实并不会真的等那么长的时间,再根据收到的刺激信息来调动各种细小肌肉的运动;实际上,我们会下意识地根据过往的经验,先提前安排好一系列的动作,在感应器官收集到信息以后,会再做调整。所以在很短的间歇内,我们实际上没法退出之前预先安排好的动作,即便此时已经出现了严重的问题。 👳🛍🖨😰👈 呜呼,对现在个人计算机的性能来说,即使只有这个延迟时间的十分之一长,就足已发生很多事情了。特别是,脚本可以弹出新窗口、到处移动窗口或关闭已有的窗口;也可以弹出或退出操作系统的提示框。在这种情况下,要设计出高安全度的UI就不像表面看到的那么简单了,除非在软件设计方式上能有重大突破,否则有些类型的攻击恐怕就是没有办法防护的。 要说清楚这个问题,举例说某个页面企图强制下载某种危险类型的文件。通常来说,下载会自动弹出系统提示框上面有“打开”、“保存”和“取消”三个选项。正常的用户反应是选择最后一个选项——除非攻击者令他们完全没有机会做此选择。 👌💈🫖📶🐕 我们假设在下载对话框弹出几毫秒之后,在用户甚至还没来得及注意到这个对话框的时候,最顶层又弹出了一个窗口把这个下载对话框给挡住了。在新的窗口里,攻击者精心构造出用户最可能点击的某个按钮或链接,例如,提示可以关掉某个讨厌的全屏遮盖式广告的按钮。当用户执行这个看似完全正常的动作时,恶意页面可以使用onmousemove事件监控鼠标指针的位置和移动速度,就能相当准确地预测出用户的点击时间。在用户点击前几毫秒再关掉顶层覆盖的窗口,只显示在同一位置的“打开”按钮,使得用户不可避免地点击了下载提示框里那个有问题的选项。实际上用户对这事确实做不了什么。 为了应对安全对话框里的这种攻击,在过去几年里浏览器加人了各种安全延时,必须先要经过500毫秒到5秒的延迟,光标才会被移到此类对话框内,用户才能点击到这些按钮。但这种延迟机制受到浏览器UI设计人员的抵制:设计人员显然痛恨这种处理,他们觉得产品的响应速度当然是越快越好,这种让用户很不爽的无法点击的按钮或倒计时机制会严重影响产品的可用性。有些人已经在鼓动着把现在老UI里的超时处理去除掉。HTML5的地理位置分享提示框就受到这一观点的影响。在许多浏览器里都没有针对这个UI的真正防护。 实际可能比上述情况还要更复杂,浏览器自身的界面可并非UI时差攻击的唯一对象。事实上,在受信任网站上,许多和安全以及隐私相关的界面也是有可能受到攻击的,而要修复这些问题可就比在已知风险的系统UI里加点延迟时间要困难得多了。 🖐🎠🥚♀🦄 注意:除了上述这些毫秒级的点击和按键劫持之外,哪怕仅依靠一些看来很不起眼的最低限度的条件,即使是身心健康注意力集中的测试对象也有可能被成功诱导,以致忽略某些非常明显和不同寻常的视觉刺激。 譬如下图里显示的“隐形的大猩猩试验”,就是其中尤为知名的例子。研究人员先准备好一段视频,但几乎所有的观看者都没有留意到在人群里非常突出的大猩猩。结论是即使一个很懂行的用户,在某些条件下也可能忽略地址栏里URL的变化或浏览器里SSL状态提示这类信息——这可真叫人不安啊。 👈🚗🍍❎🐮 我们现在之所以没有尝试去解决这个问题,是操纵这种攻击的人很少而且他们多半是规规矩矩的科学家。但如果攻击的目标是位非常重要的人物,事情就很难说了。 👃🌕🍏♂🐕 视频地址: ✊🌡🍚💲🦊 当观众们被请来观看这段视频时,会被要求统计视频里的人传递篮球的次数,然而大多数观众都没有注意到视频的中段有个身穿大猩猩服装的人在房间里随意走动。真的! 评分
帖子热度 1.2万 ℃
|
|
远古时期并无人类,女娲娘娘补天后,用剩下的两块神泥各捏了一个小人,两人一开始并无区别,都是一头四肢,一身一乳,唤名男,女。
只是后来两人不知为何大打出手,女人强悍,把男人的那一乳撕下,据为己有置于胸前,男人几次想抢回,均未成功,于是告到女娲娘娘那里,娘娘见女人这样甚是好看,便没有给她取下,而是在女人两腿之间,不起眼处取泥一小块,搓成圆形送给男人,用以安抚。男人甚喜,如获至宝藏于身下。每每拿出把玩,均感身心愉悦,所以到了今日男人还乐此不疲。 女人无时不想把它夺回,所以伤口至今没有愈合,每月均由血流出,但碍于女娲娘娘,不敢造次。多年后想出一法,找男人商量,允许男人抚摸他以前失去的那一乳(男人在抚摸时,实际上比较偏爱一个,因为那个以前就是他的),条件是也要把她原来的东西暂时放回原处,想用体液将其融化,已达到索回的目的,男人不知是计欣然同意,于是交合后两人均感到极大满足。👨🎨👚🖲😉👎 有了第一次,就有第二次,第三次,每次后都有一小部分被留在女人体内,但多年已过,那已被男人彻底融合,留在体内的自己却融合不了了,经十月孕育还是融合不了,但成了独立的一个生命体,不得不排出。就这样人类开始繁衍生息。。。。。 。。。我是来混熟脸的#y398:#y398: |