WebAssembly 的記憶體(以及它為什麼比你想的更安全)

Mozilla Taiwan
Aug 23, 2017 · 6 min read

WebAssembly 處理記憶體(memory)的方式和 JavaScript 不太一樣。WebAssembly 能讓你直接存取記憶體內的原始位元……而造成有些人擔心不夠安全。不過,WebAssembly 的做法其實比你想像得更安全。

什麼是記憶體物件?
當 WebAssembly 模組被實體化(instantiate)後,它會需要記憶體物件。你可建立和發送一個全新的 WebAssembly.Memory 物件。如果你不想這麼做的話,WebAssembly 還可自動產生一個記憶體物件,並將之附加於實體(instance)上。

所有的 JavaScript 引擎內部都會產生 ArrayBuffer(我在另一篇文章中已介紹過)。ArrayBuffer 是 JS 所參照的 JavaScript 物件。JS 會幫你配置記憶體。你只需告訴它要用多少記憶體,它就會建立符合該容量的 ArrayBuffer (陣列緩衝區)。

你可以把陣列(array)的索引(indexes)看成是記憶體的位址。如果你之後需要更多記憶體,你還能讓陣列「長大」(此作法稱為 growing)。

藉由把 WebAssembly 的記憶體當作 ArrayBuffer 來處理(也就是當成一個JavaScript 物件),你可達成兩個目的:

  1. 更輕鬆地在 JS 與 WebAssembly 之間傳遞 values
  2. 加強記憶體管理的安全性

在 JS 與 WebAssembly 之間傳遞值
因為 WebAssembly 的記憶體只是個 JavaScript 物件,所以,JavaScript 也可使用到此記憶體位元。如此一來,WebAssembly 和 JavaScript 便可共享記憶體,並且來回傳送值。

它們會使用陣列索引來存取陣列內的每一格,而不是使用記憶體位址。

例如,若 WebAssembly 要在記憶體中放入一個字串。它會把字串轉成位元編碼……

……然後,再把那些位元放入陣列。

之後,WebAssembly 會回傳第一個整數 (integer) 索引給 JavaScript,以便 JavaScript 擷取那些位元來使用。

由於 JavaScript 大多不知如何直接使用位元,所以你還需要幫 JavaScript 加點工,就像你幫 WebAssembly 這邊做的一樣,才能把位元轉換成更有用的值(如字串)。

在一些瀏覽器上,你可使用 TextDecoderTextEncoder APIs。或你也可在 .js 檔內加入補助函數。如果要增加編碼和解碼的補助函數,你可使用 Emscripten 這一類的工具。

這就是 WebAssembly 記憶體身為 JS 物件的第一個好處 —讓 WebAssembly 與 JavaScript 直接經由記憶體彼此傳送值。

把記憶體存取變得更安全
WebAssembly 記憶體只是 JS 物件的另一個好處是:安全。它能避免瀏覽器層級的記憶體洩漏,並能達成記憶體隔離,使得實作更安全。

記憶體洩漏(Memory leaks)
我在記憶體管理的文章中曾提過,如果自己管理記憶體的話,常常容易因為忘記清理記憶體,而造成系統記憶體不足的狀況。

如果 WebAssembly 模組可直接存取記憶體,萬一它也忘記在記憶體用光前釋出空間的話,就會造成瀏覽器洩漏記憶體。

不過,由於記憶體物件只是個 JavaScript 物件,物件本身會受到垃圾回收器 (Garbage Collector)的監控(但其內容不會)。

也就是說,當 WebAssembly 實體所附帶的記憶體物件耗盡記憶體時,垃圾回收器 (Garbage Collector)會把整個記憶體陣列都清乾淨。

記憶體隔離(Memory isolation)
很多人一聽到 WebAssembly 可以直接存取記憶體時,都會變得有點緊張。因為他們擔心萬一出現惡意的 WebAssembly 模組,它就能長驅直入、接觸到不該碰觸的記憶體。不過,那是不可能的。

ArrayBuffer 的外圍便構成隔離的邊界,會限制住 WebAssembly 模組所能直接碰觸到的記憶體區塊。

儘管 WebAssembly 模組能直接接觸陣列內的位元,卻無法看到在陣列範圍以外的任何東西。

譬如,WebAssembly 便無法存取記憶體內的其他 JavaScript 物件(如 window global)。這一點對保障安全來說極為重要。

每當 WebAssembly 要載入程式或儲存物件時,WebAssembly 引擎便會檢查陣列的範圍,以確保該位址位於相對應之 WebAssembly 實例的記憶體內。

若有程式碼試圖存取陣列範圍以外的位址,WebAssembly 引擎則會發出例外通知,進而保障其他記憶體的安全。

以上是 memory import 的介紹。你還可閱讀另一篇文章,進一步了解另外一種有助於加強安全性的 import — table import

原文連結

)

    Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
    Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
    Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade