Websecurify – 经验与技术选择

几年前,当我推出 @websecurify 时,我编写了大量的 JavaScript、原生代码和 XUL,但如今 Websecurify 中使用的技术组合是由一种编译成 JavaScript 的自定义语言构成,它位于现代 HTML5 堆栈之上,并在您的普通浏览器中运行。听起来很疯狂,但不知何故,这感觉是正确的选择。

Websecurify default application launcher.

认识到 HTML5 已经准备好满足 Websecurify 的目标并非易事。我们当时进入了充满危险和权衡的未知领域。没有人尝试做我们想做的事情,这有点让人害怕。Websecurify 并非一蹴而就。它最初是一个桌面应用程序,多年来我们构建了一个可靠的框架,编写了数千行代码,并花费了大量时间修复和跟踪我们自己的算法以及当时 JavaScript 解释器中的错误。

当时还存在一个疑问,即是否真的可以用浏览器技术编写一个完整的安全测试框架——出于各种原因,浏览器实际上从未打算这样做。我们最终成功了,以下是一些促使我们采用 HTML5 的因素以及我们在过程中学到的一些东西。

JavaScript 及其作用

我们需要从 JavaScript 开始讲述这个故事——推动 Web 发展的语言。多年来,这种语言变得如此普遍,这很有趣。感觉就像昨天,JavaScript 只是用来创建花哨的悬停按钮和弹出窗口。我们选择 JavaScript 作为我们的漏洞测试平台,并不是因为我们知道它是一门很棒的语言,而是因为它原生于 Mozilla 的 Xulrunner,当时 Xulrunner 看起来像是一个可靠的跨平台桌面应用程序框架。

多年来,我们了解了关于 JavaScript 作为通用编程语言的一些令人不快的真相。首先,JavaScript 是一种脚本语言——这意味着它适合编写脚本。如果目的是将事物粘合在一起,那么使用 JavaScript 就足够了。对于大型应用程序,扩展到数千行代码,您将需要一种具有静态编译、类型系统以及所有其他功能的适当的编程语言。我们使用 JavaScript 遇到的障碍之一是垃圾回收。当您使用 JavaScript 编程时,您往往会考虑到闭包。几乎所有内容都作为函数内联。由于这种编程风格,在我们扫描技术的最初几个月,我们不断遇到 js 解释器的怪癖,这些怪癖很难调试。要么是解释器,要么是我们自己的代码没有保留足够的引用,导致各种意想不到的错误。

有时,这并非垃圾回收的影响,而是相反——内存泄漏。突然之间,我们分配的内存远远超过了我们想要使用的内存。该语言的动态特性也是一个障碍,因为永远不可能知道任何给定时间点所有对象的的状态是否正确。解决此问题的直接方法是编写单元测试,我们很乐意开始这样做,但这只在一定程度上解决了问题。即使在数千行单元测试之后,JavaScript 也未能达到我们的预期。

自定义语言

在我们处理意外错误的某个糟糕时期,我们决定用一种自定义语言替换 JavaScript,该语言为我们的需求和编程理念提供了足够的鲁棒性。这是一个实验,它源于绝望。我相信我们是第一批将 JavaScript 或多或少地视为汇编器而非实际通用编程语言的人之一。我们花了 3 个月时间开发第一个原型,结果非常出色。我们的 JavaScript 编译器的第一个版本本质上是一个经过美化的 grep。情况开始变得乐观起来,因为我们当时第一次拥有一个可以在标准 JavaScript 解释器上完整运行的 Web 应用程序安全框架。我们的 Web 安全扫描技术成熟了,我们推出了桌面产品的多个版本,以及一个使用 Objective-C 的自定义编译器构建的 iOS 安全测试工具。

如果不是因为缺乏对 Xulrunner 和 XUL 的支持,我们永远不会将 HTML5 视为替代方案。没错。XUL 是一个很棒的框架,但它以 Mozilla 为中心(几乎像 Java、Flash、Silverlight、ActiveX 和其他),并且缺乏任何支持,因为它从未打算在 Firefox 之外使用。XUL 是围绕关注点分离的设计原则构建的。国际化文件、样式、结构和代码都分别保存,并且覆盖层提供了根据需要扩展事物的最强大的方法。我仍然认为 XUL 和 XPCOM 是一个很棒的组合,也许是有史以来最强大的桌面编程框架,但它从未打算成为主流。

Mozilla 社区对 HTML5 作为下一代编程平台寄予厚望,在查看了一些正在进行的项目(如 B2G(现为 Firefox OS)、Chromeless 浏览器实验、Firefox for Android(完全原生)之后,我们开始意识到 XUL 可能很快就会被弃用,我们必须为未来考虑。我们决定采用 HTML5,这是一个严重的赌博。事实上,它疯狂到令人难以置信。

使用 HTML5

HTML5 最初有点困难。它确实缺乏任何原生的外观和感觉,但在思考了一段时间之后,我们意识到这实际上是一个优势而不是劣势。HTML5 缺乏国际化支持。它缺乏 XUL 的主题和覆盖功能,最初感觉相当不成熟和单调。它缺少 XBL。它当然不是 XML 语言。当您使用 HTML5 编程时,唯一的方法是自己构建所有内容,并以您希望的任何方式从头开始构建您的应用程序。

很难想象这将如何转化为我们的需求,但我们做到了。UI 是从头开始构建的,所有应用程序元素都封装在一个小型框架中。我们能否像以前使用 XUL 那样扩展 UI?绝对不能!但是,它更简单,也更不容易混淆。HTML5 渲染速度很快,并且对 Firefox 和 Chrome 都非常可靠,我们第一次看到了潜力。

我们拥有开始开发桌面软件的所有组件,但下一个需要解决的大问题是如何将 Web 应用程序安全扫描程序作为现代 Web 应用程序交付。这是一个难题。它之所以困难,是因为为了让扫描程序工作,您必须突破浏览器使用的安全模型,而浏览器不允许您这样做。我们并没有迷失方向,因为我们已经知道,最坏的情况是,我们将简单地嵌入一个浏览器渲染引擎并以本地方式编写其余代码,但我们希望将我们的下一代产品打造成 Firefox 和 Chrome 中的一等公民。

添加我们自己的 API

当然,我们无法使用浏览器提供的标准 API 来做到这一点,因此我们决定效仿 B2G 在 Firefox OS 中所做的事情,添加我们自己的 API,使我们的应用程序能够按照我们的意愿执行操作,同时仍然根据定义保持 Web 应用程序的特性。我们喜欢称这些增强为扩展,它们在浏览器和 Websecurify 之间提供了一层薄薄的层,我们自己的代码作为 Web 应用程序交付。扩展背后的机制很难描述,因此我将跳过这一部分。但是,可以肯定地说,我们的扩展证明易于维护,并提供了我们需要的浏览器支持功能,以便我们的浏览器内 Web 应用程序安全套件能够像您期望的桌面应用程序一样工作。

Websecurify operating as a proxy using the Firefox extension.

Websecurify Httpview,可通过 Websecurify Firefox 扩展完全访问浏览器 HTTP 流量。

HTML5 应用程序加上浏览器扩展证明是一个不错的组合。HTML5 应用程序负责交付机制,如您所知,它通过 Web 进行。它还简化了更新,因为我们不再需要等待数月才能推出更新,因为我们可以在日常工作中随时进行更新(我们今天仍在这样做)。我们编写的 HTML5 应用程序还意味着我们具有面向未来的特性,并且作为一家技术公司将继续存在,能够在以前未开发的领域采用、开拓和创新。另一方面,我们提供的浏览器扩展提供了急需的支持,可以超越现代浏览器的功能,而不会影响用户体验或安全性。结果非常出色。

结论

到目前为止,您一定在想我为什么要写所有这些东西。这个家伙的目的是什么?当我们开始编写基于 XUL 的应用程序时,我们一直希望将我们的框架贡献回 Mozilla,同时将我们的扫描技术保留给自己。我们认为这是一个不错的折衷方案。现在,由于上述所有原因,我们不再为 Xulrunner 开发,我们唯一可以分享的就是我们的经验,我相信从中可以学到很多东西。我们仍在努力寻找使旧 XUL 框架公开的最佳方法。

我想强调的主要一点是,尽管 JavaScript 和 HTML5 都有自己的障碍,但我们发现它们已经足够成熟,可以编写超越数据录入的优秀 Web 应用程序。这证明了 Web 应用程序已经足够成熟,可以用于各种应用程序,包括大型游戏、通常仅适用于各种原生平台的复杂软件等。我对未来充满期待,我相信未来会令人兴奋。

关于 Petko D. Petkov

Petko D. Petkov(又名 pdp)是 GNUCITIZEN 信息安全智库的创始人兼主要成员。他是一位公认的信息安全研究员、安全工具开发人员、渗透测试人员,经常在安全行业认可的活动中发表演讲,并且是已发表的作者,曾为几本畅销书、众多热门博客和在线杂志做出贡献。

Petko D. Petkov 的更多文章……

关于 Robert Nyman [荣誉编辑]

Mozilla Hacks 的技术布道师和编辑。就 HTML5、JavaScript 和开放 Web 发表演讲和博客。Robert 是 HTML5 和开放 Web 的坚定支持者,自 1999 年以来一直在从事 Web 前端开发工作——在瑞典和纽约市。他还定期在 http://robertnyman.com 上发表博客,并且喜欢旅行和结识新朋友。

Robert Nyman [荣誉编辑] 的更多文章……


4 条评论

  1. Michael Turnwall

    您是如何测试 JavaScript 的性能和内存泄漏的?我一直都在寻找类似的东西,但真的没有找到任何详细说明如何执行此操作的内容。现在我正在构建更重的基于 js 的网站,并尝试构建可以在网站之间重复使用的 js 类,因此测试 js 的性能变得至关重要。

    2013 年 1 月 31 日 00:35

  2. Michael Turnwall

    您使用什么工具测试 javascript 性能和内存使用情况?我从未找到真正详细介绍如何执行此操作的内容。现在我正在构建更重的 js 网站和可以在项目之间重复使用的类,因此测试性能和内存使用情况变得非常重要且必要。

    2013 年 1 月 31 日 00:38

  3. Petko D. Petkov

    您好,Michael,

    这是一个好问题,但没有简单的答案。Mozilla 提供了一些可以帮助您查找内存泄漏的工具(https://wiki.mozilla.org/Performance:Leak_Tools)。它们都不完美,老实说,除非您了解 Firefox 的内部结构和更低级别的编程,否则使用起来会非常困难。

    Chrome/Webkit 有一套不错的工具。实际上,我非常喜欢 Profiler。

    但是,大多数时候我都是手动并依靠直觉来查找内存泄漏。最简单的方法是将给定的代码包装到某种函数中并测量性能。您还可以将特殊字符串值放置在对象内部,并查看它们如何在您正在调试的进程的内存中传播。这是一个痛苦的过程。

    这是切换到全新语言的主要原因,该语言的设计旨在防止内存泄漏。虽然仍然可能发生内存泄漏,但发生的概率较低。我所能给出的最佳建议是稍微思考一下你的对象。一个好的方法是使几乎所有对象都不可变,这样你就无法更改它们的状态。此外,避免使用闭包。更简单、更不容易出错的方法是在全局作用域中调用函数(几乎像函数式编程语言)或使用对象。闭包非常方便,但也有代价。

    最后,如果可能,将你的代码移植到更多解释器上。这通常会揭示一些意想不到的行为。我们为 4 个不同的平台编写代码,并通过这种方式发现了许多问题。

    最后但并非最不重要的是,如果你正在使用任何内存泄漏检测工具,你确实需要知道你在寻找什么。否则,这些工具将毫无用处。

    2013年1月31日 02:56

    1. Michael Turnwall

      感谢你的回复,抱歉重复发帖了 :-)

      2013年1月31日 11:27

本文评论已关闭。