Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: CSP with unsafe-eval detection with Trusted Types #27469

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/renderer/security-warnings.ts
Expand Up @@ -80,7 +80,7 @@ const isUnsafeEvalEnabled: () => Promise<boolean> = 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;
}
Expand Down
25 changes: 23 additions & 2 deletions spec-main/security-warnings-spec.ts
Expand Up @@ -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) => {
Expand All @@ -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();
});
Expand All @@ -68,6 +72,7 @@ describe('security warnings', () => {

afterEach(async () => {
useCsp = true;
useTrustedTypes = false;
await closeWindow(w);
w = null as unknown as any;
});
Expand Down Expand Up @@ -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,
Expand Down
39 changes: 39 additions & 0 deletions typings/internal-ambient.d.ts
Expand Up @@ -199,6 +199,7 @@ declare interface Window {
}
};
ResizeObserver: ResizeObserver;
trustedTypes: TrustedTypePolicyFactory;
}

/**
Expand Down Expand Up @@ -250,3 +251,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;
}