mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Replace CSP 'nonce-<base64>' directive with 'self' directive (#43553)
This commit is contained in:
parent
90532673fd
commit
5071c74945
19 changed files with 187 additions and 129 deletions
|
@ -27,10 +27,8 @@ in a manner that is inconsistent with `/proc/self/cgroup`
|
|||
|
||||
`csp.rules:`:: A template
|
||||
https://w3c.github.io/webappsec-csp/[content-security-policy] that disables
|
||||
certain unnecessary and potentially insecure capabilities in the browser. All
|
||||
instances of `{nonce}` will be replaced with an automatically generated nonce
|
||||
at load time. We strongly recommend that you keep the default CSP rules that
|
||||
ship with Kibana.
|
||||
certain unnecessary and potentially insecure capabilities in the browser. We
|
||||
strongly recommend that you keep the default CSP rules that ship with Kibana.
|
||||
|
||||
`csp.strict:`:: *Default: `true`* Blocks access to Kibana to any browser that
|
||||
does not enforce even rudimentary CSP rules. In practice, this will disable
|
||||
|
|
|
@ -40,14 +40,12 @@ beforeEach(() => {
|
|||
appendChildSpy = jest.spyOn(document.body, 'appendChild').mockReturnValue({} as any);
|
||||
|
||||
// Mock global fields needed for loading modules.
|
||||
coreWindow.__kbnNonce__ = 'asdf';
|
||||
coreWindow.__kbnBundles__ = {};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
appendChildSpy.mockRestore();
|
||||
createElementSpy.mockRestore();
|
||||
delete coreWindow.__kbnNonce__;
|
||||
delete coreWindow.__kbnBundles__;
|
||||
});
|
||||
|
||||
|
@ -64,7 +62,6 @@ test('`loadPluginBundles` creates a script tag and loads initializer', async ()
|
|||
'/bundles/plugin/plugin-a.bundle.js'
|
||||
);
|
||||
expect(fakeScriptTag.setAttribute).toHaveBeenCalledWith('id', 'kbn-plugin-plugin-a');
|
||||
expect(fakeScriptTag.setAttribute).toHaveBeenCalledWith('nonce', 'asdf');
|
||||
expect(fakeScriptTag.onload).toBeInstanceOf(Function);
|
||||
expect(fakeScriptTag.onerror).toBeInstanceOf(Function);
|
||||
expect(appendChildSpy).toHaveBeenCalledWith(fakeScriptTag);
|
||||
|
|
|
@ -31,7 +31,6 @@ export type UnknownPluginInitializer = PluginInitializer<unknown, Record<string,
|
|||
* @internal
|
||||
*/
|
||||
export interface CoreWindow {
|
||||
__kbnNonce__: string;
|
||||
__kbnBundles__: {
|
||||
[pluginBundleName: string]: UnknownPluginInitializer | undefined;
|
||||
};
|
||||
|
@ -80,9 +79,6 @@ export const loadPluginBundle: LoadPluginBundle = <
|
|||
script.setAttribute('id', `kbn-plugin-${pluginName}`);
|
||||
script.setAttribute('async', '');
|
||||
|
||||
// Add kbnNonce for CSP
|
||||
script.setAttribute('nonce', coreWindow.__kbnNonce__);
|
||||
|
||||
const cleanupTag = () => {
|
||||
clearTimeout(timeout);
|
||||
// Set to null for IE memory leak issue. Webpack does the same thing.
|
||||
|
|
|
@ -57,6 +57,42 @@ const dataPath = (settings, log) => {
|
|||
}
|
||||
};
|
||||
|
||||
const NONCE_STRING = `{nonce}`;
|
||||
// Policies that should include the 'self' source
|
||||
const SELF_POLICIES = Object.freeze(['script-src', 'style-src']);
|
||||
const SELF_STRING = `'self'`;
|
||||
|
||||
const cspRules = (settings, log) => {
|
||||
const rules = _.get(settings, 'csp.rules');
|
||||
if (!rules) {
|
||||
return;
|
||||
}
|
||||
|
||||
const parsed = new Map(rules.map(ruleStr => {
|
||||
const parts = ruleStr.split(/\s+/);
|
||||
return [parts[0], parts.slice(1)];
|
||||
}));
|
||||
|
||||
settings.csp.rules = [...parsed].map(([policy, sourceList]) => {
|
||||
if (sourceList.find(source => source.includes(NONCE_STRING))) {
|
||||
log(`csp.rules no longer supports the {nonce} syntax. Replacing with 'self' in ${policy}`);
|
||||
sourceList = sourceList.filter(source => !source.includes(NONCE_STRING));
|
||||
|
||||
// Add 'self' if not present
|
||||
if (!sourceList.find(source => source.includes(SELF_STRING))) {
|
||||
sourceList.push(SELF_STRING);
|
||||
}
|
||||
}
|
||||
|
||||
if (SELF_POLICIES.includes(policy) && !sourceList.find(source => source.includes(SELF_STRING))) {
|
||||
log(`csp.rules must contain the 'self' source. Automatically adding to ${policy}.`);
|
||||
sourceList.push(SELF_STRING);
|
||||
}
|
||||
|
||||
return `${policy} ${sourceList.join(' ')}`.trim();
|
||||
});
|
||||
};
|
||||
|
||||
const deprecations = [
|
||||
//server
|
||||
unused('server.xsrf.token'),
|
||||
|
@ -69,7 +105,8 @@ const deprecations = [
|
|||
savedObjectsIndexCheckTimeout,
|
||||
rewriteBasePath,
|
||||
configPath,
|
||||
dataPath
|
||||
dataPath,
|
||||
cspRules
|
||||
];
|
||||
|
||||
export const transformDeprecations = createTransform(deprecations);
|
||||
|
|
|
@ -22,13 +22,12 @@ import { transformDeprecations } from './transform_deprecations';
|
|||
|
||||
describe('server/config', function () {
|
||||
describe('transformDeprecations', function () {
|
||||
|
||||
describe('savedObjects.indexCheckTimeout', () => {
|
||||
it('removes the indexCheckTimeout and savedObjects properties', () => {
|
||||
const settings = {
|
||||
savedObjects: {
|
||||
indexCheckTimeout: 123
|
||||
}
|
||||
indexCheckTimeout: 123,
|
||||
},
|
||||
};
|
||||
|
||||
expect(transformDeprecations(settings)).toEqual({});
|
||||
|
@ -38,22 +37,22 @@ describe('server/config', function () {
|
|||
const settings = {
|
||||
savedObjects: {
|
||||
indexCheckTimeout: 123,
|
||||
foo: 'bar'
|
||||
}
|
||||
foo: 'bar',
|
||||
},
|
||||
};
|
||||
|
||||
expect(transformDeprecations(settings)).toEqual({
|
||||
savedObjects: {
|
||||
foo: 'bar'
|
||||
}
|
||||
foo: 'bar',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('logs that the setting is no longer necessary', () => {
|
||||
const settings = {
|
||||
savedObjects: {
|
||||
indexCheckTimeout: 123
|
||||
}
|
||||
indexCheckTimeout: 123,
|
||||
},
|
||||
};
|
||||
|
||||
const log = sinon.spy();
|
||||
|
@ -62,5 +61,124 @@ describe('server/config', function () {
|
|||
sinon.assert.calledWithExactly(log, sinon.match('savedObjects.indexCheckTimeout'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('csp.rules', () => {
|
||||
describe('with nonce source', () => {
|
||||
it('logs a warning', () => {
|
||||
const settings = {
|
||||
csp: {
|
||||
rules: [`script-src 'self' 'nonce-{nonce}'`],
|
||||
},
|
||||
};
|
||||
|
||||
const log = jest.fn();
|
||||
transformDeprecations(settings, log);
|
||||
expect(log.mock.calls).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
"csp.rules no longer supports the {nonce} syntax. Replacing with 'self' in script-src",
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('replaces a nonce', () => {
|
||||
expect(
|
||||
transformDeprecations(
|
||||
{ csp: { rules: [`script-src 'nonce-{nonce}'`] } },
|
||||
jest.fn()
|
||||
).csp.rules
|
||||
).toEqual([`script-src 'self'`]);
|
||||
expect(
|
||||
transformDeprecations(
|
||||
{ csp: { rules: [`script-src 'unsafe-eval' 'nonce-{nonce}'`] } },
|
||||
jest.fn()
|
||||
).csp.rules
|
||||
).toEqual([`script-src 'unsafe-eval' 'self'`]);
|
||||
});
|
||||
|
||||
it('removes a quoted nonce', () => {
|
||||
expect(
|
||||
transformDeprecations(
|
||||
{ csp: { rules: [`script-src 'self' 'nonce-{nonce}'`] } },
|
||||
jest.fn()
|
||||
).csp.rules
|
||||
).toEqual([`script-src 'self'`]);
|
||||
expect(
|
||||
transformDeprecations(
|
||||
{ csp: { rules: [`script-src 'nonce-{nonce}' 'self'`] } },
|
||||
jest.fn()
|
||||
).csp.rules
|
||||
).toEqual([`script-src 'self'`]);
|
||||
});
|
||||
|
||||
it('removes a non-quoted nonce', () => {
|
||||
expect(
|
||||
transformDeprecations(
|
||||
{ csp: { rules: [`script-src 'self' nonce-{nonce}`] } },
|
||||
jest.fn()
|
||||
).csp.rules
|
||||
).toEqual([`script-src 'self'`]);
|
||||
expect(
|
||||
transformDeprecations(
|
||||
{ csp: { rules: [`script-src nonce-{nonce} 'self'`] } },
|
||||
jest.fn()
|
||||
).csp.rules
|
||||
).toEqual([`script-src 'self'`]);
|
||||
});
|
||||
|
||||
it('removes a strange nonce', () => {
|
||||
expect(
|
||||
transformDeprecations(
|
||||
{ csp: { rules: [`script-src 'self' blah-{nonce}-wow`] } },
|
||||
jest.fn()
|
||||
).csp.rules
|
||||
).toEqual([`script-src 'self'`]);
|
||||
});
|
||||
|
||||
it('removes multiple nonces', () => {
|
||||
expect(
|
||||
transformDeprecations(
|
||||
{
|
||||
csp: {
|
||||
rules: [
|
||||
`script-src 'nonce-{nonce}' 'self' blah-{nonce}-wow`,
|
||||
`style-src 'nonce-{nonce}' 'self'`,
|
||||
],
|
||||
},
|
||||
},
|
||||
jest.fn()
|
||||
).csp.rules
|
||||
).toEqual([`script-src 'self'`, `style-src 'self'`]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('without self source', () => {
|
||||
it('logs a warning', () => {
|
||||
const log = jest.fn();
|
||||
transformDeprecations({ csp: { rules: [`script-src 'unsafe-eval'`] } }, log);
|
||||
expect(log.mock.calls).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
"csp.rules must contain the 'self' source. Automatically adding to script-src.",
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('adds self', () => {
|
||||
expect(
|
||||
transformDeprecations({ csp: { rules: [`script-src 'unsafe-eval'`] } }, jest.fn()).csp
|
||||
.rules
|
||||
).toEqual([`script-src 'unsafe-eval' 'self'`]);
|
||||
});
|
||||
});
|
||||
|
||||
it('does not add self to other policies', () => {
|
||||
expect(
|
||||
transformDeprecations({ csp: { rules: [`worker-src blob:`] } }, jest.fn()).csp.rules
|
||||
).toEqual([`worker-src blob:`]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
import {
|
||||
createCSPRuleString,
|
||||
generateCSPNonce,
|
||||
DEFAULT_CSP_RULES,
|
||||
DEFAULT_CSP_STRICT,
|
||||
DEFAULT_CSP_WARN_LEGACY_BROWSERS,
|
||||
|
@ -40,7 +39,7 @@ import {
|
|||
test('default CSP rules', () => {
|
||||
expect(DEFAULT_CSP_RULES).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"script-src 'unsafe-eval' 'nonce-{nonce}'",
|
||||
"script-src 'unsafe-eval' 'self'",
|
||||
"worker-src blob:",
|
||||
"child-src blob:",
|
||||
"style-src 'unsafe-inline' 'self'",
|
||||
|
@ -56,32 +55,8 @@ test('CSP legacy browser warning defaults to enabled', () => {
|
|||
expect(DEFAULT_CSP_WARN_LEGACY_BROWSERS).toBe(true);
|
||||
});
|
||||
|
||||
test('generateCSPNonce() creates a 16 character string', async () => {
|
||||
const nonce = await generateCSPNonce();
|
||||
|
||||
expect(nonce).toHaveLength(16);
|
||||
});
|
||||
|
||||
test('generateCSPNonce() creates a new string on each call', async () => {
|
||||
const nonce1 = await generateCSPNonce();
|
||||
const nonce2 = await generateCSPNonce();
|
||||
|
||||
expect(nonce1).not.toEqual(nonce2);
|
||||
});
|
||||
|
||||
test('createCSPRuleString() converts an array of rules into a CSP header string', () => {
|
||||
const csp = createCSPRuleString([`string-src 'self'`, 'worker-src blob:', 'img-src data: blob:']);
|
||||
|
||||
expect(csp).toMatchInlineSnapshot(`"string-src 'self'; worker-src blob:; img-src data: blob:"`);
|
||||
});
|
||||
|
||||
test('createCSPRuleString() replaces all occurrences of {nonce} if provided', () => {
|
||||
const csp = createCSPRuleString(
|
||||
[`string-src 'self' 'nonce-{nonce}'`, 'img-src data: blob:', `default-src 'nonce-{nonce}'`],
|
||||
'foo'
|
||||
);
|
||||
|
||||
expect(csp).toMatchInlineSnapshot(
|
||||
`"string-src 'self' 'nonce-foo'; img-src data: blob:; default-src 'nonce-foo'"`
|
||||
);
|
||||
});
|
||||
|
|
|
@ -17,13 +17,8 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { randomBytes } from 'crypto';
|
||||
import { promisify } from 'util';
|
||||
|
||||
const randomBytesAsync = promisify(randomBytes);
|
||||
|
||||
export const DEFAULT_CSP_RULES = Object.freeze([
|
||||
`script-src 'unsafe-eval' 'nonce-{nonce}'`,
|
||||
`script-src 'unsafe-eval' 'self'`,
|
||||
'worker-src blob:',
|
||||
'child-src blob:',
|
||||
`style-src 'unsafe-inline' 'self'`,
|
||||
|
@ -33,14 +28,6 @@ export const DEFAULT_CSP_STRICT = true;
|
|||
|
||||
export const DEFAULT_CSP_WARN_LEGACY_BROWSERS = true;
|
||||
|
||||
export async function generateCSPNonce() {
|
||||
return (await randomBytesAsync(12)).toString('base64');
|
||||
}
|
||||
|
||||
export function createCSPRuleString(rules: string[], nonce?: string) {
|
||||
let ruleString = rules.join('; ');
|
||||
if (nonce) {
|
||||
ruleString = ruleString.replace(/\{nonce\}/g, nonce);
|
||||
}
|
||||
return ruleString;
|
||||
export function createCSPRuleString(rules: string[]) {
|
||||
return rules.join('; ');
|
||||
}
|
||||
|
|
|
@ -26,12 +26,6 @@ export const appEntryTemplate = (bundle) => `
|
|||
* context: ${bundle.getContext()}
|
||||
*/
|
||||
|
||||
// ensure the csp nonce is set in the dll
|
||||
import 'dll/set_csp_nonce';
|
||||
|
||||
// set the csp nonce in the primary webpack bundle too
|
||||
__webpack_nonce__ = window.__kbnNonce__;
|
||||
|
||||
// import global polyfills
|
||||
import Symbol_observable from 'symbol-observable';
|
||||
import '@babel/polyfill';
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
var kbnCsp = JSON.parse(document.querySelector('kbn-csp').getAttribute('data'));
|
||||
window.__kbnStrictCsp__ = kbnCsp.strictCsp;
|
||||
window.__kbnNonce__ = kbnCsp.nonce;
|
||||
|
||||
if (window.__kbnStrictCsp__ && window.__kbnCspNotEnforced__) {
|
||||
var legacyBrowserError = document.getElementById('kbn_legacy_browser_error');
|
||||
|
@ -65,7 +64,6 @@ if (window.__kbnStrictCsp__ && window.__kbnCspNotEnforced__) {
|
|||
var dom = document.createElement('script');
|
||||
|
||||
dom.setAttribute('async', '');
|
||||
dom.setAttribute('nonce', window.__kbnNonce__);
|
||||
dom.addEventListener('error', failure);
|
||||
dom.setAttribute('src', file);
|
||||
dom.addEventListener('load', next);
|
||||
|
|
|
@ -26,7 +26,7 @@ import { i18n } from '@kbn/i18n';
|
|||
import { AppBootstrap } from './bootstrap';
|
||||
import { mergeVariables } from './lib';
|
||||
import { fromRoot } from '../../utils';
|
||||
import { generateCSPNonce, createCSPRuleString } from '../../server/csp';
|
||||
import { createCSPRuleString } from '../../server/csp';
|
||||
|
||||
export function uiRenderMixin(kbnServer, server, config) {
|
||||
function replaceInjectedVars(request, injectedVars) {
|
||||
|
@ -222,10 +222,7 @@ export function uiRenderMixin(kbnServer, server, config) {
|
|||
...kbnServer.newPlatform.setup.core.plugins.uiPlugins.public.entries()
|
||||
].map(([id, plugin]) => ({ id, plugin }));
|
||||
|
||||
const nonce = await generateCSPNonce();
|
||||
|
||||
const response = h.view('ui_app', {
|
||||
nonce,
|
||||
strictCsp: config.get('csp.strict'),
|
||||
uiPublicUrl: `${basePath}/ui`,
|
||||
bootstrapScriptUrl: `${basePath}/bundles/app/${app.getId()}/bootstrap.js`,
|
||||
|
@ -261,7 +258,7 @@ export function uiRenderMixin(kbnServer, server, config) {
|
|||
},
|
||||
});
|
||||
|
||||
const csp = createCSPRuleString(config.get('csp.rules'), nonce);
|
||||
const csp = createCSPRuleString(config.get('csp.rules'));
|
||||
response.header('content-security-policy', csp);
|
||||
|
||||
return response;
|
||||
|
|
|
@ -300,6 +300,6 @@ html(lang=locale)
|
|||
block head
|
||||
|
||||
body
|
||||
kbn-csp(data=JSON.stringify({ nonce, strictCsp }))
|
||||
kbn-csp(data=JSON.stringify({ strictCsp }))
|
||||
kbn-injected-metadata(data=JSON.stringify(injectedMetadata))
|
||||
block content
|
||||
|
|
|
@ -132,9 +132,9 @@ block content
|
|||
| #{i18n('common.ui.legacyBrowserMessage', { defaultMessage: 'This Kibana installation has strict security requirements enabled that your current browser does not meet.' })}
|
||||
|
||||
script.
|
||||
// Since this script tag does not contain a nonce, this code will not run
|
||||
// Since this is an unsafe inline script, this code will not run
|
||||
// in browsers that support content security policy(CSP). This is
|
||||
// intentional as we check for the existence of __kbnCspNotEnforced__ in
|
||||
// bootstrap.
|
||||
window.__kbnCspNotEnforced__ = true;
|
||||
script(src=bootstrapScriptUrl, nonce=nonce)
|
||||
script(src=bootstrapScriptUrl)
|
||||
|
|
|
@ -408,10 +408,7 @@ export default class BaseOptimizer {
|
|||
'node_modules',
|
||||
fromRoot('node_modules'),
|
||||
],
|
||||
alias: {
|
||||
...this.uiBundles.getAliases(),
|
||||
'dll/set_csp_nonce$': require.resolve('./dynamic_dll_plugin/public/set_csp_nonce')
|
||||
}
|
||||
alias: this.uiBundles.getAliases(),
|
||||
},
|
||||
|
||||
performance: {
|
||||
|
|
|
@ -57,10 +57,7 @@ function generateDLL(config) {
|
|||
resolve: {
|
||||
extensions: ['.js', '.json'],
|
||||
mainFields: ['browser', 'browserify', 'main'],
|
||||
alias: {
|
||||
...dllAlias,
|
||||
'dll/set_csp_nonce$': require.resolve('./public/set_csp_nonce')
|
||||
},
|
||||
alias: dllAlias,
|
||||
modules: [
|
||||
'webpackShims',
|
||||
fromRoot('webpackShims'),
|
||||
|
|
|
@ -18,10 +18,8 @@
|
|||
*/
|
||||
|
||||
export function dllEntryTemplate(requirePaths = []) {
|
||||
return [
|
||||
`require('dll/set_csp_nonce');`,
|
||||
...requirePaths
|
||||
.map(path => `require('${path}');`)
|
||||
.sort()
|
||||
].join('\n');
|
||||
return requirePaths
|
||||
.map(path => `require('${path}');`)
|
||||
.sort()
|
||||
.join('\n');
|
||||
}
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line camelcase, no-undef
|
||||
__webpack_nonce__ = window.__kbnNonce__;
|
|
@ -34,16 +34,9 @@ export default function ({ getService }) {
|
|||
return [key, parts];
|
||||
}));
|
||||
|
||||
// ensure script-src uses a nonce, and remove it so we can .eql everything else
|
||||
const scriptSrc = parsed.get('script-src');
|
||||
expect(scriptSrc).to.be.an(Array);
|
||||
const nonceIndex = scriptSrc.findIndex(value => value.startsWith(`'nonce-`));
|
||||
expect(nonceIndex).greaterThan(-1);
|
||||
scriptSrc.splice(nonceIndex, 1);
|
||||
|
||||
const entries = Array.from(parsed.entries());
|
||||
expect(entries).to.eql([
|
||||
[ 'script-src', [ '\'unsafe-eval\'' ] ],
|
||||
[ 'script-src', [ '\'unsafe-eval\'', '\'self\'' ] ],
|
||||
[ 'worker-src', [ 'blob:' ] ],
|
||||
[ 'child-src', [ 'blob:' ] ],
|
||||
[ 'style-src', [ '\'unsafe-inline\'', '\'self\'' ] ]
|
||||
|
|
|
@ -9,7 +9,7 @@ import Joi from 'joi';
|
|||
import { schema } from '@kbn/config-schema';
|
||||
import { canRedirectRequest, wrapError, OIDCAuthenticationFlow } from '../../../../../../../plugins/security/server';
|
||||
import { KibanaRequest } from '../../../../../../../../src/core/server';
|
||||
import { createCSPRuleString, generateCSPNonce } from '../../../../../../../../src/legacy/server/csp';
|
||||
import { createCSPRuleString } from '../../../../../../../../src/legacy/server/csp';
|
||||
|
||||
export function initAuthenticateApi({ authc: { login, logout }, config }, server) {
|
||||
|
||||
|
@ -96,12 +96,11 @@ export function initAuthenticateApi({ authc: { login, logout }, config }, server
|
|||
const legacyConfig = server.config();
|
||||
const basePath = legacyConfig.get('server.basePath');
|
||||
|
||||
const nonce = await generateCSPNonce();
|
||||
const cspRulesHeader = createCSPRuleString(legacyConfig.get('csp.rules'), nonce);
|
||||
const cspRulesHeader = createCSPRuleString(legacyConfig.get('csp.rules'));
|
||||
return h.response(`
|
||||
<!DOCTYPE html>
|
||||
<title>Kibana OpenID Connect Login</title>
|
||||
<script nonce="${nonce}">
|
||||
<script>
|
||||
window.location.replace(
|
||||
'${basePath}/api/security/v1/oidc?authenticationResponseURI=' + encodeURIComponent(window.location.href)
|
||||
);
|
||||
|
|
|
@ -48,12 +48,10 @@ export default function({ getService }: FtrProviderContext) {
|
|||
});
|
||||
|
||||
// Check that proxy page is returned with proper headers.
|
||||
const scriptNonce = dom.window.document.querySelector('script')!.getAttribute('nonce');
|
||||
expect(scriptNonce).to.have.length(16);
|
||||
expect(response.headers['content-type']).to.be('text/html; charset=utf-8');
|
||||
expect(response.headers['cache-control']).to.be('private, no-cache, no-store');
|
||||
expect(response.headers['content-security-policy']).to.be(
|
||||
`script-src 'unsafe-eval' 'nonce-${scriptNonce}'; worker-src blob:; child-src blob:; style-src 'unsafe-inline' 'self'`
|
||||
`script-src 'unsafe-eval' 'self'; worker-src blob:; child-src blob:; style-src 'unsafe-inline' 'self'`
|
||||
);
|
||||
|
||||
// Check that script that forwards URL fragment worked correctly.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue