下载本文的 PDF 版本 PDF

构建安全的 Web 应用程序

信不信由你,这并非无望之举。

乔治·V·内维尔-尼尔,顾问

如今,网络钓鱼事件和几乎每天都发生的大规模数据泄露导致的身份盗窃事件层出不穷,谈论保护 Web 安全似乎近乎荒谬。在这一点上,大多数人似乎都准备对这个想法束手无策,或者为了控制住他们认为的混乱局面,而锁定他们可以控制的一个小组件。

在深入探讨之前,请允许我首先定义人们试图通过构建安全的 Web 应用程序来解决的三个主要问题

在本文中,我将讨论这些问题中的每一个、现有解决方案的当前状态,以及继续困扰大型 Web 应用程序的未解决问题。

浏览器安全模型

Web 本质上是一个难以保护安全的系统。为了提供统一的用户体验和足够的性能,大多数大型 Web 应用程序都是分布式的,并且用于在任何系统中完成工作的请求和回复都尽可能地尝试是无状态的。由于每个请求都试图是无状态的,因此服务器本身必须维护管理用户操作的所有状态。与应用程序不同,但与远程登录类似,客户端(又名用户的浏览器)和服务器之间不维护单个、长期存在的会话。为了使 Web 页面的流程看起来更像 Web 会话,有一些技巧可以在浏览器和服务器之间的每个请求上维护和通信状态。身份验证就是一个很好的例子。

为了向 Web 应用程序验证自己的身份,用户必须证明他们是他们声称的那个人。大多数应用程序都有用户名和密码方案,其中每个用户被分配一个唯一的用户名,然后选择一个只有该用户知道的密码。一旦用户成功地向应用程序提供了用户名和密码,用户就进入登录状态。这些概念对于过去 50 年中使用过计算机的任何人来说都很熟悉。它们直接来源于 20 世纪 60 年代的多用户分时系统。

问题是,虽然在使用分时系统时,用户与终端或长期存在的网络连接等通信设备之间存在某种唯一的映射,但在 Web 中情况并非如此。例如,用户可能正在使用 mail.foo.com 上的服务,然后决定单击日历并访问 calendar.foo.com,这很可能是一组完全不同的服务器,甚至可能与邮件服务器位于不同的物理位置。然而,它们仍然是 foo.com 提供的相关服务,并且它们之间的切换对于用户来说应该是无缝的。

大型 Web 应用程序维护身份验证状态的方式是依赖 Cookie,Cookie 由服务器设置并存储在浏览器中,并依赖浏览器来实现现在所谓的浏览器安全模型,尽管它应该被称为 Cookie 安全模型。该模型是服务器和浏览器之间的合同,声明浏览器将仅将 Cookie 发送到最初设置它们的域中的服务器。域由分配给服务器的 DNS 名称定义。在前面的示例中,foo.com 是设置 Cookie 的域名。

与任何由多个方独立实现的协议一样,不同的实现具有不同的错误。这意味着 Mozilla 在 Firefox 中实现的安全模型可能与 Microsoft 在 Internet Explorer 中实现的安全模型略有不同,并且这些模型与 Opera 中实现的安全模型不同,等等。安全模型实际上是所有可用实现的并集。仅保护您的系统免受市场份额最大的浏览器的攻击总是会导致麻烦。

一个具体的例子将有助于理解安全模型。在每个请求中,用户的 Web 浏览器都会发送它认为属于用户正在使用的域的 Cookie 集。如果用户正在使用域 mybank.com,则浏览器将发送在 mybank.com 域中设置的 Cookie。如果用户移动到另一个域(例如 freemail.com),则浏览器仅发送由 freemail.com 服务器设置的 Cookie。更改域的任何部分都会更改浏览器愿意发送的 Cookie 集。因此,freemail.com 和 freemail.net 不是等效的;它们是不同的域。

Cookie

在 Web 应用程序中,用户的 Cookie 充当使用系统的身份验证令牌。我不想在此处解决正确实现 Cookie 作为登录令牌的问题。只需说 Cookie 需要进行加密签名,以确保它们不会被篡改,并且必须仅在服务器验证有效的密码或其他信息后才能颁发。我在此处解决的 Cookie 的两个问题是:它们的范围应该有多大,以及它们的有效期应该有多长?

Cookie 的范围是指它可以访问多少服务。从用户的角度来看,公司​​的整个网站代表一个单一的应用程序。例如,如果一家公司提供电子邮件、日历、博客和产品评论,用户希望登录一次,然后能够平等地访问所有这些系统。对于每个子系统(例如邮件、日历、博客和评论)都必须输入密码,这被认为是一种糟糕的用户体验,并且是无法容忍的。

过于严格地定义 Cookie 并要求用户更频繁地输入密码还存在其他风险。网络钓鱼如此成功的原因之一是用户已经习惯于在响应特定页面时输入密码。只要用户看到一个看起来类似于登录页面的页面,他们就会输入密码。研究表明,即使是精通计算机的用户也可能被精心构建的虚假登录页面所愚弄。1 用户输入密码的频率越高,他们被钓鱼的风险就越高。大多数大型服务都允许用户登录一次,然后在整个站点中漫游一段时间。只有当用户做了一些被认为更严重的事情,例如购买产品时,他们才会被再次要求通过输入密码来证明自己的身份。

决定 Cookie 的有效期也是一个安全问题。显然,仅使 Cookie 在一次事务中有效是荒谬且令人恼火的,每次页面转换都需要密码。在频谱的另一端,使 Cookie 永远有效同样是荒谬的,因为存在被盗和滥用的可能性。

Cookie 范围和生命周期的问题尚未解决。然而,大多数网站都有自己的经验法则,他们试图保持内部一致性。

请求伪造

一旦用户登录,他们的浏览器忠实地在每个请求中向服务器发送他们的 Cookie,就会出现另一个问题。如果用户能够修改他们在使用的站点上的数据怎么办?例如,他们可能正在撰写餐厅评论或博客条目,甚至更改他们的密码。如果用于执行更新的服务的 URL 很容易被猜到,那么用户就容易受到请求伪造的攻击。

在请求伪造攻击中,攻击者创建一个 URL,当用户单击该 URL 时,将导致用户的帐户发生某些事情。想象一个博客系统,要删除一个条目,用户会发布一个 URL,例如 http://myblog.com/username/delete=blogentry ,其中 username 是用户的用户名,blogentry 是一个数字。

想要删除受害者博客条目的攻击者只需要使用受害者的真实用户名(通常在博客上可见)和适当的博客条目编号插入来制作 URL,然后诱骗受害者提交该 URL。攻击者可以向受害者发送一个 URL,如下所示,或将其放置在受害者可能阅读的网页中:<a img=http://myblog.com/victim/delete=blogentry> 用户看不到任何内容,但如果此图像标签成功部署在 myblog.com 站点上的页面中,并且用户查看了它,则博客条目将被删除。

服务器需要一种方法来确定用户是否真的打算采取行动。一种方法是在此类操作中再次请求密码,或者服务器可以以某种方式使每个 URL 唯一,通常通过要求生成签名并将其放入代表用户采取操作的任何 URL 中。

Javascript

到目前为止我们一直在谈论的挑战存在于 20 世纪 90 年代的静态 Web 内容中,但与过去十年的动态 Web 相关的一系列更棘手的问题。过去只是将静态 HTML 页面提供给浏览器,但现在代码实际上是在浏览器中执行的。

此代码通常用 JavaScript 编写,JavaScript 是一种解释型语言,浏览器在向用户显示页面时执行该语言。几乎所有可以在 Web 或任何高级 UI 技巧中看到的有趣内容都是使用从 Web 服务器下载并在浏览器中运行的 JavaScript 代码片段执行的。JavaScript 几乎可以做任何事情,包括查看用户正在查看的页面中的所有数据——毕竟,它被设计用于操作页面并使其看起来更有趣。JavaScript 还可以抓取和操作用户的 Cookie 和其他元数据。

浏览器在执行 JavaScript 时并不遵循与设置 Cookie 相同的限制。浏览器将接受来自页面告诉它的任何位置的 JavaScript。

与 Cookie 不同,JavaScript 不遵守基于站点域名的安全模型。一旦一段 JavaScript 控制了您的浏览器,它就可以在它喜欢的任何域中做任何事情,无论代码是从哪里提供的还是从哪里发出其他请求。

JavaScript 的风险之一是公司必须信任它提供给用户的内容。提供第三方 JavaScript 的公司正在对其站点承担严重风险,因为如果第三方 JavaScript 是恶意的,或者只是包含错误,这些问题将直接影响到每个访问该页面的用户。正如下一节解释的那样,问题不仅仅是第三方提供 JavaScript。现在许多站点允许用户通过向其页面添加 JavaScript 来自定义他们的页面。

用户生成内容

大多数以编写 JavaScript 为生的人都不是恶意软件作者,尽管他们会犯错误,但他们真诚地希望把事情做好。Web 站点现在面临的最大挑战是使 UGC 安全。

过去几年,允许用户上传和共享内容的站点激增。无论是博客条目、评论、音频、JavaScript、照片还是视频,所有这些数据类型都是由用户生成的,然后与全球成千上万甚至数百万的其他用户共享。让人工编辑在所有用户上传的所有内容被推送到网络上之前进行审查是不可能的。病毒扫描软件和其他基于黑名单的解决方案只能做到这一步,因为扫描软件需要不断更新新的签名,以防止新的攻击传播。

您可能会认为,只要代码不在用户之间共享,病毒就没有传播的方式,但是随着 JPEG 病毒(存在于 JPEG 编码图片的标头中)的出现,即使允许用户上传照片也为病毒提供了传播途径。允许用户使用 JavaScript 自定义其页面外观的站点很容易成为用该语言编写的病毒和蠕虫的目标。任何希望允许用户上传和共享数据的站点面临的挑战是如何安全地做到这一点,以及如何保护用户免受彼此的侵害。

UGC 挑战有一系列解决方案。第一个很简单:不允许任何 UGC,放弃将其作为服务的一部分。许多大型站点实际上确实排除了部分或全部 UGC,但市场压力是使用更多 UGC。那些允许 UGC 的站点会看到他们的受欢迎程度以及市场价值增加。

现在大多数站点都允许某种形式的 UGC,聪明的站点通过对用户可以上传的允许内容进行非常严格的白名单来实现这一点。这些白名单可以采用多种形式。如果 UGC 是 HTML 数据形式——例如,在线评论——那么用户在文本中可以使用的标签受到限制。他们通常被允许使用粗体、下划线、斜体和其他简单的格式属性,但他们不允许上传完整的 HTML 或使用 script 标签。在照片共享的情况下,照片在上传时可以进行编程调整大小,这会破坏用户在 JPEG 标头中拥有的任何数据。为了防止人们在视频共享站点上发起拒绝服务攻击,上传的视频在大小上受到限制。每种类型的 UGC 都必须根据具体情况进行处理。适用于照片的方法可能不适用于视频,反之亦然。

决定如何处理 UGC 类似于决定本文中提到的任何挑战。您所做的事情在很大程度上取决于您的系统想要做什么以及您需要保护哪些数据。如果用户最终将 Cookie 作为其身份验证机制,那么您不能允许他们上传 JavaScript,因为他们将能够以编程方式窃取 Cookie,从而获得对其他用户数据的控制权。

未来展望

此时,您可能会想拔掉计算机的电源插头并将其扔掉,但这不是一个很有成效的解决方案。事实是,Web 以及作为其基础的 Internet 被设计为一个协作系统,供大多数情况下会表现良好且不会恶意行事的人们使用。我们现在早已过了那些设计原则有意义的时代。使 Web 成为一个更安全的系统,人们可以并且想要每天使用的系统,需要一些在最初设计中遗漏的功能。

当用户查看网页时,谁可以对谁做什么的更好模型是朝着正确方向迈出的一步。浏览器安全模型依赖于域名来决定谁接收用户的元数据,这可能对于使应用程序比现在更复杂来说过于粗糙。每个混搭都是等待发生的安全性大杂烩。人们仍在为 Web 设计新系统,这些系统实际上试图绕过有限的浏览器安全模型,允许从一个域无限制地访问另一个域中的数据。这显然朝着错误的方向发展。

仅仅依赖 Cookie——特别是那些范围全局到整个网站域的 Cookie——对于具有多个服务的系统来说效果不佳。现在是时候找到一种在无会话协议(即 HTTP 请求)中实现会话的新方法了。找到一种防止请求伪造的好方法必须是为会话问题提出的任何解决方案的组成部分。

RIA(富 Internet 应用程序)是 Web 上安全问题的下一个前沿领域,其中更多的工作是在浏览器中使用 JavaScript 或 Flash 完成的。当源代码下载到浏览器并在浏览器中可见时,诸如输入验证和防止恶意数据进入用户工作区之类的问题变得更加困难。对于程序员来说,确保任何敏感数据在应用程序对其采取操作之前都由服务器验证,这一点非常重要。

UGC 的问题将继续存在,因为这是 Web 的发展方向,无法处理 UGC 服务的站点将被能够处理 UGC 服务的站点超越。现在和将来最需要的解决方案是那些允许用户安全地生成和共享内容的解决方案。

参考文献

1. Dhamija, R., Tygar, J.D., Hearst, M. 2006. 为什么网络钓鱼有效。《人机交互计算系统 SIGCHI 会议论文集》:581-590。

乔治·V·内维尔-尼尔是一位网络和操作系统代码顾问。他还教授与编程相关的各种主题的课程。他的兴趣领域是代码探秘和操作系统。他获得了马萨诸塞州波士顿东北大学计算机科学学士学位,并且是 、Usenix 协会和 IEEE 的成员。他是一位狂热的自行车爱好者和旅行者,自 1990 年以来一直以旧金山为家。

acmqueue

最初发表于 Queue vol. 5, no. 5
数字图书馆 中评论本文





更多相关文章

Shylaja Nukala, Vivek Rau - 为什么 SRE 文档很重要
SRE(站点可靠性工程)是一种职位职能、一种思维模式以及一套工程方法,用于使 Web 产品和服务可靠地运行。SRE 在软件开发和系统工程的交叉点运作,以解决运营问题并设计解决方案,从而可扩展、可靠且高效地设计、构建和运行大规模分布式系统。成熟的 SRE 团队可能拥有与许多 SRE 功能相关的明确定义的文档体系。


Taylor Savage - 组件化 Web
如今,在软件工程中,没有哪项任务像 Web 开发那样艰巨。Web 应用程序的典型规范可能如下:该应用程序必须跨各种浏览器工作。它必须以 60 fps 的速度运行动画。它必须对触摸立即响应。它必须符合特定的一组设计原则和规范。它必须在几乎所有可以想象到的屏幕尺寸上工作,从电视和 30 英寸显示器到手机和手表表面。它必须在长期内得到良好的工程设计和可维护性。


Arie van Deursen - 超越页面对象:使用状态对象测试 Web 应用程序
Web 应用程序的端到端测试通常涉及通过 Selenium WebDriver 等框架与 Web 页面进行棘手的交互。隐藏此类 Web 页面复杂性的推荐方法是使用页面对象,但首先需要回答一些问题:在测试 Web 应用程序时,您应该创建哪些页面对象?您应该在页面对象中包含哪些操作?给定您的页面对象,您应该指定哪些测试场景?


Rich Harris - 消除准入门槛
一场战争正在 Web 开发世界中进行。一方面是工具制造者和工具使用者的先锋,他们依靠对糟糕的旧观念的破坏(在他们看来,“旧”意味着任何在一个多月前在 Hacker News 上首次亮相的东西)以及关于转译器等的热烈辩论而蓬勃发展。





© 保留所有权利。

© . All rights reserved.