JavaScript 陷阱

網頁可能犯下兩種道德上的錯誤。本頁面描述的是傳送非自由程式到您的電腦上執行的錯誤。還有一種我們稱之為 SaaSS,「服務即軟體替代品」的錯誤,網頁邀請您傳送您的資料,以便它可以在伺服器上進行運算——這種運算是不公正的,因為您無法控制運算的內容。

您可能每天都在您的電腦上執行非自由程式而沒有意識到——透過您的網路瀏覽器。

在自由軟體社群中,任何非自由程式都會虐待其使用者這個觀念是眾所周知的。我們有些人透過拒絕我們電腦上的所有專有軟體來捍衛我們的自由。許多其他人則將非自由性視為該程式的一個缺點。

許多使用者都知道這個問題適用於瀏覽器提供的外掛程式,因為它們可能是自由或非自由的。但是瀏覽器還執行其他非自由程式,它們不會詢問您,甚至不會告訴您——網頁包含或連結到的程式。這些程式通常以 JavaScript 撰寫,但也使用其他語言。

JavaScript(正式名稱為 ECMAScript,但很少人使用這個名稱)曾經用於網頁中的次要裝飾,例如可愛但非必要的導覽和顯示功能。將這些視為 HTML 標記的簡單擴展,而不是真正的軟體,並忽略這個問題是可以接受的。

有些網站仍然以這種方式使用 JavaScript,但許多網站將其用於執行大型工作的主要程式。例如,Google 文件嘗試在您的瀏覽器中安裝一個 JavaScript 程式,該程式的大小為半兆位元組,以一種我們可以稱之為 Obfuscript 的壓縮形式。這種壓縮形式是從原始碼建立的,方法是刪除使程式碼可讀的額外空格和使程式碼可理解的解釋性註解,並將程式碼中每個有意義的名稱替換為任意的短名稱,以便我們無法判斷它應該是什麼意思。

自由軟體的意義之一是使用者可以存取程式的原始碼(其計畫)。程式的原始碼意味著程式設計師修改的首選形式——包括有用的間距、解釋性註解和有意義的名稱。壓縮程式碼是原始碼的虛假、無用的替代品;這些程式的真正原始碼使用者無法取得,因此使用者無法理解它;因此這些程式是非自由的。

除了非自由之外,這些程式中還有許多是惡意軟體,因為它們窺探使用者。更糟糕的是,有些網站使用服務來記錄使用者在瀏覽頁面時的所有操作。這些服務據說會「編輯」錄音,以排除網站不應取得的一些敏感資料。但即使這樣做可靠地運作,這些服務的全部目的也是為了向網站提供網站不應取得的其他個人資料。

瀏覽器通常不會告訴您它們何時載入 JavaScript 程式。有些瀏覽器有完全關閉 JavaScript 的方法,但即使您意識到這個問題,也需要花費相當大的力氣來識別重要的非自由程式並封鎖它們。然而,即使在自由軟體社群中,大多數使用者也沒有意識到這個問題;瀏覽器的沉默往往會掩蓋它。

需要澄清的是,JavaScript 語言本身對於使用者的自由而言,並不比任何其他語言更好或更差。可以透過在自由軟體授權條款下發布原始碼來將 JavaScript 程式作為自由軟體發布。如果程式是獨立的——如果它的功能和目的是獨立於它所在的頁面——那就沒問題;您可以將其複製到您電腦上的檔案中,修改它,並使用瀏覽器造訪該檔案來執行它。甚至可以像其他自由程式一樣將其封裝以進行安裝,並使用 shell 命令調用它。這些程式提出的道德問題與 C 程式沒有什麼特別不同。

JavaScript 陷阱的問題適用於 JavaScript 程式與使用者造訪的網頁一起出現的情況。這些 JavaScript 程式是為了與特定的頁面或網站一起運作而編寫的,而頁面或網站依賴它們才能運作。

假設您複製並修改了頁面的 JavaScript 程式碼。然後會出現另一個問題:即使程式的原始碼可用,瀏覽器也不提供在造訪該頁面或網站時執行您修改後的版本而不是原始版本的方法。這種效果與 tivoization 類似,儘管原則上並非那麼難以克服。

JavaScript 不是網站用於傳送給使用者的程式的唯一語言。Flash 透過 JavaScript 的擴展變體支援程式設計,但那已成為過去。Microsoft Silverlight 似乎可能會產生與 Flash 類似的問題,甚至更糟,因為 Microsoft 將其用作非自由編解碼器的平台。除非自由世界通常附帶免費的替代編解碼器,否則 Silverlight 的免費替代品無法充分勝任自由世界的工作。

Java applet 也會在瀏覽器中執行,並引發類似的問題。一般來說,任何類型的 applet 系統都會造成這類問題。擁有 applet 的自由執行環境只會讓我們勉強足以遇到這個問題。

理論上可以用 HTML 和 CSS 進行程式設計,但實際上這種能力有限且不方便;僅僅讓它做一些事情就是一個令人印象深刻的駭客技巧。這些程式應該是自由的,但截至 2019 年,CSS 對於使用者的自由來說並不是一個嚴重的問題。

一項強大的運動已經興起,呼籲網站僅透過自由(有些人說是「開放」)的格式和協定進行通訊;也就是說,其文件已發布,並且任何人都可以自由實作。然而,網頁中 JavaScript 程式的存在使得該標準不足。JavaScript 語言本身作為一種格式是自由的,並且在網站中使用 JavaScript 不一定是不好的。但是,正如我們上面所看到的,如果 JavaScript 程式是非自由的,那它就可能是糟糕的。當網站將程式傳輸給使用者時,僅僅程式以已記錄且不受約束的語言編寫是不夠的;該程式也必須是自由的。「僅向使用者傳輸自由程式」必須成為道德網站的標準之一。

靜默載入和執行非自由程式是「網路應用程式」引發的幾個問題之一。「網路應用程式」這個術語的設計目的是為了無視傳遞給使用者的軟體和在伺服器上執行的軟體之間的根本區別。它可以指在瀏覽器中執行的專用客戶端程式;它可以指專用伺服器軟體;它可以指與專用伺服器軟體密切合作的專用客戶端程式。即使客戶端和伺服器端緊密整合到可以被認為是單一程式的一部分,它們也會引發不同的道德問題。本文僅討論客戶端軟體的問題。我們將另行討論伺服器問題。

實際上,我們如何處理網站中重要的非自由 JavaScript 程式的問題?第一步是避免執行它。

我們所說的「重要」是什麼意思?這是一個程度問題,所以這是一個設計一個能產生良好結果的簡單標準的問題,而不是找到唯一的正確答案。

我們目前的標準是,如果符合以下任何條件,則將 JavaScript 程式視為重要

  • 它被稱為外部腳本(來自另一個頁面)。
  • 它宣告一個長度超過 50 個元素的陣列。
  • 它定義一個具名實體(函數或方法),該實體調用任何非原始類型。
  • 它定義一個具有超過三個條件結構和迴圈結構的具名實體。
  • 具名定義之外的程式碼調用任何非原始類型和在頁面更上方定義的函數。
  • 具名定義之外的程式碼總共包含超過三個條件結構和迴圈結構。
  • 它調用 eval
  • 它執行 Ajax 調用。
  • 它使用方括號表示法進行動態物件屬性存取,看起來像 物件[屬性]
  • 它更改 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 讓我注意到這個問題。