隱私

瀏覽器端檔案轉換:運作原理及為何你的檔案始終私密

koboshiCo-founder
·2 分鐘閱讀
瀏覽器端檔案轉換:運作原理及為何你的檔案始終私密
概述

基於伺服器的轉換器要求你把檔案上傳到別人的機器上。瀏覽器端轉換器使用 WebAssembly 和平台 API 完全在你的裝置上執行。本文詳解使這一切成為可能的架構,以及它對隱私意味著什麼。

把檔案上傳到一個基於伺服器的轉換器,三件事會發生。你的檔案透過網路傳輸到你無法控制的某個 IP 位址。伺服器上的某個行程解碼它。然後,取決於網站的保留政策,檔案會留在磁碟上——短則幾分鐘,長則永久。

同樣的事情在瀏覽器分頁裡做,檔案不會離開你機器的記憶體。解碼器執行在瀏覽器引擎強制執行的 WebAssembly 沙箱內。網路從未被觸及。

這不僅是政策差異,更是架構差異。基於伺服器的轉換器可以承諾刪除你的檔案;瀏覽器端的轉換器無法洩漏你的檔案,因為它從一開始就從未收到過它們。

架構

用戶端轉換由四個層次組成:

第 1 層:檔案存取

當你拖放一個檔案到瀏覽器分頁時,DragEvent<input type="file"> 會給 JavaScript 一個 File 物件。File 不是檔案的內容,而是一個參照:包含檔名、大小、MIME 類型,以及一個按需從磁碟讀取位元組到記憶體的方法(file.arrayBuffer())。

在這個方法被呼叫之前,零位元組被移動。檔案安靜地躺在你的檔案系統裡。瀏覽器的檔案選擇器是作業系統級別的對話框,網頁只能看到使用者明確選擇的 File 物件。

第 2 層:格式偵測

任何檔案的前幾個位元組都能可靠地標識其格式。JPEG 以 FF D8 FF 開頭。PNG 以 89 50 4E 47 開頭。HEIC 檔案包含一個 ftyp box,在位移 8 處帶有 heicheif 品牌標記。

讀取檔案頭(通常是前 32 個位元組)足以確認它到底是什麼,無論副檔名是什麼。這項檢查在任何解碼器接觸像素資料之前執行。如果檔案頭不匹配,檔案立即被拒絕。沒有浪費的 CPU 週期,也不會在解碼到一半時彈出令人困惑的錯誤訊息。

第 3 層:解碼

原始位元組透過解碼器變成像素。用哪個解碼器取決於格式:

  • JPEG、PNG、WebP、BMP:瀏覽器自帶這些格式的原生解碼器。createImageBitmap() 將壓縮位元組交給作業系統的編解碼器(Windows 上是 Windows Imaging Component,macOS 上是 Core Graphics,Linux/ChromeOS 上是 Skia),返回原始像素資料。這條路徑速度快,在作業系統支援的地方有硬體加速,且不需要額外程式碼。
  • HEIC:除 Safari 外,沒有瀏覽器自帶 HEIC 原生解碼器。我們的轉換器內建了 libheif——一個編譯為 WebAssembly 的 C 函式庫。.wasm 二進位檔案(~1.2 MB 壓縮後)下載一次後快取。它在 WASM 沙箱內將 HEIF/HEIC 檔案解碼為原始 RGB 像素。
  • PDF:PDF.js(Mozilla 的 PDF 渲染器)將每一頁以請求的解析度渲染到畫布。沒有伺服器端渲染。PDF 從未離開瀏覽器。

每個解碼器從記憶體讀取、向記憶體寫入。沒有解碼器會開啟 socket。WASM 沙箱尤其無法發起網路請求:瀏覽器不會向 WebAssembly 模組暴露網路 API。即使 C 程式碼呼叫了 socket(),沙箱也會攔截它。

第 4 層:編碼

原始像素進入 <canvas> 元素的 2D 上下文。canvas.toBlob()canvas.toDataURL() 呼叫瀏覽器的內建編碼器輸出 JPG、PNG 或 WebP。編碼器是平台原生程式碼:和你的作業系統儲存截圖用的是同一條程式碼路徑。

輸出是一個 Blob——記憶體中的位元組緩衝區。它被交給下載連結,或者封裝進一個用 JavaScript 構建的 ZIP 壓縮檔。在整個過程中,沒有任何位元組觸碰到網路 socket。

瀏覽器強制執行了什麼

網頁執行在瀏覽器於引擎層面維護的沙箱內。這不是禮貌協議,而是由行程隔離強制執行的:

渲染器行程:JavaScript 引擎、DOM 和 WASM 執行時期執行在一個沙箱化行程中,沒有直接的檔案系統或網路存取權限。它透過 IPC 與瀏覽器行程通訊。

站點隔離:現代瀏覽器將每個來源放在自己獨立的渲染器行程中。你在 file-convert-factory.org 中的檔案對於執行在任何其他域名上的 JavaScript 是不可見的。

WASM 沙箱:WebAssembly 模組只能看到一塊平坦的線性記憶體緩衝區,別無他物。沒有檔案系統 API,沒有 fetch(除非 JavaScript 顯式匯入),沒有存取 DOM 或其他瀏覽器 API 的權限。一個被攻破的 WASM 模組最壞的情況是破壞自己的記憶體,讓分頁崩潰。

相比之下,基於伺服器的轉換器以特權行程執行在伺服器的作業系統上。它可以讀磁碟、寫磁碟、開啟網路連線、派生子行程。安全模型取決於伺服器營運者的能力和意圖。瀏覽器沙箱只取決於瀏覽器引擎的正確性,而瀏覽器沙箱是軟體領域中被審計最嚴格的安全邊界之一。

基於伺服器的轉換器承諾(和不承諾)什麼

基於伺服器的轉換器本身並不惡毒。很多是由善意的團隊營運的。問題出在結構上:

  1. 上傳步驟就是一次複製。你的檔案現在存在於兩個地方。你控制一個副本,別人控制另一個。
  2. 刪除是一個承諾。「我們 24 小時後刪除檔案」意味著你要信任那行日誌、那個定時工作、備份系統和每個有伺服器權限的員工。這些都無法從外部驗證。
  3. 元數據隨檔案一同傳輸。你照片的 EXIF 資料(GPS 座標、相機序號、時間戳)屬於檔案位元組的一部分。檔案上傳了,元數據也就上傳了。我們的 EXIF 隱私指南詳細介紹了裡面到底有什麼以及如何去除。簡單來說:本站的每個轉換器都會去除元數據,因為它解碼像素再重新編碼,丟棄了所有不屬於影像資料的內容。
  4. HTTPS 保護的是傳輸管道,不是端點。TLS 加密上傳過程中的資料,但對於檔案到達後發生的事情無能為力。

瀏覽器端轉換器的隱私保證更窄但更強。它說的是:你的檔案不會離開你的裝置,因為不存在讓它們離開的程式碼路徑。這是可驗證的。轉換檔案時開啟 DevTools 的 Network(網路)面板,你會看到 WASM 二進位檔案載入一次後就再也沒有任何網路請求。零位元組上傳。沒有對 /api/convert 的請求。沒有 WebSocket 流量。轉換完全在渲染器行程內發生。

親自驗證

你不必相信任何人的說辭。開啟 Chrome DevTools(F12),切換到 Network 面板,然後在任何工具頁面上轉換一個檔案。你能看到的唯一網路活動:

  1. 頁面 HTML、CSS 和 JavaScript:首次存取時載入一次。
  2. WASM 二進位檔案(針對 HEIC 轉換器):載入一次,之後快取。
  3. 分析請求(如果你沒有封鎖的話)。

沒有任何檔案資料離開瀏覽器。每個請求的 Content-Length 單位是 KB,不是 MB。任何會用 DevTools 的人都可以獨立驗證這一點。

對於基於伺服器的服務,你無法做同樣的斷言。你上傳檔案,得到結果,然後你只能相信伺服器確實刪除了它。

相關工具

本站的每一個轉換器都遵循這套架構。管線(拖放、驗證、解碼、編碼、下載)在所有 23 個工具上執行方式完全一致:

關於 WASM 沙箱的技術細節,參見我們的 WebAssembly 詳解。想深入了解你照片攜帶了什麼元數據,EXIF 隱私指南會逐位元組地教你讀取和去除它們。

更多推薦閱讀