fix relative urls in external url service (#116404) (#117100)

Co-authored-by: Joe Reuter <johannes.reuter@elastic.co>
This commit is contained in:
Kibana Machine 2021-11-02 08:57:03 -04:00 committed by GitHub
parent 0ecffd9a2d
commit 4139f1a0dc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 60 additions and 4 deletions

View file

@ -155,6 +155,40 @@ describe('External Url Service', () => {
});
});
internalRequestScenarios.forEach(({ description, policy, allowExternal }) => {
describe(description, () => {
it('allows relative URLs without absolute path replacing last path segment', () => {
const { setup } = setupService({ location, serverBasePath, policy });
const urlCandidate = `my_other_app?foo=bar`;
const result = setup.validateUrl(urlCandidate);
expect(result).toBeInstanceOf(URL);
expect(result?.toString()).toEqual(`${kibanaRoot}/app/${urlCandidate}`);
});
it('allows relative URLs without absolute path replacing multiple path segments', () => {
const { setup } = setupService({ location, serverBasePath, policy });
const urlCandidate = `/api/my_other_app?foo=bar`;
const result = setup.validateUrl(`..${urlCandidate}`);
expect(result).toBeInstanceOf(URL);
expect(result?.toString()).toEqual(`${kibanaRoot}${urlCandidate}`);
});
if (!allowExternal) {
describe('handles bypass of base path via relative URL', () => {
it('does not allow relative URLs that escape base path', () => {
const { setup } = setupService({ location, serverBasePath, policy: [] });
const urlCandidate = `../../base_path_escape`;
const result = setup.validateUrl(urlCandidate);
expect(result).toBeNull();
});
});
}
});
});
describe('handles protocol resolution bypass', () => {
it('does not allow relative URLs that include a host', () => {
const { setup } = setupService({ location, serverBasePath, policy: [] });
@ -194,7 +228,7 @@ describe('External Url Service', () => {
internalRequestScenarios.forEach(({ description, policy }) => {
describe(description, () => {
it('allows relative URLs', () => {
it('allows relative URLs with absolute path', () => {
const { setup } = setupService({ location, serverBasePath, policy });
const urlCandidate = `/some/path?foo=bar`;
const result = setup.validateUrl(`${serverBasePath}${urlCandidate}`);
@ -214,6 +248,28 @@ describe('External Url Service', () => {
});
});
internalRequestScenarios.forEach(({ description, policy }) => {
describe(description, () => {
it('allows relative URLs without absolute path replacing last path segment', () => {
const { setup } = setupService({ location, serverBasePath, policy });
const urlCandidate = `my_other_app?foo=bar`;
const result = setup.validateUrl(urlCandidate);
expect(result).toBeInstanceOf(URL);
expect(result?.toString()).toEqual(`${kibanaRoot}/app/${urlCandidate}`);
});
it('allows relative URLs without absolute path replacing multiple path segments', () => {
const { setup } = setupService({ location, serverBasePath, policy });
const urlCandidate = `/api/my_other_app?foo=bar`;
const result = setup.validateUrl(`..${urlCandidate}`);
expect(result).toBeInstanceOf(URL);
expect(result?.toString()).toEqual(`${kibanaRoot}${urlCandidate}`);
});
});
});
describe('handles protocol resolution bypass', () => {
it('does not allow relative URLs that include a host', () => {
const { setup } = setupService({ location, serverBasePath, policy: [] });

View file

@ -14,7 +14,7 @@ import { InjectedMetadataSetup } from '../injected_metadata';
import { Sha256 } from '../utils';
interface SetupDeps {
location: Pick<Location, 'origin'>;
location: Pick<Location, 'href'>;
injectedMetadata: InjectedMetadataSetup;
}
@ -52,11 +52,11 @@ function normalizeProtocol(protocol: string) {
const createExternalUrlValidation = (
rules: IExternalUrlPolicy[],
location: Pick<Location, 'origin'>,
location: Pick<Location, 'href'>,
serverBasePath: string
) => {
const base = new URL(location.origin + serverBasePath);
return function validateExternalUrl(next: string) {
const base = new URL(location.href);
const url = new URL(next, base);
const isInternalURL =