JavaScript 的陷阱

一个网页可能犯两种道德错误。本页描述了将非自由程序发送到您的计算机上运行的错误。还有一种错误我们称之为 SaaSS,“软件替代服务”,即页面邀请您发送您的数据,以便它可以在服务器上进行计算 —— 这种计算是不公正的,因为您无法控制所进行的计算。

您可能每天都在您的计算机上运行非自由程序而没有意识到 —— 通过您的网络浏览器。

在自由软件社区中,任何非自由程序都会虐待其用户的想法是众所周知的。我们中的一些人通过拒绝我们计算机上的所有专有软件来捍卫我们的自由。许多其他人也认识到非自由是反对该程序的理由。

许多用户都知道这个问题适用于浏览器提供的安装插件,因为它们可以是自由的或非自由的。但是浏览器会运行其他非自由程序,它们不会询问您,甚至不会告诉您 —— 这些程序是网页包含的或链接到的。这些程序通常用 JavaScript 编写,尽管也使用其他语言。

JavaScript(官方称为 ECMAScript,但很少有人使用这个名称)曾经用于网页中的次要装饰,例如可爱但无关紧要的导航和显示功能。将这些视为 HTML 标记的简单扩展而不是真正的软件,并忽略这个问题是可以接受的。

一些网站仍然以这种方式使用 JavaScript,但许多网站将其用于执行大型工作的主要程序。例如,Google Docs 尝试在您的浏览器中安装一个 JavaScript 程序,该程序的大小为半兆字节,采用我们可以称为混淆脚本的压缩形式。这种压缩形式是通过删除使代码可读的额外空格以及使代码可理解的解释性备注,并将代码中每个有意义的名称替换为任意短名称来使其无法得知其含义,从而从源代码生成的。

自由软件的含义之一是用户可以访问程序的源代码(其计划)。程序的源代码是指程序员修改的首选形式 —— 包括有用的空格、解释性备注和有意义的名称。压缩代码是源代码的虚假、无用的替代品;这些程序的真实源代码对用户不可用,因此用户无法理解它;因此,这些程序是非自由的。

除了是非自由的之外,许多这些程序还是恶意软件,因为它们会窥探用户。更令人讨厌的是,一些网站使用服务来记录用户在查看页面时的所有操作。这些服务据称会“编辑”录音,以排除网站不应获取的一些敏感数据。但是,即使这样可靠地工作,这些服务的全部目的也是向网站提供其不应获取的其他个人数据。

浏览器通常不会在加载 JavaScript 程序时通知您。一些浏览器提供完全关闭 JavaScript 的方法,但即使您意识到这个问题,也需要花费大量精力来识别重要的非自由程序并阻止它们。然而,即使在自由软件社区中,大多数用户也没有意识到这个问题;浏览器的沉默倾向于掩盖它。

需要明确的是,JavaScript 语言本身在用户自由方面并不比任何其他语言更好或更差。通过在自由软件许可下分发源代码,可以将 JavaScript 程序作为自由软件发布。如果程序是自包含的 —— 如果它的功能和目的是独立于它所在的页面的 —— 那就很好;您可以将其复制到计算机上的文件中,对其进行修改,并使用浏览器访问该文件来运行它。甚至可以像其他自由程序一样将其打包以进行安装,并使用 shell 命令调用。这些程序不存在与 C 程序不同的特殊道德问题。

当 JavaScript 程序随用户访问的网页一起出现时,就会出现 JavaScript 陷阱的问题。这些 JavaScript 程序被编写为与特定页面或站点一起工作,并且该页面或站点依赖于它们才能运行。

假设您复制并修改了页面的 JavaScript 代码。那么就会出现另一个问题:即使程序的源代码可用,浏览器也没有提供在访问该页面或站点时运行您的修改版本而不是原始版本的方法。效果类似于 tivo 化,尽管原则上并非如此难以克服。

JavaScript 并不是网站用来发送给用户的程序的唯一语言。Flash 通过 JavaScript 的扩展变体支持编程,但那已成为过去。Microsoft Silverlight 似乎可能会造成类似于 Flash 的问题,而且更糟,因为 Microsoft 将其用作非自由编解码器的平台。除非它通常带有自由的替代编解码器,否则 Silverlight 的自由替代品无法充分满足自由世界的需求。

Java 小程序也在浏览器中运行,并引发类似的问题。通常,任何类型的小程序系统都会出现此类问题。拥有小程序的自由执行环境只是让我们遇到了这个问题。

理论上可以使用 HTML 和 CSS 进行编程,但在实践中,这种能力是有限且不方便的;仅仅让它做一些事情就是一项令人印象深刻的技巧。此类程序应该是自由的,但截至 2019 年,CSS 对用户的自由并不是一个严重的问题。

已经形成了一个强大的运动,呼吁网站仅通过自由(有些人说“开放”)的格式和协议进行通信;也就是说,其文档已发布,并且任何人都可以自由实施。但是,网页中 JavaScript 程序的存在使该标准不足以满足要求。JavaScript 语言本身作为一种格式是自由的,并且在网站中使用 JavaScript 不一定不好。但是,如上所述,它可能是坏的 —— 如果 JavaScript 程序是非自由的。当站点向用户传输程序时,仅程序用有文档且不受约束的语言编写是不够的;该程序也必须是自由的。“仅向用户传输自由程序”必须成为道德网站的标准之一。

在“Web 应用程序”引发的几个问题中,静默加载和运行非自由程序只是其中之一。“Web 应用程序”一词旨在忽略交付给用户的软件和在服务器上运行的软件之间的根本区别。它可以指在浏览器中运行的专用客户端程序;它可以指专用服务器软件;它可以指与专用服务器软件携手工作的专用客户端程序。客户端和服务器端会引发不同的道德问题,即使它们紧密集成以至于可以被认为是单个程序的一部分。本文仅讨论客户端软件的问题。我们正在单独讨论服务器问题。

在实际操作中,我们如何处理网站中重要的非自由 JavaScript 程序的问题?第一步是避免运行它。

我们所说的“重要”是什么意思?这是一个程度问题,因此这是设计一个能产生良好结果的简单标准,而不是找到唯一正确答案的问题。

我们当前的标准是,如果满足以下任何条件,则将 JavaScript 程序视为重要的

  • 它被称为外部脚本(来自另一个页面)。
  • 它声明一个长度超过 50 个元素的数组。
  • 它定义了一个命名实体(函数或方法),该实体调用除基元之外的任何内容。
  • 它定义了一个包含三个以上条件结构和循环结构的命名实体。
  • 命名定义之外的代码调用除基元和页面中更早定义的函数之外的任何内容。
  • 命名定义之外的代码总共包含三个以上的条件结构和循环结构。
  • 它调用 eval
  • 它执行 Ajax 调用。
  • 它使用方括号表示法进行动态对象属性访问,看起来像 object[property]
  • 它会更改 DOM。
  • 它使用难以在不解释程序的情况下进行分析的动态 JavaScript 构造,或者与使用此类构造的脚本一起加载。具体来说,使用除带有某些方法的字符串文字之外的任何其他构造 (Obj.writeObj.createElement 等)。

我们如何判断 JavaScript 代码是否自由?在另一篇文章中,我们提出了一种方法,网页中重要的 JavaScript 程序可以通过该方法声明其源代码所在的 URL,并使用风格化的注释声明其许可证。

最后,我们需要更改自由浏览器以检测并阻止网页中重要的非自由 JavaScript。程序 LibreJS 会检测您访问的页面中非自由的重要 JavaScript,并阻止它。LibreJS 包含在 IceCat 中,并可作为 Firefox 的附加组件使用。

浏览器用户还需要一个方便的功能来指定要使用的 JavaScript 代码,而不是某个页面中的 JavaScript。(指定的代码可能是完全替换,也可能是该页面中自由 JavaScript 程序的修改版本。)Greasemonkey 几乎可以做到这一点,但并非完全如此,因为它不能保证在该程序开始执行之前修改页面中的 JavaScript 代码。使用本地代理可以工作,但现在太不方便而不能成为真正的解决方案。我们需要构建一个可靠且方便的解决方案,以及共享更改的站点。GNU 项目希望推荐仅用于自由更改的站点。

这些特性将使得网页中包含的 JavaScript 程序在真实和实际的意义上是自由的。JavaScript 将不再是我们自由的特定障碍——就像 C 和 Java 现在不是障碍一样。我们将能够拒绝甚至替换非自由的、重要的 JavaScript 程序,就像我们拒绝和替换通常提供安装的非自由软件包一样。然后,我们就可以开始我们要求网站释放其 JavaScript 的行动。

同时,有一种情况下可以接受运行非自由的 JavaScript 程序:向网站运营商发送投诉,说明他们应该释放或删除网站中的 JavaScript 代码。请不要犹豫,暂时启用 JavaScript 来执行此操作,但请记住之后再次禁用它。

致谢: 感谢 Matt LeeJohn Resig 帮助我们定义了我们提出的标准,以及 David Parunakian 提醒我注意这个问题。