diff --git a/index.js b/index.js index 844d560..b9b8b37 100644 --- a/index.js +++ b/index.js @@ -451,11 +451,19 @@ export function installGuard(server, guard, { audit, loginPath, logoutPath }) { // Cross-origin form posts are rejected: the login form must come from this host. // Hostname-level comparison tolerates port/case differences that proxies // or alternate listeners introduce, while still blocking foreign sites. + // `Origin: null` (opaque contexts: sandboxed iframes, privacy proxies, + // browser isolation) carries no usable origin information — treat it like + // an absent header instead of rejecting real users. const origin = req.headers.origin const host = req.headers.host const ip = clientIp(req) const ua = req.headers['user-agent'] ?? '' - if (typeof origin === 'string' && typeof host === 'string' && !sameHost(origin, host)) { + if ( + typeof origin === 'string' && + origin !== 'null' && + typeof host === 'string' && + !sameHost(origin, host) + ) { audit.write({ event: 'login-fail', username: '', diff --git a/test.mjs b/test.mjs index 6110237..4170e09 100644 --- a/test.mjs +++ b/test.mjs @@ -94,6 +94,10 @@ assert.match(await r.text(), /非法请求来源/) r = await post('/panel-auth/login', 'username=admin&password=s3cret-pass&next=%2F', { Origin: 'http://127.0.0.1:9999' }) assert.equal(r.status, 303) +// 5d. `Origin: null` (opaque context: privacy proxy / sandboxed iframe) → tolerated +r = await post('/panel-auth/login', 'username=admin&password=s3cret-pass&next=%2F', { Origin: 'null' }) +assert.equal(r.status, 303) + // 6. POST login with correct credentials → 303 + cookie + next r = await post('/panel-auth/login', 'username=admin&password=s3cret-pass&next=%2Fsome%2Fpage') assert.equal(r.status, 303)