diff --git a/tools/applicationinsights-web-snippet/README.md b/tools/applicationinsights-web-snippet/README.md index 0a75c9a70..440cfae03 100644 --- a/tools/applicationinsights-web-snippet/README.md +++ b/tools/applicationinsights-web-snippet/README.md @@ -45,6 +45,10 @@ let config = {connectionString: "InstrumentationKey=xxx", sri: true}; More details on web snippet, see [Web Snippet](https://github.com/microsoft/ApplicationInsights-JS#snippet-setup-ignore-if-using-npm-setup). +### Trusted Types Support (available since v1.2.2) +For restrictions like require-trusted-types-for 'script', check [url policy check](./trustedTypeSupport.md) +For restrictions like script-src 'self' ..., check [add nounce when inject script]() + ## Build ``` npm install -g grunt-cli diff --git a/tools/applicationinsights-web-snippet/Tests/manual/cspUsePolicyTest.html b/tools/applicationinsights-web-snippet/Tests/manual/cspUsePolicyTest.html new file mode 100644 index 000000000..26740e988 --- /dev/null +++ b/tools/applicationinsights-web-snippet/Tests/manual/cspUsePolicyTest.html @@ -0,0 +1,84 @@ + + + +
+ + + + + + + + + + + + + + + diff --git a/tools/applicationinsights-web-snippet/src/snippet.ts b/tools/applicationinsights-web-snippet/src/snippet.ts index 9e3b83cdd..748af9f93 100644 --- a/tools/applicationinsights-web-snippet/src/snippet.ts +++ b/tools/applicationinsights-web-snippet/src/snippet.ts @@ -30,6 +30,7 @@ declare var cfg:ISnippetConfig; let strGetMethod = "GET"; let sdkInstanceName = "appInsightsSDK"; // required for Initialization to find the current instance let aiName = cfg.name || "appInsights"; // provide non default instance name through snipConfig name value + let policyName = cfg.pn || "aiPolicy"; if (cfg.name || win[sdkInstanceName]) { // Only set if supplied or another name is defined to avoid polluting the global namespace win[sdkInstanceName] = aiName; @@ -304,9 +305,44 @@ declare var cfg:ISnippetConfig; loadFailed = false; } + function create_policy() { + // Function to handle URL validation + function validateURL(urlString: string): string | null { + try { + const url = new URL(urlString); + if (url.host && url.host === "js.monitor.azure.com") { + return urlString; + } else { + handleInvalidURL(urlString); + } + } catch { + handleInvalidURL(urlString); + } + } + + // Function to handle reporting failures + function handleInvalidURL(urlString: string) { + _reportFailure("AI policy blocked URL: " + urlString); + } + + return (window as any).trustedTypes?.createPolicy(policyName, { + createScriptURL: validateURL + }); + } + + const _createScript = (src: string) => { let scriptElement : HTMLElement = doc.createElement(scriptText); - (scriptElement as any)["src"] = src; + if (cfg.pl){ + if (cfg.ttp && cfg.ttp.createScript) { + (scriptElement as any)["src"] = cfg.ttp.createScriptURL(src); + } else { + (scriptElement as any)["src"] = create_policy().createScriptURL(src); + } + } else { + (scriptElement as any)["src"] = src; + } + if (integrity){ // Set the integrity attribute to the script tag if integrity is provided (scriptElement as any).integrity = integrity; diff --git a/tools/applicationinsights-web-snippet/src/type.ts b/tools/applicationinsights-web-snippet/src/type.ts index ede09f010..6d817e852 100644 --- a/tools/applicationinsights-web-snippet/src/type.ts +++ b/tools/applicationinsights-web-snippet/src/type.ts @@ -12,6 +12,16 @@ export interface SdkLoaderConfig { cr?: boolean; dle?: boolean; sri?: boolean; + pl?: boolean; + pn?: string; + ttp?: TrustedTypePolicy; +} + +export abstract class TrustedTypePolicy { + readonly name: string; + createHTML?: ((input: string, ...args: any[]) => string) | undefined; + createScript?: ((input: string, ...args: any[]) => string) | undefined; + createScriptURL?: ((input: string, ...args: any[]) => string) | undefined; } export interface ISnippetConfig { @@ -25,6 +35,18 @@ export interface ISnippetConfig { cr?: boolean; // cdn retry would be proceed if ture dle?: boolean; // Custom optional value to disable sdk load error to be sent sri?: boolean; // Custom optional value to specify whether fetching the snippet from integrity file and do integrity check + /** + * Custom optional value to specify whether to enable the trusted type policy check on snippet + */ + pl?: boolean; + /** + * Custom optional value to specify the name of the trusted type policy that would be implemented on the snippet, default is 'aiPolicy' + */ + pn?: string; + /* + * Custom optional value to specify the trusted type policy that would be applied on the snippet src + */ + ttp?: TrustedTypePolicy; } export interface Fields { diff --git a/tools/applicationinsights-web-snippet/trustedTypeSupport.md b/tools/applicationinsights-web-snippet/trustedTypeSupport.md new file mode 100644 index 000000000..4ab4949bd --- /dev/null +++ b/tools/applicationinsights-web-snippet/trustedTypeSupport.md @@ -0,0 +1,62 @@ +# Trust Type Support + +We offer two methods for implementing Trusted Type policy checks. Choose the one that best suits your needs. + +## Method 1: Using require-trusted-types-for 'script' +If your page utilizes require-trusted-types-for 'script' to enforce script injection policies, configure your snippet as follows: +### Configuration Options +```js + /** + * Custom optional value to specify whether to enable the trusted type policy check on snippet + */ + pl?: boolean; + /** + * Custom optional value to specify the name of the trusted type policy that would be implemented on the snippet, default is 'aiPolicy' + */ + pn?: string; + /* + * Custom optional value to specify the trusted type policy that would be applied on the snippet src + */ + ttp?: TrustedTypePolicy; +``` +### Automatic Policy Creation +To have the policy automatically created, set pl to true. You can optionally specify a policy name with pn. +Example usage: +```html + +``` +### Using a Custom Trusted Type Policy +If you prefer to pass your own Trusted Type Policy, create it and then apply it using the ttp option. + +Example: +```html + +``` +### Test +Your could also check our [test](./Tests/manual/cspUsePolicyTest.html) + +## Method 2: Using Nonce Tag and script-src