From 0d5d555f4523ddfcf4379da07f289929e94b9e78 Mon Sep 17 00:00:00 2001 From: Matej Melko Date: Fri, 22 Dec 2023 14:56:52 +0100 Subject: [PATCH] fix: Add a sanitization of the redirect_uri in the form auth to prevent XSS --- .../src/form/login/form-auth-login-service.ts | 17 ++++++++++++-- packages/oauth/src/utils/urls.ts | 22 +++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/packages/oauth/src/form/login/form-auth-login-service.ts b/packages/oauth/src/form/login/form-auth-login-service.ts index 4edae91e..cb1f6f93 100644 --- a/packages/oauth/src/form/login/form-auth-login-service.ts +++ b/packages/oauth/src/form/login/form-auth-login-service.ts @@ -1,7 +1,15 @@ import { hawtio } from '@hawtio/react' import { log } from '../../globals' import { oAuthService } from '../../oauth-service' -import { FetchOptions, fetchPath, joinPaths, redirect, relToAbsUrl } from '../../utils' +import { + FetchOptions, + fetchPath, + joinPaths, + redirect, + relToAbsUrl, + sanitizeUri, + validateRedirectURI, +} from '../../utils' import { FORM_TOKEN_STORAGE_KEY } from '../globals' export type ValidationCallback = { @@ -58,7 +66,12 @@ class FormAuthLoginService { const currentUri = new URL(window.location.href) const searchParams: URLSearchParams = currentUri.searchParams if (searchParams.has('redirect_uri')) { - return searchParams.get('redirect_uri') as string + const uri = new URL(searchParams.get('redirect_uri') as string) + if (validateRedirectURI(uri)) { + return sanitizeUri(uri) + } else { + log.error('invalid redirect_uri', uri.toString()) + } } return relToAbsUrl(hawtio.getBasePath() || window.location.origin) diff --git a/packages/oauth/src/utils/urls.ts b/packages/oauth/src/utils/urls.ts index b37f32bb..9298faa9 100644 --- a/packages/oauth/src/utils/urls.ts +++ b/packages/oauth/src/utils/urls.ts @@ -50,6 +50,28 @@ export function logoutRedirect(redirectUri: URL): void { }) } +export function validateRedirectURI(redirectUri: URL) { + const currentUrl = new URL(window.location.href) + const { hostname, port, protocol } = redirectUri + return ( + hostname === currentUrl.hostname && + port === currentUrl.port && + protocol === currentUrl.protocol && + ['http:', 'https:'].includes(protocol) + ) +} + +export function sanitizeUri(url: URL) { + const searchParams = url.searchParams + + if (searchParams.toString() !== '') { + searchParams.forEach((value, key) => { + searchParams.set(key, encodeURIComponent(value)) + }) + } + return url.href +} + export function redirect(target: URL) { log.debug('Redirecting to URI:', target) // Redirect to the target URI