fix(api): block open redirects, add health check and body limits, run as non-root
- safeReturnTo resolves the target against a placeholder origin and rejects backslashes and control characters, so `/\evil.example` and similar payloads can no longer redirect off-site after sign-in. - Add a real unauthenticated /api/health and answer unknown /api/* paths with a JSON 404 instead of the SPA shell. - Limit request bodies: 16 KB for /api/auth/* (read before a session exists), 128 MB for resource create/update and uploads, 10 MB elsewhere. - Run the production image as an unprivileged user and add a Docker HEALTHCHECK against /api/health.
This commit is contained in:
@@ -106,6 +106,27 @@ describe('login throttling', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('post-login redirect', () => {
|
||||
async function redirectAfterLogin(returnTo: string) {
|
||||
const response = await request(app(localConfig()), '/api/auth/login', '198.51.100.40', {
|
||||
method: 'POST',
|
||||
headers: {cookie: 'floci_ui_csrf=csrf-token', 'content-type': 'application/x-www-form-urlencoded', accept: 'application/json'},
|
||||
body: new URLSearchParams({username: 'admin', password: 'correct-horse-battery', csrf: 'csrf-token', returnTo}),
|
||||
})
|
||||
return (await response.json() as {redirectTo: string}).redirectTo
|
||||
}
|
||||
|
||||
test('keeps same-origin paths with their query and fragment', async () => {
|
||||
expect(await redirectAfterLogin('/cloud-explorer/aws/storage?search=logs#top')).toBe('/cloud-explorer/aws/storage?search=logs#top')
|
||||
})
|
||||
|
||||
test('refuses destinations that a browser would resolve to another origin', async () => {
|
||||
for (const returnTo of ['//evil.example', '/\\evil.example', '/\\/evil.example', '/\t/evil.example', 'https://evil.example', '/%0d%0a/evil.example'.replace('%0d%0a', '\r\n')]) {
|
||||
expect(await redirectAfterLogin(returnTo)).toBe('/console/aws')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('OIDC authorization', () => {
|
||||
let privateKey: CryptoKey
|
||||
let jwk: JWK
|
||||
|
||||
Reference in New Issue
Block a user