diff --git a/lib/renderer/security-warnings.ts b/lib/renderer/security-warnings.ts index 0f6b3782ccc8..92c98130f106 100644 --- a/lib/renderer/security-warnings.ts +++ b/lib/renderer/security-warnings.ts @@ -81,7 +81,7 @@ const isUnsafeEvalEnabled: () => Promise = function () { // Call _executeJavaScript to bypass the world-safe deprecation warning return (webFrame as any)._executeJavaScript(`(${(() => { try { - new Function(''); // eslint-disable-line no-new,no-new-func + eval(window.trustedTypes.emptyScript); // eslint-disable-line no-eval } catch { return false; } diff --git a/spec-main/security-warnings-spec.ts b/spec-main/security-warnings-spec.ts index 40c8a990d05d..217cb916262c 100644 --- a/spec-main/security-warnings-spec.ts +++ b/spec-main/security-warnings-spec.ts @@ -22,6 +22,7 @@ describe('security warnings', () => { let server: http.Server; let w: BrowserWindow; let useCsp = true; + let useTrustedTypes = false; let serverUrl: string; before((done) => { @@ -48,8 +49,11 @@ describe('security warnings', () => { return; } - const cspHeaders = { 'Content-Security-Policy': 'script-src \'self\' \'unsafe-inline\'' }; - response.writeHead(200, useCsp ? cspHeaders : undefined); + const cspHeaders = [ + ...(useCsp ? ['script-src \'self\' \'unsafe-inline\''] : []), + ...(useTrustedTypes ? ['require-trusted-types-for \'script\'; trusted-types *'] : []) + ]; + response.writeHead(200, { 'Content-Security-Policy': cspHeaders }); response.write(file, 'binary'); response.end(); }); @@ -68,6 +72,7 @@ describe('security warnings', () => { afterEach(async () => { useCsp = true; + useTrustedTypes = false; await closeWindow(w); w = null as unknown as any; }); @@ -129,6 +134,22 @@ describe('security warnings', () => { expect(message).to.include('Insecure Content-Security-Policy'); }); + it('should warn about insecure Content-Security-Policy (Trusted Types)', async () => { + w = new BrowserWindow({ + show: false, + webPreferences: { + enableRemoteModule: false, + ...webPreferences + } + }); + + useCsp = false; + useTrustedTypes = true; + w.loadURL(`${serverUrl}/base-page-security.html`); + const [,, message] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning); + expect(message).to.include('Insecure Content-Security-Policy'); + }); + it('should warn about allowRunningInsecureContent', async () => { w = new BrowserWindow({ show: false, diff --git a/typings/internal-ambient.d.ts b/typings/internal-ambient.d.ts index 77267a737e26..b280e882af51 100644 --- a/typings/internal-ambient.d.ts +++ b/typings/internal-ambient.d.ts @@ -272,6 +272,7 @@ declare interface Window { } }; ResizeObserver: ResizeObserver; + trustedTypes: TrustedTypePolicyFactory; } /** @@ -323,3 +324,41 @@ interface ResizeObserverEntry { */ readonly contentRect: DOMRectReadOnly; } + +// https://w3c.github.io/webappsec-trusted-types/dist/spec/#trusted-types + +type TrustedHTML = string; +type TrustedScript = string; +type TrustedScriptURL = string; +type TrustedType = TrustedHTML | TrustedScript | TrustedScriptURL; +type StringContext = 'TrustedHTML' | 'TrustedScript' | 'TrustedScriptURL'; + +// https://w3c.github.io/webappsec-trusted-types/dist/spec/#typedef-trustedtypepolicy + +interface TrustedTypePolicy { + createHTML(input: string, ...arguments: any[]): TrustedHTML; + createScript(input: string, ...arguments: any[]): TrustedScript; + createScriptURL(input: string, ...arguments: any[]): TrustedScriptURL; +} + +// https://w3c.github.io/webappsec-trusted-types/dist/spec/#typedef-trustedtypepolicyoptions + +interface TrustedTypePolicyOptions { + createHTML?: (input: string, ...arguments: any[]) => TrustedHTML; + createScript?: (input: string, ...arguments: any[]) => TrustedScript; + createScriptURL?: (input: string, ...arguments: any[]) => TrustedScriptURL; +} + +// https://w3c.github.io/webappsec-trusted-types/dist/spec/#typedef-trustedtypepolicyfactory + +interface TrustedTypePolicyFactory { + createPolicy(policyName: string, policyOptions: TrustedTypePolicyOptions): TrustedTypePolicy + isHTML(value: any): boolean; + isScript(value: any): boolean; + isScriptURL(value: any): boolean; + readonly emptyHTML: TrustedHTML; + readonly emptyScript: TrustedScript; + getAttributeType(tagName: string, attribute: string, elementNs?: string, attrNs?: string): StringContext | null; + getPropertyType(tagName: string, property: string, elementNs?: string): StringContext | null; + readonly defaultPolicy: TrustedTypePolicy | null; +}