Skip to content

Commit

Permalink
avoid double-slash redirects (mdn#3222)
Browse files Browse the repository at this point in the history
  • Loading branch information
peterbe committed Jun 1, 2021
1 parent 9447dd9 commit c902eb1
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 16 deletions.
21 changes: 21 additions & 0 deletions deployer/aws-lambda/content-origin-request/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,27 @@ exports.handler = async (event) => {
const host = request.headers.host[0].value.toLowerCase();
const qs = request.querystring ? `?${request.querystring}` : "";

// If the URL was something like `https://domain/en-US/search/`, our code
// would make a that a redirect to `/en-US/search` (stripping the trailing slash).
// But if it was `https://domain/en-US/search/` it'd make a redirect
// to `//en-US/search`.
// However, if pathname starts with `//` the Location header might look
// relative but it's actually an absolute URL.
// A 302 redirect from `https://domain//evil.com/` actually ends open
// opening `https://evil.com/` in the browser, because the browser will
// treat `//evil.com/ == https://evil.com/`.
// Prevent any pathnames that start with a double //.
if (request.uri.startsWith("//")) {
return {
status: 404,
statusDescription: "Not found",
headers: {
"content-type": [{ key: "Content-Type", value: "text/plain" }],
},
body: "URL pathname can't start with //\n",
};
}

const { url, status } = resolveFundamental(request.uri);
if (url) {
// TODO: Do we want to add the query string to the redirect?
Expand Down
42 changes: 26 additions & 16 deletions deployer/aws-lambda/content-origin-request/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@ async function catchall(req, res) {
};

event.Records = [{ cf }];
// console.log("EVENT...");
// console.log(event);
// console.log(JSON.stringify(event, null, 3));
const handle = await handler(event);
if (handle === cf.request) {
// The request is allowed to pass through.
Expand All @@ -59,26 +56,39 @@ async function catchall(req, res) {
res.end(`${msg}\n`);
} else if (handle.status) {
// It's a redirect.
// console.log(JSON.stringify(handle, null, 3));
let path = null;
for (const headers of Object.values(handle.headers)) {
let location = null;
for (const headers of Object.values(handle.headers || {})) {
for (const header of headers) {
res.setHeader(header.key, header.value);
if (header.key.toLowerCase() === "location") {
path = header.value;
location = header.value;
}
}
}
console.log(
`${
handle.status === 302
? kleur.green(handle.status)
: kleur.yellow(handle.status)
} redirect to ${kleur.bold(path)}`
);
if (handle.status >= 300 && handle.status < 400) {
console.log(
`${
handle.status === 302
? kleur.green(handle.status)
: kleur.yellow(handle.status)
} redirect to ${kleur.bold(location)}`
);
if (location) {
res.setHeader("Location", location);
}
} else if (handle.status >= 400) {
console.log(
`${
handle.status >= 500
? kleur.red(handle.status)
: kleur.yellow(handle.status)
} '${handle.body.trim()}'`
);
} else {
console.log(`${kleur.gree(handle.status)} '${handle.body.trim()}'`);
}
res.statusCode = handle.status;
res.setHeader("Location", path);
res.end("");
res.end(handle.body || "");
} else {
console.warn(JSON.stringify(handle, null, 3));
res.statusCode = 500;
Expand Down
10 changes: 10 additions & 0 deletions deployer/aws-lambda/content-origin-request/server.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ async function get(uri, headers = {}) {
headers,
followRedirect: false,
retry: 0,
throwHttpErrors: false,
});
return response;
}
Expand Down Expand Up @@ -186,3 +187,12 @@ describe("always check for fundamental redirects first", () => {
}
});
});

describe("avoid double-slash redirects", () => {
it("should 404 on any pathname that starts with //", async () => {
const r = await get(`//en-US/search/`);
expect(r.statusCode).toBe(404);
expect(r.headers["location"]).toBeFalsy();
expect(r.body).toContain("URL pathname can't start with //");
});
});

0 comments on commit c902eb1

Please sign in to comment.