Solving the IPFS XSS problem
I explored IPFS in a previous post, and think it offers a ton of promise. One open issue, however, is that all pages are served from the same origin (either ipfs.io
, gateway.ipfs.io
, or localhost
), which means that all pages on IPFS share privileges (Javascript geolocation api), cookies, and client-side data. There is discussion in an open IPFS ticket already and I wanted to unpack the various issues and goals.
Goals
I'm approaching this as an app developer considering publishing a web app on IPFS. This app will request javascript permissions (geolocation api), set a cookie, and store some data in localstorage. In order to choose IPFS over a traditional centralized server, I need a solution that satisfies the following goals:
- Isolation - The permissions granted to and data stored by my app will not be accessible by anyone else's app deployed on IPFS
- Transferability - When I deploy a new bundle to IPFS to fix a bug or add a feature, my new code should be able to access the same permissions and data as the old one, and ideally the app should load from the same url that everyone already uses for the previously deployed version
A final goal mostly irrelevant to app publishers but important for IPFS users:
- Persistence - If I give up on the app (I take down a domain if I have one, and stop running the IPFS daemon) users of my app should continue to have access to it, along with all data and permissions. This assumes the app is self contained, and did not rely on CORS calls to my privately run server.
Solutions
These solutions assume IPNS->IPFS mappings, once published to the DHT, stay there even if the original publishing node goes offline. The discussion in FAQ #44 implies this is currently true.
IPFS root subdomains
A comment by ''edrex'' suggests either a per-root subdomains on gateway.ipfs.io
, or using per-page suborigins for each root. If the root was an IPFS hash, they would ensure isolation and persistence, but (since the data pointed to by an IPFS hash cannot be changed) there would be no transferability. Any new version of my app will not have the permissions or data of the old version, and I'll have to redistribute new urls for the new version.
IPNS root subdomains
If the system above supported IPNS hashes, then I get transferability at the cost of partial persistence. The app remains functional if my IPFS daemon goes dark because the DHT preserves the last IPNS->IPFS mapping. The problem lies in me publishing a breaking IPNS->IPFS before I stop development (point the IPNS hash at a landing page that has no app and says "Sorry, I took down this app because I don't want to update it anymore"). This ability is inseparable from my ability to do bug fixes (it's all part of mutability) so the only way to fix that while still preserving transferability is if historical IPNS mappings are persisted in some kind of commit chain as alluded to at the end of the IPNS example. If this were the case, we could come up with a way for end users to select which mapping to use, allowing them to "roll back" to a previous version of the app.
Custom domain
IPFS issue 39 is working on a system where a custom domain could be bound to an IPNS hash. This has the same benefits and drawbacks as the IPNS root subdomains above, with the additional downside that if I stop development, I might let my custom domain registration expire, breaking all urls even if the IPNS hash remains mapped to the right IPFS root.
Balancing opposing goals
As an app developer, if IPFS gives me isolation and transferability I would be willing to publish on it. As an IPFS proponent, I want it to ensure as much persistence as possible. Given this conflict between making IPFS enticing enough for publishers to use while providing features to help the public / consumers, I think IPNS root subdomains is the right balance. We get isolation and transferability, reducing barriers to publishers, while the only loss to persistence is that a malicious publisher can release a new app version that removes features. Even this loss may be mitigated in the future with a history-preserving blockchain or commit chain.