-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Description
Abstract
Currently ZeroNet uses a wrapper for sidebar and notifications UI, and embeds site content with an iframe. This proposal fixes some issues caused by iframing by embedding ZeroNet UI into site content.
Rationale
- Add blob: scheme to Content-Security-Policy #2165, Allow Pointer Lock API in iframe #2057 - All features have to be marked unsafe by default, so supporting new ones is troublesome;
- Allow a site to bust out of IFrame #2154 - Most people don't understand what NOSANDBOX means;
- Chrome is going to block interactive content in iframes #2086 - Some interactive content in iframes might get blocked;
- Disable pull to refresh on all sites. #2058 - Pull-to-refresh is working weird with iframes;
- "Opened as child-window, stopping..." #2003 - "Opening as child window" is sometimes impossible to bypass;
- Open link in new tab really doesn't works #1736 - Opening link in a new tab is more difficult than required;
- Picture in picture mode #1707, Embedding other sites with iframes #565 - Embedding a site into a site is unsafe with an iframe;
- API for change browser's header/address bar color #1667 - Browser header style can only be set by root frame;
- Can't scroll in safari #1403 - Scrolling is impossible, iframe is most likely the reason;
- How to use localStorage? #1399, Accessing localStorage from zite #1054, Allow sites to use localresources, IndexedDB, WebSql, etc #29 - localStorage, IndexedDB, etc. are not available in sandboxed iframes;
- I make a WebGl game based on Unity3d. Then I put these files under my websites folder (clear all original files). When I open my web through ZeroNet, it just show nothing. #1237 - Fullscreen API doesn't work;
- Error: Permission denied to access property "document" #1236, Allow zite loading outside iframe (for zite owners) #1262 - Some Vue plugins don't work;
- Sandbox prevents creating web worker #1010 - Creating Web Workers requires data: URI usage;
- Uncaught SecurityError: #469 - History management requires ZeroFrame usage.
Overview
Current architecture:
┌─────────────────────────────────────────────────────┐
│ WRAPPER (src/Ui/template/wrapper.html) │
│ Stores secrets (e.g. wrapper key) │
│ ┌─────────────────────────────────────────────────┐ │
│ │ WS UPLINK │ │
│ │ UiWebsocket API │ │
│ └─────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ NOTIFICATIONS (<div>) │ │
│ │ ╔═════════════════════════════════════════════╗ │ │
│ │ ║ SITE NOTIFICATIONS (<div>) ║ │ │
│ │ ║ Unsafe content (possible XSS) ║ │ │
│ │ ╚═════════════════════════════════════════════╝ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ WRAPPER NOTIFICATIONS (<div>) │ │ │
│ │ │ Safe content (no leaking or spoofing) │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ SIDEBAR (<div>) │ │
│ │ Site and key management, safe │ │
│ │ ╔═════════════════════════════════════════════╗ │ │
│ │ ║ SITE DATA ║ │ │
│ │ ║ Title, description, donate links, etc. ║ │ │
│ │ ╚═════════════════════════════════════════════╝ │ │
│ └─────────────────────────────────────────────────┘ │
│ ╔═════════════════════════════════════════════════╗ │
│ ║ IFRAME SANDBOX ║ │
│ ║ Unsafe content (managed by site code) ║ │
│ ╚═════════════════════════════════════════════════╝ │
└─────────────────────────────────────────────────────┘
Safety layers are separated with double border.
No software has zero bugs. This includes security issues. There are many possible attack points here:
- Site notifications (protected by manual escaping) were exploited by me, revealing site private keys;
- Sidebar content (protected by manual escaping) wasn't exploited according to my sources, but it's still a valid point of attack;
- Iframe sandbox (protected by browser) is in theory unbreakable, but still adds unnecessary complexity;
- The final attack point is the external iframe (in case the wrapper is in an iframe itself). This was exploited by me once.
Proposed architecture;
┌─────────────────────────────────────────────────────┐
│ HTML PAGE │
│ ┌─────────────────────────────────────────────────┐ │
│ │ PREFIX (shadow DOM) │ │
│ │ Practically invisible to site content │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ SITE NOTIFICATIONS (<div>) │ │ │
│ │ │ Unsafe content (possible XSS) │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ ╔═════════════════════════════════════════════╗ │ │
│ │ ║ WRAPPER NOTIFICATIONS (<iframe>) ║ │ │
│ │ ║ Safe content (no leaking or spoofing) ║ │ │
│ │ ╚═════════════════════════════════════════════╝ │ │
│ │ ╔═════════════════════════════════════════════╗ │ │
│ │ ║ SIDEBAR (iframe) ║ │ │
│ │ ║ Site and key management ║ │ │
│ │ ║ ╔═════════════════════════════════════════╗ ║ │ │
│ │ ║ ║ GATE (iframe) ║ ║ │ │
│ │ ║ ║ ┌─────────────────────────────────────┐ ║ ║ │ │
│ │ ║ ║ │ WS UPLINK │ ║ ║ │ │
│ │ ║ ║ │ UiWebsocket API (ADMIN) │ ║ ║ │ │
│ │ ║ ║ └─────────────────────────────────────┘ ║ ║ │ │
│ │ ║ ╚═════════════════════════════════════════╝ ║ │ │
│ │ ╚═════════════════════════════════════════════╝ │ │
│ │ ╔═════════════════════════════════════════════╗ │ │
│ │ ║ GATE (iframe) ║ │ │
│ │ ║ ┌─────────────────────────────────────────┐ ║ │ │
│ │ ║ │ WS UPLINK │ ║ │ │
│ │ ║ │ UiWebsocket API (site) │ ║ │ │
│ │ ║ └─────────────────────────────────────────┘ ║ │ │
│ │ ╚═════════════════════════════════════════════╝ │ │
│ └─────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ SITE DATA │ │
│ │ Unsafe content (managed by site code) │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
Sure, it might look more difficult at the first glance, but security comes with a cost.
Resulting HTML
The resulting HTML (the one that browser receives) consists of a prefix and the real site .html
file.
Prefix
Prefix is a "magic" HTML code that sets up an analogue of what was a wrapper by creating a shadow DOM node. This ensures that the sidebar and notifications are shown correctly, independent of main site styles, and that it doesn't affect the site itself.
Gate
A gate is an iframe that acts like a gate between UiWebsocket and its user. The gate handler uses the referrer to check what permissions the websocket must have.
Fixed issues / added features
- Add blob: scheme to Content-Security-Policy #2165, Allow Pointer Lock API in iframe #2057 - All features are now safe;
- Allow a site to bust out of IFrame #2154 - No need for NOSANDBOX anymore;
- Chrome is going to block interactive content in iframes #2086 - The only interactive content is simple notifications (i.e. buttons);
- Disable pull to refresh on all sites. #2058 - Pull-to-refresh can now be controlled by the site;
- "Opened as child-window, stopping..." #2003 - No need to be top frame anymore;
- Open link in new tab really doesn't works #1736 - Opening in a new tab made easy;
- Picture in picture mode #1707, Embedding other sites with iframes #565 - Embedding made possible (requires a separate proposal);
- API for change browser's header/address bar color #1667 - Controlled by the site now;
- Can't scroll in safari #1403 - Scrolling is fixed;
- How to use localStorage? #1399, Accessing localStorage from zite #1054, Allow sites to use localresources, IndexedDB, WebSql, etc #29 - localStorage, IndexedDB, etc. made possible (requires a separate proposal);
- I make a WebGl game based on Unity3d. Then I put these files under my websites folder (clear all original files). When I open my web through ZeroNet, it just show nothing. #1237 - Fullscreen API without ZeroFrame;
- Error: Permission denied to access property "document" #1236, Allow zite loading outside iframe (for zite owners) #1262 - SecurityError's fixed;
- Sandbox prevents creating web worker #1010 - Web Workers by path should work now;
- Uncaught SecurityError: #469 - History API without ZeroFrame.
Implementation status
- Prefix
- Gate
- 0 button
- Sidebar
- Debug logs
- Notifications
- Modified panel
- Old wrapper compatiblity
- Local storage
- Wrapper commands
- innerReady [compat]
- innerLoaded & wrapperInnerLoaded [compat]
- wrapperNotification, wrapperConfirm, wrapperPrompt, wrapperProgress
- wrapperSetViewport [compat]
- wrapperSetTitle [compat]
- wrapperReload [compat]
- wrapperGetLocalStorage & wrapperSetLocalStorage
- wrapperPushState, wrapperReplaceState, wrapperGetState [compat]
- wrapperGetAjaxKey
- wrapperOpenWindow [compat]
- wrapperPermissionAdd
- wrapperRequestFullscreen [compat]
- wrapperWebNotification & wrapperCloseWebNotification [compat]
ETA: at most 1 week if no major issues are found