Aegis: only the page's own scripts can reach the wallet relay
The isolated-world relay accepted any postMessage carrying the fixed tag "aegis-aegis", including one from a cross-origin iframe (an ad, an embed), and attributed it to the top-level origin and its grants. The tag now carries a per-load random nonce that only the injected main-world bridge knows, and both listeners drop events whose source is not this window. The document_start install path is unchanged.
This commit is contained in:
parent
206f54edd2
commit
f57cf4c894
1 changed files with 15 additions and 7 deletions
|
|
@ -191,13 +191,20 @@ theseus.contextBridge.exposeInMainWorld("wizardconnect", wizardconnect);
|
||||||
// to us via `window.postMessage` on a namespaced envelope. This mirrors how
|
// to us via `window.postMessage` on a namespaced envelope. This mirrors how
|
||||||
// MetaMask and Phantom bridge extension code back to page code.
|
// MetaMask and Phantom bridge extension code back to page code.
|
||||||
|
|
||||||
// Namespace used on the postMessage envelope. Includes the addon id so a
|
// Namespace used on the postMessage envelope. Includes the addon id plus a
|
||||||
// page that runs multiple dapp-wallet extensions doesn't misroute messages.
|
// per-page-load nonce: only the main-world bridge we install below knows
|
||||||
const AEGIS_TAG = "aegis-" + theseus.id;
|
// it, so a cross-origin iframe on the page cannot address the relay. The
|
||||||
|
// listener additionally requires the event to come from this very window
|
||||||
|
// (e.source === window) — an iframe's postMessage to its parent has
|
||||||
|
// e.source === that iframe — so a request can never be attributed to the
|
||||||
|
// top-level origin by anything but the top-level page's own scripts. The
|
||||||
|
// old fixed tag let any embedded ad frame call the wallet as the page.
|
||||||
|
const AEGIS_TAG = "aegis-" + theseus.id + "-" + Array.from(crypto.getRandomValues(new Uint8Array(12)), (b) => b.toString(16).padStart(2, "0")).join("");
|
||||||
const pendingCalls = new Map();
|
const pendingCalls = new Map();
|
||||||
window.addEventListener("message", async (e) => {
|
window.addEventListener("message", async (e) => {
|
||||||
const d = e && e.data;
|
if (!e || e.source !== window || e.origin !== location.origin) return;
|
||||||
if (!d || d.aegisTag !== AEGIS_TAG) return;
|
const d = e.data;
|
||||||
|
if (!d || typeof d !== "object" || d.aegisTag !== AEGIS_TAG) return;
|
||||||
if (d.kind === "request") {
|
if (d.kind === "request") {
|
||||||
// Forward main-world → isolated-world → addon.
|
// Forward main-world → isolated-world → addon.
|
||||||
try {
|
try {
|
||||||
|
|
@ -229,8 +236,9 @@ const mainWorldSource = `(function () {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
window.addEventListener("message", (e) => {
|
window.addEventListener("message", (e) => {
|
||||||
const d = e && e.data;
|
if (!e || e.source !== window) return;
|
||||||
if (!d || d.aegisTag !== TAG) return;
|
const d = e.data;
|
||||||
|
if (!d || typeof d !== "object" || d.aegisTag !== TAG) return;
|
||||||
if (d.kind === "response") {
|
if (d.kind === "response") {
|
||||||
const p = pending.get(d.id);
|
const p = pending.get(d.id);
|
||||||
if (!p) return;
|
if (!p) return;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue