sapui5content-security-policyamdsap-fioriui5-tooling

How to make UI5 content compatible with the FLP setting "Asynchronous Module Loading" and CSP?


The "Browser Settings" section from the "Site Settings" page of the launchpad now allows enabling "Asynchronous Module Loading".

SAP Fiori launchpad Asynchronous Module Loading switch

But once it's enabled, some of the SAPUI5 applications or FLP plugins fail to start. The browser reports in the console:

Failed to execute '<JavaScript module>.js': Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-scr * data: blob:".

How is the CSP topic related to the launchpad's "Asynchronous Module Loading" setting in this case and what can we do to avoid evaluating "string as JavaScript" in UI5?


Solution

  • Cause

    If "Asynchronous Module Loading" is activated, not only does SAP Fiori launchpad (FLP) bootstrap SAPUI5 with data-sap-ui-async="true" but serves also its HTML document with the content-security-policy (CSP) response header that contains a set of CSP directives omitting unsafe-eval and unsafe-inline from script-src. UI5 contents, that initiate calling eval or contain inline scripts, violate the CSP and thus won't be processed by the browser.

    In the legacy UI5 code, eval is called typically due to the application synchronously fetching JS modules via deprecated APIs. For other causes, see the table below.

    Resolution

    It is highly recommended to keep the "Asynchronous Module Loading" setting enabled which improves the overall UI5 performance in FLP (unblocked main thread) and security (stricter CSP).

    UI5 has already deprecated legacy/synchronous APIs and — with the 1.96 release — largely improved the support for strict CSP. UI5 content owners should adjust their code accordingly:

    ❌ UI5 content violating CSP ✅ Making UI5 content more CSP-compliant
    Application's initial HTML document bootstrapping SAPUI5 without data-sap-ui-async="true" or with the debug mode activated. Bootstrap UI5 with data-sap-ui-async="true" and ensure that no debug mode is activated unnecessarily. C.f. "Is Your Application Ready for Asynchronous Loading?"
    Using inline scripts (<script>...</script>) or inline styles (<style>...</style>/style="..."). Comply with the script-src and style-src directives that exclude unsafe-inline by using:
    Using deprecated APIs and libs such as jQuery.sap.*, $el.outerHTML, oCore.createComponent, sap.ui.controller, sap.ui.component, sap.ui.*fragment, sap.ui.*view, sap.ui.extensionpoint, sap.ui.commons, sap.ca.scfld, sap.ca.ui, sap.ui.suite, sap.landvisz, sap.ui.vtm, sap.zen.*, sap.ui.ux3, sap.makit, sap.ui.getCore, sap.ushell.Container.getService, etc..

    Refer to the API reference to learn about newer APIs that replace the deprecated ones.

    When requiring JS modules, only either sap.ui.define or sap.ui.require, and sap.ui.loader.config additionally if needed, should be used.

    Fetching resources still synchronously or indirectly referencing modules via global names despite using non-deprecated APIs. Review the API reference, reports by the Support Assistant, and the console logs. You might have to increase the log level e.g. via the URL parameter sap-ui-logLevel=... to see the relevant logs.
    Creating the component content such as the root view, routed views, and nested views synchronously at runtime despite having them defined declaratively. Add the marker interface "sap.ui.core.IAsyncContentCreation" to the Component.js definition to enable creating the component content asynchronously and other benefits.

    UI5 bundles such as Component-preload.js or library-preload.js containing JS modules that are in string.

    This could be, for example, due to the bundle having been generated via an outdated Grunt build task. Result:

    "my/Module.js":'sap.ui.define([...'

    Even when using UI5 Tooling instead, some JS modules can be still in string especially if those modules have var, let, or const declared in the global scope above the sap.ui.define call in the module definition. Result:

    "my/Module.js":'var myGlobal...'

    UI5 Tooling would then log the following warning in the terminal:

    Module [...] requires top level scope and can only be embedded as a string (requires 'eval')

    Generate the bundle by leveraging UI5 Tooling e.g. with ui5 build -a --clean-dest.

    When defining a UI5 module, avoid globals and use only sap.ui.define at top-level of the JS file.

    Result:
    "my/Module.js":function(){//...

    If the module depends on myGlobal:

    In case the static file locate-reuse-lib.js, generated by SAP Fiori toos, is also included in the bundle: note that locate-reuse-lib.js is relevant only at development time. It is not supposed to be deployed together with the app.

    Other resources that might help identifying CSP issues in UI5

    UI5 Tooling middleware csp

    1. Build the app e.g. with ui5 build --all or ui5 build self-contained -a.
    2. Serve the built app from the dist folder (Refer to SAP/ui5-tooling issue #300).
      E.g. with ui5 serve --config ui5-dist.yaml.
    3. Run the app with the following URL parameter:
      index.html?sap-ui-xx-csp-policy=sap-target-level-<1 to 3>:report-only
      • The higher sap-target-level-<n>, the stricter the CSP.
      • Remove :report-only if the browser should actually apply the CSP level.
    4. Observe any CSP violation reported in the browser console.

    ⚠️ Currently doesn't work in combination with the custom middleware ui5-middleware-index.

    Chrome DevTools

    F12F1 → Select the "Show CSP Violations view" checkbox from the Experiments section.

    Q&As

    Documentation

    For more detailed information about the current state of CSP in UI5 and which restrictions there are, see the documentation topic Content Security Policy.