caddr.org: content addressed origin

build decentralized cross site services with browser apis today

Browser resources such as localStorage, IndexedDB, and WebAuthn follow the "same-origin policy" and are locked to a particular domain. This makes it difficult to create decentralized services that are meant to work across different websites.

site-a.com localStorage IndexedDB WebAuthn keys site-b.com localStorage IndexedDB WebAuthn keys site-c.com localStorage IndexedDB WebAuthn keys
Each site's browser storage is siloed by origin — they cannot share data.

With caddr.org, the "origin" is defined by the content of the code that is being run, serving as a credibly neutral platform for building shared resources.

[hash].caddr.org shared localStorage shared IndexedDB shared WebAuthn keys site-a.com site-b.com site-c.com embeds via <iframe> embeds via <iframe> embeds via <iframe>
All sites embedding the same script share one content-addressed origin — and therefore can share the same browser storage.

what can you do with caddr.org?

how does caddr.org work?

caddr.org simply returns a page which consists of a script tag with whatever "src" is passed in through the query string, and an "integrity" attribute that corresponds to the base64-encoded version of the subdomain it is loaded from.

https:// jyhenscc…d64a47jq .caddr.org/?src= https://…/demo.js SHA-256 of the script, base32-encoded 52 chars — fits a DNS subdomain (max 63) The script to load hosted anywhere (needs CORS header)
Anatomy of a caddr.org URL.

for example

https://jyhensccrcfgezcf6f46ea6fxbrc7ul44kzlc2vrx63od64a47jq.caddr.org/?src=https://caddr-origin.github.io/examples/hello-world/demo.js

loads a page that contains

<script
  integrity="sha256-Tg5GyEKIimJkRfF54gPFuGIv0XzisrFqsb+24fuA59M="
  src="https://caddr-origin.github.io/examples/hello-world/demo.js">
</script>
Browser (embedding site) caddr.org server Script Host github.io, etc. ① GET [hash].caddr.org/?src=… ② returns minimal page <script integrity="sha256-…" src="…"> ③ fetch script (src URL) ④ JS file bytes returned ⑤ SRI check SHA-256(bytes) == hash? ✓ Execute [hash].caddr.org origin no match ✗ Blocked SRI violation caddr.org never hosts any scripts — it only pins a URL to its hash.
Request flow. caddr.org acts as a thin relay. The browser's built-in Subresource Integrity (SRI) check ensures the fetched bytes match the hash in the subdomain before execution.

Note that the embedding website is still "responsible" for hosting the contents of the script that is to be loaded— none of the scripts are hosted on caddr.org.

If you examine the source code of an actual page, you'll see that it's slightly different from what is described above. The script tags are generated dynamically in Javascript so that it can fall-back to several potential sources in the case of failure.

security

Ultimately we would like browsers to natively implement resolvers for urls that are in the format of *.caddr.org, similar to existing built-in pages such as about:blank. If you work on a browser, or know anyone who does, help towards native implementations would be much appreciated!

Since October 11, 2023, *.caddr.org has been added to the HSTS Preload List which will force it to be loaded with HTTPS. DNSSEC is also enabled for the domain. Content-Security-Policy is used to enforce the contents of the page through the headers.

A browser extension has been developed to serve as an additional layer of security that guards against compromises of the caddr.org domain.

We would like to get caddr.org added to the public suffix list, help on putting together a submission would also be appreciated.

The domain has been renewed ahead of time for 10 years, but as a piece of web infrastructure, it might be ideal if stewardship could be transferred to a credible organization.

At some point in the future, it may be possible that vulnerabilities are discovered in SHA-256 that compromise its viability as the basis for a content-addressing scheme. However the only other browser-supported hashing schemes SHA-386 and SHA-512 are not viable alternatives given the maximum length of a subdomain is 63 letters (RFC-1035). This is also what necessitates the current base32 encoding (as regular hexadecimal would require 64 letters).

Why base32 encoding? hex (64 chars): 4e0e46c842888a626445f179e203c5b8622fd17ce2b2b16ab1bfb6e1fb80e7d3 63-char limit base32 (52 chars): jyhensccrcfgezcf6f46ea6fxbrc7ul44kzlc2vrx63od64a47jq 52 chars — 11 chars to spare ← DNS max 63 chars
Base32 encodes SHA-256 in 52 characters, fitting within the 63-character DNS subdomain limit (RFC-1035). Hex would need 64 — one over the limit.

get started

Below is a simple tool where you can paste in the URL for some script file and it will automatically hash the contents and redirect you to the equivalent content-addressed caddr.org page.

Alternatively, you can manually calculate the subdomain from a local file by running the following shell script.

sha256sum FILENAME.js | awk '{ print $1 }' | xxd -r -p | base32 | sed 's/=//g'

source integrity error

TODO: explanation of content addressed origin integrity error

misc

The name is pronounced "kuh-duh-dur" as traditional in the lisp community for the abbreviation of (car (cdr (cdr x))) which returns the third item in a linked list.