Configuring OpenBSD relayd’s Content Security Policy for WebAssembly(wasm)

Author’s Note: The following discussion assumes you’re using both relayd and httpd for serving your site. httpd by itself does not handle manipulating things like response headers.

Context

WebAssembly(wasm) is the new hotness if you’ve not heard. It provides a language-agnostic binary instruction format that can be run in browsers. This means we can finally escape the tyranny of JavaScript and its assorted transpiled offspring.

I’ve been doing my own exploration with wasm lately. I’m using Rust as the source language and yew.rs to produce a wasm frontend. This works great and has been a much nicer experience than anything like React.js or Vue.js.

Unfortunately, when I deployed my frontend app to my website, it wouldn’t load. After some digging, I ended up finding the culprit in the browser debugger:

Refused to execute inline script because it violates the following Content Security Policy directive: "default-src 'self'". Either the 'unsafe-inline' keyword, a hash ('sha256-jLxI1VFLBFY9e7acBLasiHGwzA2Os8wzffVUjpu0bT0='), or a nonce ('nonce-...') is required to enable inline execution. Note also that 'script-src' was not explicitly set, so 'default-src' is used as a fallback.

Ah - it’s the Content Security Policy. I’d forgotten those exist. After some digging, I learn two things:

If you’re unfamiliar with unsafe-inline and unsafe-eval, they prevent unsafe execution of styles and scripts. Things like dynamic uses of JavaScript’s eval(..) function. Generally, it’s a good practice to not set theses values for your Content Security Policy but needs must in my case.

Updating the Content Security Policy

My original Content-Security-Policy in my relayd.conf file looked like this:

match response header set "Content-Security-Policy" value "default-src 'self';"

That’s a pretty restricted and barebones one. It basically says only trust things loaded on the local server, preventing sketchy XSS attacks and friends.

My updated Content-Security-Policy now looks like:

match response header set "Content-Security-Policy" value "default-src 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-eval' 'unsafe-inline';"

This adds two new keys - script-src and style-src. For both, I’ve specified that for self (i.e. zacbrown.org), enable unsafe-inline and unsafe-eval for content served by self.

This will allow us to load the WASM binaries and also lets the WASM binaries utilize styles defined outside the WASM binary itself.

Addendum: a protip on WASM and httpd.conf

By the way - httpd.conf doesn’t natively know about application/wasm as a MIME type. You’ll want to upload your httpd.conf’s type {} block with something like:

# make all OpenBSD default mime types available
types {
  include "/usr/share/misc/mime.types"
  application/wasm wasm
}

This will serve your WASM binaries with a well-known MIME type that browsers can optimize loading.

Posted on 2022-05-04