middleware do not prohibits
Signed-off-by: Kenneth Obsequio <k80308392@gmail.com>
This commit is contained in:
@@ -76,6 +76,13 @@ const ALLOWED = (process.env.ALLOWED_ORIGINS || process.env.APP_URL || '')
|
||||
|
||||
const MUTATION_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);
|
||||
|
||||
// Routes that legitimately receive a top-level cross-site navigation — a third-party
|
||||
// IdP (Google) redirects the browser here after consent, so Sec-Fetch-Site is
|
||||
// correctly "cross-site" even though the request is a real browser, not an attacker.
|
||||
// Still gated on GET + navigate|document below, so this doesn't open the route to
|
||||
// cross-site fetch()/XHR — only actual browser navigations.
|
||||
const CROSS_SITE_NAVIGATION_PATHS = new Set(['/google/callback']);
|
||||
|
||||
// Valid Sec-Fetch-Mode + Sec-Fetch-Dest combinations expected on this API server.
|
||||
const VALID_FETCH_COMBOS = new Set([
|
||||
'cors|empty', // standard fetch() from cross-origin SPA
|
||||
@@ -93,8 +100,12 @@ module.exports = function originGuard(req, res, next) {
|
||||
if (req.method === 'OPTIONS') return next(); // preflight — handled by cors()
|
||||
|
||||
// ── Layer 1a: Sec-Fetch-Site must be present and not cross-site ───────────
|
||||
// Exception: OAuth callback routes receive a real cross-site top-level navigation
|
||||
// from the IdP's domain — allowed only in combination with the navigate|document
|
||||
// check in Layer 1b, so cross-site fetch()/XHR is still rejected everywhere.
|
||||
const fetchSite = req.headers['sec-fetch-site'];
|
||||
if (!fetchSite || fetchSite === 'cross-site') {
|
||||
const isCrossSiteNavigationRoute = req.method === 'GET' && CROSS_SITE_NAVIGATION_PATHS.has(req.path);
|
||||
if (!fetchSite || (fetchSite === 'cross-site' && !isCrossSiteNavigationRoute)) {
|
||||
return R.error(res, 'Forbidden.', 403);
|
||||
}
|
||||
|
||||
@@ -104,6 +115,9 @@ module.exports = function originGuard(req, res, next) {
|
||||
if (!fetchMode || !fetchDest || !VALID_FETCH_COMBOS.has(`${fetchMode}|${fetchDest}`)) {
|
||||
return R.error(res, 'Forbidden.', 403);
|
||||
}
|
||||
if (isCrossSiteNavigationRoute && `${fetchMode}|${fetchDest}` !== 'navigate|document') {
|
||||
return R.error(res, 'Forbidden.', 403);
|
||||
}
|
||||
|
||||
// ── Layer 2: At least one browser-native fingerprint header must be present ─
|
||||
if (!req.headers['sec-ch-ua'] && !req.headers['accept-language']) {
|
||||
|
||||
Reference in New Issue
Block a user