mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
A content security policy is a great addition to the protections built into Kibana, but it's not effective in older browsers (like IE11) that do not enforce the policy. When CSP strict mode is enabled, right before the Kibana app is bootstrapped, a basic safety check is performed to see if "naked" inline scripts are rejected. If inline scripting is allowed by the browser, then an error message is presented to the user and Kibana never attempts to bootstrap.
This commit is contained in:
parent
4ce465c8a7
commit
652f4bb49b
6 changed files with 119 additions and 56 deletions
|
@ -2,6 +2,7 @@
|
|||
== Using Kibana in a production environment
|
||||
|
||||
* <<configuring-kibana-shield>>
|
||||
* <<csp-strict-mode>>
|
||||
* <<enabling-ssl>>
|
||||
* <<load-balancing>>
|
||||
|
||||
|
@ -36,6 +37,25 @@ which users can load which dashboards.
|
|||
For information about setting up Kibana users, see
|
||||
{kibana-ref}/using-kibana-with-security.html[Configuring security in Kibana].
|
||||
|
||||
[float]
|
||||
[[csp-strict-mode]]
|
||||
=== Require Content Security Policy
|
||||
|
||||
Kibana uses a Content Security Policy to help prevent the browser from allowing
|
||||
unsafe scripting, but older browsers will silently ignore this policy. If your
|
||||
organization does not need to support Internet Explorer 11 or much older
|
||||
versions of our other supported browsers, we recommend that you enable Kibana's
|
||||
`strict` mode for content security policy, which will block access to Kibana
|
||||
for any browser that does not enforce even a rudimentary set of CSP
|
||||
protections.
|
||||
|
||||
To do this, set `csp.strict` to `true` in your `kibana.yml`:
|
||||
|
||||
--------
|
||||
csp.strict: true
|
||||
--------
|
||||
|
||||
|
||||
[float]
|
||||
[[enabling-ssl]]
|
||||
=== Enabling SSL
|
||||
|
|
|
@ -21,6 +21,8 @@ you'll need to update your `kibana.yml` file. You can also enable SSL and set a
|
|||
|
||||
`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.
|
||||
|
||||
`csp.strict:`:: *Default: `false`* Blocks access to Kibana to any browser that does not enforce even rudimentary CSP rules. In practice, this will disable support for older, less safe browsers like Internet Explorer.
|
||||
|
||||
`elasticsearch.customHeaders:`:: *Default: `{}`* Header names and values to send to Elasticsearch. Any custom headers
|
||||
cannot be overwritten by client-side headers, regardless of the `elasticsearch.requestHeadersWhitelist` configuration.
|
||||
|
||||
|
|
|
@ -95,6 +95,7 @@ export default () => Joi.object({
|
|||
|
||||
csp: Joi.object({
|
||||
rules: Joi.array().items(Joi.string()).default(DEFAULT_CSP_RULES),
|
||||
strict: Joi.boolean().default(false),
|
||||
}).default(),
|
||||
|
||||
cpu: Joi.object({
|
||||
|
|
|
@ -1,59 +1,70 @@
|
|||
window.onload = function () {
|
||||
var files = [
|
||||
'{{dllBundlePath}}/vendors.bundle.dll.js',
|
||||
'{{regularBundlePath}}/commons.bundle.js',
|
||||
'{{regularBundlePath}}/{{appId}}.bundle.js'
|
||||
];
|
||||
|
||||
var failure = function () {
|
||||
// make subsequent calls to failure() noop
|
||||
failure = function () {};
|
||||
|
||||
var err = document.createElement('h1');
|
||||
err.style['color'] = 'white';
|
||||
err.style['font-family'] = 'monospace';
|
||||
err.style['text-align'] = 'center';
|
||||
err.style['background'] = '#F44336';
|
||||
err.style['padding'] = '25px';
|
||||
err.innerText = document.querySelector('[data-error-message]').dataset.errorMessage;
|
||||
|
||||
document.body.innerHTML = err.outerHTML;
|
||||
if (window.__kbnStrictCsp__ && window.__kbnCspNotEnforced__) {
|
||||
var legacyBrowserError = document.getElementById('kbn_legacy_browser_error');
|
||||
legacyBrowserError.style.display = 'flex';
|
||||
} else {
|
||||
if (!window.__kbnCspNotEnforced__ && window.console) {
|
||||
window.console.log("^ A single error about an inline script not firing due to content security policy is expected!");
|
||||
}
|
||||
var loadingMessage = document.getElementById('kbn_loading_message');
|
||||
loadingMessage.style.display = 'flex';
|
||||
|
||||
function loadStyleSheet(path) {
|
||||
var dom = document.createElement('link');
|
||||
window.onload = function () {
|
||||
var files = [
|
||||
'{{dllBundlePath}}/vendors.bundle.dll.js',
|
||||
'{{regularBundlePath}}/commons.bundle.js',
|
||||
'{{regularBundlePath}}/{{appId}}.bundle.js'
|
||||
];
|
||||
|
||||
dom.addEventListener('error', failure);
|
||||
dom.setAttribute('rel', 'stylesheet');
|
||||
dom.setAttribute('href', path);
|
||||
document.head.appendChild(dom);
|
||||
}
|
||||
var failure = function () {
|
||||
// make subsequent calls to failure() noop
|
||||
failure = function () {};
|
||||
|
||||
function createJavascriptElement(path) {
|
||||
var dom = document.createElement('script');
|
||||
var err = document.createElement('h1');
|
||||
err.style['color'] = 'white';
|
||||
err.style['font-family'] = 'monospace';
|
||||
err.style['text-align'] = 'center';
|
||||
err.style['background'] = '#F44336';
|
||||
err.style['padding'] = '25px';
|
||||
err.innerText = document.querySelector('[data-error-message]').dataset.errorMessage;
|
||||
|
||||
dom.setAttribute('async', '');
|
||||
dom.addEventListener('error', failure);
|
||||
dom.setAttribute('src', file);
|
||||
dom.addEventListener('load', next);
|
||||
document.head.appendChild(dom);
|
||||
}
|
||||
document.body.innerHTML = err.outerHTML;
|
||||
}
|
||||
|
||||
{{#each styleSheetPaths}}
|
||||
loadStyleSheet('{{this}}');
|
||||
{{/each}}
|
||||
function loadStyleSheet(path) {
|
||||
var dom = document.createElement('link');
|
||||
|
||||
(function next() {
|
||||
var file = files.shift();
|
||||
if (!file) return;
|
||||
dom.addEventListener('error', failure);
|
||||
dom.setAttribute('rel', 'stylesheet');
|
||||
dom.setAttribute('href', path);
|
||||
document.head.appendChild(dom);
|
||||
}
|
||||
|
||||
var dom = document.createElement('script');
|
||||
function createJavascriptElement(path) {
|
||||
var dom = document.createElement('script');
|
||||
|
||||
dom.setAttribute('async', '');
|
||||
dom.setAttribute('nonce', window.__webpack_nonce__);
|
||||
dom.addEventListener('error', failure);
|
||||
dom.setAttribute('src', file);
|
||||
dom.addEventListener('load', next);
|
||||
document.head.appendChild(dom);
|
||||
}());
|
||||
};
|
||||
dom.setAttribute('async', '');
|
||||
dom.addEventListener('error', failure);
|
||||
dom.setAttribute('src', file);
|
||||
dom.addEventListener('load', next);
|
||||
document.head.appendChild(dom);
|
||||
}
|
||||
|
||||
{{#each styleSheetPaths}}
|
||||
loadStyleSheet('{{this}}');
|
||||
{{/each}}
|
||||
|
||||
(function next() {
|
||||
var file = files.shift();
|
||||
if (!file) return;
|
||||
|
||||
var dom = document.createElement('script');
|
||||
|
||||
dom.setAttribute('async', '');
|
||||
dom.setAttribute('nonce', window.__webpack_nonce__);
|
||||
dom.addEventListener('error', failure);
|
||||
dom.setAttribute('src', file);
|
||||
dom.addEventListener('load', next);
|
||||
document.head.appendChild(dom);
|
||||
}());
|
||||
};
|
||||
}
|
||||
|
|
|
@ -181,6 +181,7 @@ export function uiRenderMixin(kbnServer, server, config) {
|
|||
|
||||
const response = h.view('ui_app', {
|
||||
nonce,
|
||||
strictCsp: config.get('csp.strict'),
|
||||
uiPublicUrl: `${basePath}/ui`,
|
||||
bootstrapScriptUrl: `${basePath}/bundles/app/${app.getId()}/bootstrap.js`,
|
||||
i18n: (id, options) => i18n.translate(id, options),
|
||||
|
|
|
@ -16,12 +16,21 @@ block content
|
|||
background-color: #F5F7FA;
|
||||
}
|
||||
|
||||
.kibanaWelcomeText {
|
||||
color: #222;
|
||||
font-size: 14px;
|
||||
.kibanaWelcomeTitle {
|
||||
color: #000;
|
||||
font-size: 20px;
|
||||
font-family: Sans-serif;
|
||||
margin-top: 20px;
|
||||
color: #666;
|
||||
animation: fadeIn 1s ease-in-out;
|
||||
animation-fill-mode: forwards;
|
||||
opacity: 0;
|
||||
animation-delay: 1.0s;
|
||||
}
|
||||
|
||||
.kibanaWelcomeText {
|
||||
font-size: 14px;
|
||||
font-family: Sans-serif;
|
||||
color: #343741;
|
||||
animation: fadeIn 1s ease-in-out;
|
||||
animation-fill-mode: forwards;
|
||||
opacity: 0;
|
||||
|
@ -35,6 +44,10 @@ block content
|
|||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.kibanaLoaderWrap + * {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.kibanaLoader {
|
||||
height: 128px;
|
||||
width: 128px;
|
||||
|
@ -101,8 +114,7 @@ block content
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.kibanaWelcomeView
|
||||
.kibanaWelcomeView(id="kbn_loading_message", style="display: none;")
|
||||
.kibanaLoaderWrap
|
||||
.kibanaLoader
|
||||
.kibanaWelcomeLogoCircle
|
||||
|
@ -110,6 +122,22 @@ block content
|
|||
.kibanaWelcomeText(data-error-message=i18n('common.ui.welcomeErrorMessage', { defaultMessage: 'Kibana did not load properly. Check the server output for more information.' }))
|
||||
| #{i18n('common.ui.welcomeMessage', { defaultMessage: 'Loading Kibana' })}
|
||||
|
||||
.kibanaWelcomeView(id="kbn_legacy_browser_error", style="display: none;")
|
||||
.kibanaLoaderWrap
|
||||
.kibanaWelcomeLogoCircle
|
||||
.kibanaWelcomeLogo
|
||||
h2.kibanaWelcomeTitle
|
||||
| #{i18n('common.ui.legacyBrowserTitle', { defaultMessage: 'Please upgrade your browser' })}
|
||||
.kibanaWelcomeText
|
||||
| #{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
|
||||
// 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(nonce=nonce).
|
||||
window.__kbnStrictCsp__ = !{strictCsp};
|
||||
window.__webpack_nonce__ = '!{nonce}';
|
||||
script(src=bootstrapScriptUrl, nonce=nonce)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue