Skip to content

Commit ba2e692

Browse files
sapphi-redkretajak
authored andcommitted
fix(security): check cross origin requests
1 parent 5ba835f commit ba2e692

File tree

3 files changed

+145
-0
lines changed

3 files changed

+145
-0
lines changed

lib/Server.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2209,6 +2209,32 @@ class Server {
22092209
this.options.onBeforeSetupMiddleware(this);
22102210
}
22112211

2212+
// Register setup cross origin request check for securityAdd commentMore actions
2213+
middlewares.push({
2214+
name: "cross-origin-header-check",
2215+
/**
2216+
* @param {Request} req
2217+
* @param {Response} res
2218+
* @param {NextFunction} next
2219+
* @returns {void}
2220+
*/
2221+
middleware: (req, res, next) => {
2222+
const headers =
2223+
/** @type {{ [key: string]: string | undefined }} */
2224+
(req.headers);
2225+
if (
2226+
headers["sec-fetch-mode"] === "no-cors" &&
2227+
headers["sec-fetch-site"] === "cross-site"
2228+
) {
2229+
res.statusCode = 403;
2230+
res.end("Cross-Origin request blocked");
2231+
return;
2232+
}
2233+
2234+
next();
2235+
},
2236+
});
2237+
22122238
if (typeof this.options.headers !== "undefined") {
22132239
middlewares.push({
22142240
name: "set-headers",

test/e2e/cross-origin-request.test.js

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
"use strict";
2+
3+
const webpack = require("webpack");
4+
const Server = require("../../lib/Server");
5+
const config = require("../fixtures/client-config/webpack.config");
6+
const runBrowser = require("../helpers/run-browser");
7+
const [port1, port2] = require("../ports-map")["cross-origin-request"];
8+
9+
describe("cross-origin requests", () => {
10+
const devServerPort = port1;
11+
const htmlServerPort = port2;
12+
const htmlServerHost = "127.0.0.1";
13+
14+
it("should return 403 for cross-origin no-cors non-module script tag requests", async () => {
15+
const compiler = webpack(config);
16+
const devServerOptions = {
17+
port: devServerPort,
18+
allowedHosts: "auto",
19+
};
20+
const server = new Server(devServerOptions, compiler);
21+
22+
await server.start();
23+
24+
// Start a separate server for serving the HTML file
25+
const http = require("http");
26+
const htmlServer = http.createServer((req, res) => {
27+
res.writeHead(200, { "Content-Type": "text/html" });
28+
res.end(`
29+
<html>
30+
<head>
31+
<script src="http://localhost:${devServerPort}/main.js"></script>
32+
</head>
33+
<body></body>
34+
</html>
35+
`);
36+
});
37+
htmlServer.listen(htmlServerPort, htmlServerHost);
38+
39+
const { page, browser } = await runBrowser();
40+
try {
41+
const pageErrors = [];
42+
43+
page.on("pageerror", (error) => {
44+
pageErrors.push(error);
45+
});
46+
47+
const scriptTagRequest = page.waitForResponse(
48+
`http://localhost:${devServerPort}/main.js`
49+
);
50+
51+
await page.goto(`http://${htmlServerHost}:${htmlServerPort}`);
52+
53+
const response = await scriptTagRequest;
54+
55+
expect(response.status()).toBe(403);
56+
} catch (error) {
57+
throw error;
58+
} finally {
59+
await browser.close();
60+
await server.stop();
61+
htmlServer.close();
62+
}
63+
});
64+
65+
it("should return 200 for cross-origin cors non-module script tag requests", async () => {
66+
const compiler = webpack(config);
67+
const devServerOptions = {
68+
port: devServerPort,
69+
allowedHosts: "auto",
70+
headers: {
71+
"Access-Control-Allow-Origin": "*",
72+
},
73+
};
74+
const server = new Server(devServerOptions, compiler);
75+
76+
await server.start();
77+
78+
// Start a separate server for serving the HTML file
79+
const http = require("http");
80+
const htmlServer = http.createServer((req, res) => {
81+
res.writeHead(200, { "Content-Type": "text/html" });
82+
res.end(`
83+
<html>
84+
<head>
85+
<script src="http://localhost:${devServerPort}/main.js" crossorigin></script>
86+
</head>
87+
<body></body>
88+
</html>
89+
`);
90+
});
91+
htmlServer.listen(htmlServerPort, htmlServerHost);
92+
93+
const { page, browser } = await runBrowser();
94+
try {
95+
const pageErrors = [];
96+
97+
page.on("pageerror", (error) => {
98+
pageErrors.push(error);
99+
});
100+
101+
const scriptTagRequest = page.waitForResponse(
102+
`http://localhost:${devServerPort}/main.js`
103+
);
104+
105+
await page.goto(`http://${htmlServerHost}:${htmlServerPort}`);
106+
107+
const response = await scriptTagRequest;
108+
109+
expect(response.status()).toBe(200);
110+
} catch (error) {
111+
throw error;
112+
} finally {
113+
await browser.close();
114+
await server.stop();
115+
htmlServer.close();
116+
}
117+
});
118+
});

test/ports-map.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ const listOfTests = {
8080
"normalize-option": 1,
8181
"setup-middlewares-option": 1,
8282
"options-request-response": 2,
83+
"cross-origin-request": 2,
8384
};
8485

8586
let startPort = 8089;

0 commit comments

Comments
 (0)