WebAssembly, sometimes called Wasm, is a portable, low-level binary code instruction format executed in a web browser’s virtual machine (VM). It enables developers to write high-performance code in various languages and runs alongside JavaScript.
Developers are embracing WebAssembly for its ability to accelerate complex algorithms, enable gaming and multimedia applications, and provide a secure sandbox environment for running untrusted code. However, before adopting WebAssembly, it’s crucial to consider its security implications and how to mitigate the risks.
Top WebAssembly security concerns
Developers can compile many modern programming languages into WebAssembly. But despite its advantages, WebAssembly can bypass traditional security measures, potentially executing malicious code in the browser.
Let’s take a closer look at WebAssembly’s unique security issues by building a sample app with Blazor, the open source web framework. Blazor lets us write C# code instead of JavaScript for our web pages. The C# code is built into dynamic link libraries (DLLs) and WebAssembly (.wasm) files running on the client browser.
Prerequisites
Before diving into this tutorial, ensure you have the following:
- Download and install either Visual Studio or VS Code. This is the integrated development environment (IDE) you’ll use to write and run the WebAssembly code. If you select VS Code, download and install the .NET SDK and the C# extension next.
- Install the Visual Studio extension or the Snyk extension for VS Code. This plugin will scan and provide security analysis on our WebAssembly code.
- Download the sample project.
Run the sample project
If you chose Visual Studio for your IDE, open the Visual Studio Installer and check the .NET WebAssembly Build Tools option:
Open the Tools > Options > Snyk menu, then General Settings. Next, click the Connect Visual Studio to Snyk.io button.
If you chose VS Code as your IDE, click the Snyk icon in the left toolbar. Next, click Trust workspace and connect.
Run the program in Visual Studio or VS Code to launch the sample app, which looks like the screenshot below, with a "Human Resources" title, image, and text.
Security concern #1: WebAssembly module isolation
To maintain the security of web applications using this technology, you must keep WebAssembly modules isolated. Isolating modules from each other and the host environment means they each operate independently without interfering with the behavior of other modules or the host application. Module isolation is critical when executing untrusted code — it stops malicious code from accessing sensitive data or resources.
Two best practices for implementing module isolation are sandboxing and compartmentalization.
Sandboxing involves placing each module in a separate, isolated environment that limits access to the host system and other modules. The image below shows a project with two WebAssembly modules (Finance and Human Resources). When compiling and deploying the project to the web browser, the WebAssembly modules execute within a sandboxed environment separated from the host runtime.
Compartmentalization involves partitioning the host application and its modules into separate compartments, each with its own resources and access privileges.
Both sandboxing and compartmentalization create a secure environment that can execute untrusted code without compromising the security of the host system or other modules.
Next, use the Snyk Visual Studio Code extension to verify if a WebAssembly code is vulnerable. Open the Extensions > Snyk menu and click Scan.
Snyk analyzes the file and identifies known WebAssembly Code Quality issues and vulnerabilities related to open source and code security. If it finds issues or vulnerabilities, Snyk offers the issue’s details and recommendations on how to fix it.
Security concern #2: WebAssembly linear memory model
The linear memory model is a memory addressing technique using a single contiguous address space to organize memory. This approach allows the processing unit to access memory locations directly and sequentially. The image below shows an object — shared between JavaScript and WebAssembly code — using a space in linear memory.
The WebAssembly linear memory model feature allows modules to allocate and access a contiguous block of memory, much like a traditional array. While this model provides a fast and efficient way to manage memory in WebAssembly applications, it also introduces security risks.
For example, if a module accesses memory outside of its allocated range, it could corrupt the memory of other modules or the host system. This situation potentially leads to a crash or security breach.
To mitigate the security risks related to linear memory model in WebAssembly applications, follow these best practices:
- Use bounds checking to ensure modules only access memory within their allocated range.
- Avoid unsafe functions to prevent memory corruption vulnerabilities.
- Implement memory protection mechanisms, such as address space layout randomization (ASLR) and data execution prevention (DEP).
Security Concern #3: WebAssembly JIT compilation
WebAssembly just-in-time (JIT) compilation compiles Wasm code into machine code at runtime instead of ahead of time. While this process provides significant performance benefits, it also introduces potential security risks.
JIT compilation’s dynamic nature complicates detecting and preventing attacks. Bad actors can inject malicious code into the compilation process and execute it in the host environment. For example, a hacker could craft an inoffensive constant written in a high-level programming language:
var a = (0x11223344^0x44332211^0x44332211^ ...);
Then, the JIT compiler transforms that instruction into a series of native x86 code instructions:
0000: b8 44 33 22 11 mov $0x11223344,%eax mov eax,0x11223344
0005: 35 11 22 33 44 xor $0x44332211,%eax xor eax,0x44332211
000a: 35 11 22 33 44 xor $0x44332211,%eax xor eax,0x44332211
The attacker uses a known bug to move the execution pointer to address 0001. This executes a malicious set of instructions that’s carefully crafted and injected into the constant above.
To mitigate the security risks of JIT compilation in WebAssembly applications, implement the following best practices for managing the compilation process:
- Using ahead-of-time (AOT) compilation to compile Wasm code into machine code before runtime. This approach eliminates the risks associated with dynamic compilation.
- Applying security patches for known vulnerabilities in JIT compilers.
Security Concern #4: Web APIs and cross-site scripting (XSS)
WebAssembly can interact with Web APIs to access resources and data from web browsers, servers, and other platforms. However, these interactions can introduce security risks like cross-site scripting (XSS) attacks. In XSS attacks, hackers inject malicious code into web pages or applications. Later, users may unknowingly execute this malicious code, causing unauthorized access or data theft.
To mitigate the risks of XSS attacks in WebAssembly applications, implement best practices for input validation and output encoding:
- Input validation checks user input for potentially malicious code or characters and rejects any input that doesn’t meet specific criteria.
- Output encoding involves encoding user input or output to prevent the execution of malicious code.
Additionally, use HTTPS to encrypt data passing between the server and client, preventing attackers from intercepting and modifying data in transit.
Security concern #5: Insecure WebAssembly content delivery
Secure content delivery is critical for WebAssembly applications, ensuring users receive authentic, unaltered code delivered over a trusted channel. Insecure content delivery can introduce security risks, including man-in-the-middle (MITM) attacks and code tampering.
MITM attacks involve attackers intercepting and modifying code as it passes between the server and the client. This technique allows an attacker to inject malicious code into the application, which the browser or the Wasm runtime can execute.
To secure content delivery in WebAssembly applications, follow these best practices:
- Use HTTPS to encrypt data between the server and client, ensuring secure and unaltered code transmission.
- Use content integrity checks like checksums or digital signatures to verify code authenticity.
- Implement access control mechanisms to restrict code access to authorized users.
Assemble safely and securely
Developers have enthusiastically adopted WebAssembly, a technology that allows them to write high-performance applications within web browsers. However, WebAssembly’s benefits come with significant security concerns.
This article covered some WebAssembly security issues: improper module isolation, lack of protection in linear memory model, JIT compiler vulnerabilities, cross-site scripting attacks, and insecure WebAssembly content delivery.
Fortunately, several best practices mitigate the vulnerabilities that WebAssembly introduces. Following these security measures helps protect users and shield their WebAssembly apps.
To protect your systems and users, it’s also vital to keep up with the latest security threats impacting WebAssembly. Development tools help. For example, the Snyk platform maintains a vast catalog of known vulnerabilities and offers actionable insights to mitigate these risks. Tools like Snyk Code and Snyk Open Source enable you to detect and resolve code security issues quickly. Start your free account today.