weizman
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Proposal for enabling web apps full and first access and control over all same origin realms ## tl;dr * Web applications as of today **have no control/visibility over newborn same origin realms in runtime**. * When loaded, **same origin realms should be processed primarily by the app and only afterwards by their creator**, to allow the app to decide how same origin realms should behave as their host, just like how the app has the right to set its own CSP. * This is not new as a concept, as **this exact ability is granted by the browser to extensions and plugins** in the form of the manifest field [`all_frames`](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts#:~:text=Description-,all_frames,-Boolean), we just think **it makes sense to grant such power over child frames to the web app too**. * We have a **working shim called [Snow ❄️](https://github.com/lavamoat/snow/)** of how we imagine a solution to this problem should behave, which is already integrated into [MetaMask 🦊](https://github.com/MetaMask/metamask-extension/) ([merged](https://github.com/MetaMask/metamask-extension/pull/15580)) and is used to enhance its protection. * The main use case for this idea is for 1st/3rd party services who wish to **apply certain dynamic rules to a web app which are very incomplete when are only applied to the top main realm but not to all realms automatically**. * To further explore the different use cases jump over to [Motivation](#Motivation). > *To further explore this idea, its motivation, the realms security problem and Snow - jump over to the [Resources](#Resources) section at the bottom of the page.* ## Introduction We believe a **web app should have full and first control over newborn [realms](https://weizman.github.io/page-what-is-a-realm-in-js/)** within itself before any other entity does, including the creator of any certain realm. In other words, if a certain script (whether of the app or of a 3rd party) lifts up a new realm for whatever reason, the [window proxy](https://developer.mozilla.org/en-US/docs/Glossary/WindowProxy) representing that realm should **first be processed by the app itself and only afterwards by that certain script**. ### Clarification So for example, if web app `https://my-app.com` loads a [3rd party service](https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#what-do-we-mean-by-third-party-scripts) JS script from `https://external-service/sdk.js` and that service uses [iframes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe) as part of its logic, the iframe naturally will load with its own realm. This is very common for many reasons, a common example would be ad services such as [Google Ads](https://ads.google.com/) that optionally load ads within iframes. In today's landscape, the context of web apps such as `https://my-app.com` has **no control over such rising realms and therefore cannot limit/define their power/abilities/behaviour**. #### To solve this problem, we: 1. suggest a [proposal](#Proposal) for a new API; 2. would like to present a [shim](#Shim) that implements fully this proposed API. ### Proposal We imagine support for a new window owned property `"XXX"` that its descriptor is as follows: ```javascript { value: XXX, writable: true, enumerable: false, configurable: true } ``` Where `XXX` is a function that gets a callback which will be called with every new realm that comes to life within the app: ```javascript XXX((win) => console.log('Here is a new window:', win)); ``` Listing the callback by calling `XXX` should only be possible: 1. **Once** (per page load); 2. **By the web app itself** (meaning, by a script that originates in the same origin as the app, similar to how [CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) is also a privilege that only belongs to the web app); 3. **By the top most window** (aka [`top`](https://developer.mozilla.org/en-US/docs/Web/API/Window/top)). #### Important notes 1. The callback should be called **synchronously after the creation of the realm**, so that the registrer of the callback assured to be getting first access to the realm before any other entity in the app. 2. **If the same realm was already introduced to the page, the callback will fire again anyway.** This is because there are cases in which the same realm representation - the `WindowProxy` object - is loaded more than once (e.g. iframe `src` relocation). 3. **The browser should pass to the registered callback same origin realms only**, as those are the true potential danger to the web app. Cross origin realms cannot synchronously access the web app and therefore cannot be leveraged maliciously against the app. ### Shim I created [Snow ❄️](https://github.com/lavamoat/snow) which is a shim that when is applied to the web app at the beginning of its execution, **fully applies the above proposal to the execution runtime.** Once applied, a new property `SNOW` is exported via the [`globalThis`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis) which accepts the described callback and calls it with every new realm that comes to life within the app. Being a shim, Snow achieves its goal by hooking into all the different points where new realms are formed in JavaScript and makes sure to pass all new realms to the callback before returning them to their creator. However, being a shim also means Snow comes with clear disadvantages such as impacting performance, potentially not being bulletproof and more. Therefore, **Implementing Snow as part of the browser will allow us to get the advantages it brings with it without these disadvantages.** ## Motivation The motivation here is to simply **endow the web app with the capabilities that it deserves to have, which is governance and control over same origin realms within itself**. * This isn't a new concept - **this exact ability is granted by the browser to extensions and plugins** in the form of the manifest field [all_frames](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts#:~:text=Description-,all_frames,-Boolean), we just think it makes sense to grant such power over child frames to the web app too. * With the minor exception in which extensions get primer access to all child frames whether cross or same origin whereas the web app should only have power over the realms under its own origin. #### Here we'll explore the different reasons and use cases of why we might want to realize this proposal. ### 1. Third Party Vendors For Client Side Security Products > Part A - The problem with not having builtin browser support: As earlier described and demonstrated in the [Clarification](#Clarification) section, iframes are being used today in all sorts of legitimate ways. However, in addition to the legitimate usage of them, **iframes can also easily be leveraged maliciously in web security context.** This is **far more relevant today** than before due to the major shift web apps builders took towards fully relying on [3rd party dependencies](https://cleverbeagle.com/blog/articles/what-are-javascript-packages-and-dependencies) when building their apps. That is because [securing a supply chain](https://www.techtarget.com/searcherp/definition/supply-chain-security#:~:text=Supply%20chain%20security%20is%20the,part%20of%20a%20supply%20chain.), which was less of a thing a couple of years back, is currently a very difficult problem to solve. With the rise of supply chain attacks against web apps, different protection solutions (see "Part C" for examples) came to life, many of them around securing the app and browser builtin sensitive APIs in runtime. The motivation was basically "It's hard to tell what part of the supply chain will be breached and how, so let's apply protection to the app itself in realtime, so that when an attacker finds a breach, we'll already be defending the app". **It's hard to tell how an attacker will find its way into a supply chain, but might be easier to predict what they'll try to do once they're in.** Here's an example: if the attacker attempts to steal the contents of [`document.cookie`](https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie) from the web page and exfiltrate it to its malicious domain, it might be smart to apply protection around access to the JavaScript API of `document.cookie`. Such protection can be applied by what is called "[monkey patching](https://dev.to/napoleon039/monkey-patching-what-is-it-and-should-you-be-using-it-50db)" - a technique that is used to override builtin APIs provided by the browser with custom hooks: ```javascript /* defender */ const desc = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie'); desc.get = () => ''; // disable document.cookie API getter Object.defineProperty(Document.prototype, 'cookie', desc); ``` That is of course an oversimplification, but in that manner it is possible to apply robust protection around different sensitive APIs and by that encounter an attacker more prepared in the battlefield. **However**, such protections are **basically worthless** due to the power that realms inherently bring with them, because the attacker can easily bypass the protection demonstrated above by simply leveraging another instance of the `document.cookie` API from within the realm of an iframe: ```javascript /* attacker */ document.body.appendChild(document.createElement('iframe')).contentWindow.document.cookie; ``` While the example of protecting the top main realm's `document.cookie` API is simple, dynamically defending every new `document.cookie` API that might be brought to life within newborn realms is not possible as of today. > Part B - How builtin browser support can help solve the problem: If the proposal described above makes it through, we could use the new suggested API to **automatically apply our protection to all child realms with no effort**: ```javascript /* defender */ top.XXX((win) => { const desc = win.Object.getOwnPropertyDescriptor(win.Document.prototype, 'cookie'); desc.get = () => ''; // disable document.cookie API getter win.Object.defineProperty(win.Document.prototype, 'cookie', desc); }); ``` The registered callback will process every new same origin realm that comes to life **first** and will apply our `document.cookie` API protection to it, thus leaving no option to leverage new realms to retrieve the original behaviour of the protected API. > Part C - Actors benefiting from this: As mentioned in "Part A" above, there are a number of actors in the client side supply chain security industry that would highly benefit from being able to apply their security mechanizms automatically to all realms, some of them (but not all) are: * [PerimeterX's Code Defender](https://www.humansecurity.com/products/code-defender) * [Akamai's Page Integrity Manager](https://www.akamai.com/products/page-integrity-manager) * [Imperva's Client Side Protection](https://www.imperva.com/products/client-side-protection/) ### 2. Client Side Monitoring Tools > Part A - The problem with not having builtin browser support: There are third party services that provide monitoring tools for web apps to have better insights into how their apps function and behave "in the wild". To achieve that those usually apply monkey patches to different builtin APIs in the web app's runtime to have visibility into how, why and how many times are they being used. For example, the popular among those - [Sentry.io](https://sentry.io/) - [patches different APIs such as `console`](https://github.com/getsentry/sentry-javascript/blob/c6f9dfe9570369c9acabec988f8a573d08bd8c82/packages/utils/src/instrument.ts#L108) to have real visibility into the `console` API usage of the web app in realtime. Like before, this is a common practice among services like this, and they hook into many APIs than just `console`. However, their visibility is incomplete, because in web apps where there is some to a lot of iframes usage, such services **do not extend their visibility into such iframes and therefore miss a big part of the picture.** > Part B - How builtin browser support can help solve the problem: If the proposal described above makes it through, we could use the new suggested API to automatically apply those visibility-purposed patches into all iframes within the page too, thus **significantly enhancing the quality of the service such third party vendors come to supply.** > Part C - Actors benefiting from this: As mentioned in "Part A" above, there are a number of actors in the client side visibility and monitoring industry that would highly benefit from being able to apply their tracking abilities automatically to all realms, some of them (but not all) are: * [Sentry.io](https://sentry.io) * [LogRocket.com](https://logrocket.com/) ### 3. Importance For Technological Innovation In JS > Part A - The problem with not having builtin browser support: There are innovative projects (different shims mostly) that would benefit from being able to apply themselves to all same origin realms automatically, partly because they're trying to apply technology to the page that needs to be deterministic and hermetic, which sometimes can be hard to achieve with multiple realms. > Part B - How builtin browser support can help solve the problem: The ability to automatically apply such logic to all realms can help enhance its purpose and keep it fully secure. > Part C - Actors benefiting from this: Some examples in that context: * Part of the [SES shim](https://github.com/endojs/endo/tree/master/packages/ses) initiative is a strong capability called [lockdown](https://github.com/endojs/endo/tree/master/packages/ses#lockdown) which when is called freezes all platform intrinsics so that they could not be redefined and therefore trusted to function purely. However, calling lockdown only applies to the top main realm, and having the ability to apply it to all same origin realms automatically would have been beneficial for apps that wish to defend themselves using lockdown for their inner iframe activities too. * [Across](https://github.com/lavamoat/across/) is a shim that introduces a way for two scripts within a single DOM to exchange messages with each other securely based on their origins. In order for this shim to fulfil its purpose safely, it must apply itself to all child realms, otherwise a pure realm can be leveraged to bypass its mechanizm. To achieve that, currently Across is built on top of Snow shim, but obviously replacing Snow with a builtin API would be far better. ### 4. More We believe there are more examples for use cases, and there will be more in the future if this proposal goes through. ## TBDs Although the idea and the need are quite clear to us, there are minor questions to still answer: 1. Should the API simply receive a callback? Or should the callback be registered to a new event perhaps? 2. Should the API receive only one callback once? Or should it allow multiple callbacks registration chronologically? 3. What should be the name of the official API/event? (Not Snow obviously) 4. Should the descriptor of the API be configurable/writable? 5. Should the callback be called only with same origin realms? or with cross origin realms too? (even though the callback code won't have sync access to newborn cross origin realms in such a case). ## Resources This proposal derives from a long term research around the security aspect of realms, and hard work on bringing Snow to life mostly to learn that it's better off natively in the browser - here are some resources in this context: * [awesome javascript realms security ⭐️](https://github.com/weizman/awesome-javascript-realms-security) - Long term realms security research documentation which includes references to: * [Snow ❄️](https://github.com/lavamoat/snow) - Official shim repo. * [Introduction to Snow](https://github.com/lavamoat/snow/wiki/Introducing-Snow) - further reading on the rise of supply chain attacks and how it all lead to creating Snow. * [Integrating Snow into MetaMask](https://weizman.github.io/page-snow-into-metamask/) - Going deeper on why Snow is an important component for enhancing the defense of MetaMask and any other web app basically. * [Live demo](https://lavamoat.github.io/snow/demo/) - a super simple demo to demonstrate Snow in action.

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully