66 lines
2.5 KiB
JavaScript
66 lines
2.5 KiB
JavaScript
/** 浏览器防护由真实应用响应提供;不读取配置源码,也不接触真实凭证。 */
|
|
import assert from "node:assert/strict";
|
|
import { test } from "node:test";
|
|
import {
|
|
appOrigin,
|
|
backendOrigin,
|
|
scenario,
|
|
} from "./helpers/console-browser.mjs";
|
|
|
|
test("Application routes consistently provide browser trust boundaries", (t) =>
|
|
scenario(t, {}, async (page) => {
|
|
await page.goto(`${appOrigin}/login`);
|
|
const routes = ["/", "/login", "/account/realname", "/security/ssh-keys"];
|
|
for (const path of routes) {
|
|
const response = await fetch(`${appOrigin}${path}`);
|
|
assert.equal(response.status, 200);
|
|
assert.equal(response.headers.get("x-content-type-options"), "nosniff");
|
|
assert.equal(response.headers.get("referrer-policy"), "no-referrer");
|
|
assert.equal(response.headers.get("x-frame-options"), "SAMEORIGIN");
|
|
const policy = new Map(
|
|
(response.headers.get("content-security-policy") || "")
|
|
.split(";")
|
|
.map((directive) => directive.trim().split(/\s+/))
|
|
.filter(([name]) => name)
|
|
.map(([name, ...values]) => [name, values]),
|
|
);
|
|
assert.deepEqual(policy.get("frame-ancestors"), ["'self'"]);
|
|
assert.deepEqual(policy.get("object-src"), ["'none'"]);
|
|
assert.deepEqual(policy.get("base-uri"), ["'self'"]);
|
|
}
|
|
return { routes, consistentFramingMimeAndReferrerDefenses: true };
|
|
}));
|
|
|
|
test("Application navigation sends no referrer to resource servers", (t) =>
|
|
scenario(t, {}, async (page) => {
|
|
await page.goto(`${appOrigin}/login?return_hint=private-test-marker`);
|
|
for (const origin of [appOrigin, backendOrigin]) {
|
|
const pixel = `${origin}/privacy-pixel.svg`;
|
|
let observe;
|
|
const seen = new Promise((resolve) => (observe = resolve));
|
|
await page.context().route(pixel, async (route) => {
|
|
const headers = await route.request().allHeaders();
|
|
observe(Boolean(headers.referer));
|
|
await route.fulfill({
|
|
contentType: "image/svg+xml",
|
|
body: '<svg xmlns="http://www.w3.org/2000/svg" width="1" height="1"/>',
|
|
});
|
|
});
|
|
await page.evaluate((src) => {
|
|
const resource = document.createElement("img");
|
|
resource.alt = "";
|
|
resource.src = src;
|
|
document.body.append(resource);
|
|
}, pixel);
|
|
assert.equal(
|
|
await seen,
|
|
false,
|
|
"Resource requests must receive no referrer",
|
|
);
|
|
}
|
|
return {
|
|
sameAndCrossOriginResourcesChecked: true,
|
|
referrerDisclosed: false,
|
|
};
|
|
}));
|