Skip to content
Snippets Groups Projects
Verified Commit 936aade1 authored by ma1's avatar ma1 Committed by Pier Angelo Vendrame
Browse files

fixup! Bug 40458: Implement .tor.onion aliases

Bug 42099: Blind cross-site .onion requests.
parent ce807a3b
Branches
Tags
1 merge request!889Bug 42366: Tor Browser 115.7.0esr alpha rebase
......@@ -7,6 +7,7 @@ const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
JSONFile: "resource://gre/modules/JSONFile.sys.mjs",
TorRequestWatch: "resource:///modules/TorRequestWatch.sys.mjs",
});
/* OnionAliasStore observer topics */
......@@ -272,6 +273,7 @@ class _OnionAliasStore {
}
async init() {
lazy.TorRequestWatch.start();
await this._loadSettings();
if (this.enabled) {
await this._startUpdates();
......@@ -286,6 +288,7 @@ class _OnionAliasStore {
}
this._rulesetTimeout = null;
Services.prefs.removeObserver(kPrefOnionAliasEnabled, this);
lazy.TorRequestWatch.stop();
}
async getChannels() {
......
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* This module implements Tor-specific Web Request policies, such as
* preventing observable cross-site requests to .tor.onion and .bit.onion sites.
*/
import { ConsoleAPI } from "resource://gre/modules/Console.sys.mjs";
const log = new ConsoleAPI({
maxLogLevel: "warn",
maxLogLevelPref: "browser.torRequestWatch.log_level",
prefix: "TorRequestWatch",
});
class RequestObserver {
static #topics = [
"http-on-modify-request",
"http-on-examine-response",
"http-on-examine-cached-response",
"http-on-examine-merged-response",
];
#asObserver(addOrRemove) {
const action = Services.obs[`${addOrRemove}Observer`].bind(Services.obs);
for (const topic of RequestObserver.#topics) {
action(this, topic);
}
}
start() {
this.#asObserver("add");
log.debug("Started");
}
stop() {
this.#asObserver("remove");
log.debug("Stopped");
}
// nsIObserver implementation
observe(subject, topic, data) {
try {
let channel = ChannelWrapper.get(
subject.QueryInterface(Ci.nsIHttpChannel)
);
switch (topic) {
case "http-on-modify-request":
this.onRequest(channel);
break;
case "http-on-examine-cached-response":
case "http-on-examine-merged-response":
channel.isCached = true;
// falls through
case "http-on-examine-response":
this.onResponse(channel);
break;
}
} catch (e) {
log.error(e);
}
}
onRequest(channel) {
if (this.shouldBlind(channel, channel.documentURL)) {
log.warn(`Blocking cross-site ${channel.finalURL} ${channel.type} load.`);
channel.cancel(Cr.NS_ERROR_ABORT);
}
}
onResponse(channel) {
if (!channel.documentURL && this.shouldBlind(channel, channel.originURL)) {
const COOP = "cross-origin-opener-policy";
// we break window.opener references if needed to mitigate XS-Leaks
for (let h of channel.getResponseHeaders()) {
if (h.name.toLowerCase() === COOP && h.value === "same-origin") {
log.debug(`${COOP} is already same-origin, nothing to do.`);
return;
}
}
log.warn(`Blinding cross-site ${channel.finalURL} load.`);
channel.setResponseHeader(COOP, "same-origin-allow-popups");
}
}
isCrossOrigin(url1, url2) {
return new URL(url1).origin !== new URL(url2).origin;
}
shouldBlindCrossOrigin(uri) {
try {
let { host } = uri;
if (host.endsWith(".onion")) {
const previousPart = host.slice(-10, -6);
return (
previousPart && (previousPart === ".tor" || previousPart === ".bit")
);
}
} catch (e) {
// no host
}
return false;
}
shouldBlind(channel, sourceURL) {
return (
sourceURL &&
this.shouldBlindCrossOrigin(channel.finalURI) &&
this.isCrossOrigin(channel.finalURL, sourceURL)
);
}
}
let observer;
export const TorRequestWatch = {
start() {
if (!observer) {
(observer = new RequestObserver()).start();
}
},
stop() {
if (observer) {
observer.stop();
observer = null;
}
},
};
......@@ -4,4 +4,5 @@ EXTRA_JS_MODULES += [
"OnionAliasStore.sys.mjs",
"OnionLocationChild.sys.mjs",
"OnionLocationParent.sys.mjs",
"TorRequestWatch.sys.mjs",
]
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment