fix: treat Origin: null as absent instead of rejecting login

The audit diagnostics showed the real browser posting the login form with
Origin: null (opaque context — sandboxed iframe, privacy proxy, or browser
isolation product), which is not an attack signal. Skip the origin check
for the literal "null" value; real cross-site posts with a concrete
foreign origin are still rejected.

Tests: Origin:null POST tolerated, foreign origin still 403.
This commit is contained in:
dsh
2026-08-16 01:43:13 -04:00
parent 1794fe98c2
commit 000ca41501
2 changed files with 13 additions and 1 deletions
+9 -1
View File
@@ -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. // Cross-origin form posts are rejected: the login form must come from this host.
// Hostname-level comparison tolerates port/case differences that proxies // Hostname-level comparison tolerates port/case differences that proxies
// or alternate listeners introduce, while still blocking foreign sites. // 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 origin = req.headers.origin
const host = req.headers.host const host = req.headers.host
const ip = clientIp(req) const ip = clientIp(req)
const ua = req.headers['user-agent'] ?? '' 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({ audit.write({
event: 'login-fail', event: 'login-fail',
username: '', username: '',
+4
View File
@@ -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' }) 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) 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 // 6. POST login with correct credentials → 303 + cookie + next
r = await post('/panel-auth/login', 'username=admin&password=s3cret-pass&next=%2Fsome%2Fpage') r = await post('/panel-auth/login', 'username=admin&password=s3cret-pass&next=%2Fsome%2Fpage')
assert.equal(r.status, 303) assert.equal(r.status, 303)