@@ -23,13 +23,33 @@ export type CspDirectiveName =
2323 | 'report-uri'
2424 | 'report-to'
2525 | 'form-action'
26- | 'object-src' ;
26+ | 'object-src'
27+ | 'child-src'
28+ | 'manifest-src'
29+ | 'media-src'
30+ | 'object-src'
31+ | 'prefetch-src'
32+ | 'script-src-elem'
33+ | 'script-src-attr'
34+ | 'style-src-elem'
35+ | 'style-src-attr' ;
2736
2837/**
2938 * The default report only directives rules
3039 */
3140export const defaultReportOnlyRules : Partial < Record < CspDirectiveName , string [ ] > > = {
3241 'form-action' : [ `'report-sample'` , `'self'` ] ,
42+ 'default-src' : [ `'report-sample'` , `'none'` ] ,
43+ 'font-src' : [ `'report-sample'` , `'self'` ] ,
44+ 'img-src' : [ `'report-sample'` , `'self'` , 'data:' ] ,
45+ 'connect-src' : [
46+ `'report-sample'` ,
47+ `'self'` ,
48+ // TODO: Ideally, Core would not know about these endpoints, as they are governed by the Telemetry plugin.
49+ // This can be improved once https://github.com/elastic/kibana/issues/181812 is implemented.
50+ 'telemetry.elastic.co' ,
51+ 'telemetry-staging.elastic.co' ,
52+ ] ,
3353} ;
3454
3555/**
@@ -55,6 +75,29 @@ export const additionalRules: Partial<Record<CspDirectiveName, string[]>> = {
5575 'frame-src' : [ `'self'` ] ,
5676} ;
5777
78+ /**
79+ * Child directives that should inherit from `default-src` if not explicitly set.
80+ * Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/default-src
81+ */
82+ export const defaultSrcChildDirectives : CspDirectiveName [ ] = [
83+ 'child-src' ,
84+ 'connect-src' ,
85+ 'font-src' ,
86+ 'frame-src' ,
87+ 'img-src' ,
88+ 'manifest-src' ,
89+ 'media-src' ,
90+ 'object-src' ,
91+ 'prefetch-src' ,
92+ 'script-src' ,
93+ 'script-src-elem' ,
94+ 'script-src-attr' ,
95+ 'style-src' ,
96+ 'style-src-elem' ,
97+ 'style-src-attr' ,
98+ 'worker-src' ,
99+ ] ;
100+
58101interface CspConfigDirectives {
59102 enforceDirectives : Map < CspDirectiveName , string [ ] > ;
60103 reportOnlyDirectives : Map < CspDirectiveName , string [ ] > ;
@@ -80,6 +123,14 @@ export class CspDirectives {
80123 directive . delete ( `'none'` ) ;
81124 }
82125 directive . add ( normalizedDirectiveValue ) ;
126+
127+ // If we are testing default-src 'none', then we need to add all expected child directives to the report-only policy
128+ // to prevent reports from being generated for those child directives.
129+ const enforcingDefaultSrcChildDirective =
130+ enforce && defaultSrcChildDirectives . includes ( directiveName ) ;
131+ if ( this . isTestingDefaultSrc ( ) && enforcingDefaultSrcChildDirective ) {
132+ this . addDirectiveValue ( directiveName , directiveValue , false ) ;
133+ }
83134 }
84135
85136 clearDirectiveValues ( directiveName : CspDirectiveName ) {
@@ -106,6 +157,17 @@ export class CspDirectives {
106157 . join ( '; ' ) ;
107158 }
108159
160+ /**
161+ * Determines if we are currently testing the default-src 'none' configuration.
162+ * @returns True if we are testing default-src 'none', false otherwise.
163+ */
164+ private isTestingDefaultSrc ( ) : boolean {
165+ return this . reportOnlyDirectives . has ( 'default-src' ) &&
166+ this . reportOnlyDirectives . get ( 'default-src' ) ?. has ( `'none'` )
167+ ? true
168+ : false ;
169+ }
170+
109171 static fromConfig (
110172 firstConfig : CspConfigType ,
111173 ...otherConfigs : Array < Partial < CspConfigType > >
@@ -116,17 +178,19 @@ export class CspDirectives {
116178 ) ;
117179 const cspDirectives = new CspDirectives ( ) ;
118180
119- // combining `default` directive configurations
120- Object . entries ( defaultRules ) . forEach ( ( [ key , values ] ) => {
181+ // combining `default` report only directive configurations
182+ // it's important to add these before the enforced directives below so that we can handle report-only updates
183+ // in response to enforced directives (e.g., default-src 'none' testing)
184+ Object . entries ( defaultReportOnlyRules ) . forEach ( ( [ key , values ] ) => {
121185 values ?. forEach ( ( value ) => {
122- cspDirectives . addDirectiveValue ( key as CspDirectiveName , value ) ;
186+ cspDirectives . addDirectiveValue ( key as CspDirectiveName , value , false ) ;
123187 } ) ;
124188 } ) ;
125189
126- // combining `default` report only directive configurations
127- Object . entries ( defaultReportOnlyRules ) . forEach ( ( [ key , values ] ) => {
190+ // combining `default` directive configurations
191+ Object . entries ( defaultRules ) . forEach ( ( [ key , values ] ) => {
128192 values ?. forEach ( ( value ) => {
129- cspDirectives . addDirectiveValue ( key as CspDirectiveName , value , false ) ;
193+ cspDirectives . addDirectiveValue ( key as CspDirectiveName , value ) ;
130194 } ) ;
131195 } ) ;
132196
0 commit comments