Inhaltssicherheitsrichtlinie

Inhaltssicherheitsrichtlinie (CSP) wird derzeit in Modellgesteuerten und Canvas-Power Apps unterstützt. Administratoren können steuern, ob der CSP-Header gesendet wird, und in gewissem Umfang, was er enthält. Diese Einstellungen befindeen sich auf Umgebungsebene, d.h. sie wird auf alle Apps in der Umgebung angewendet, sobald sie aktiviert ist.

Jede Komponente des CSP-Header-Werts steuert die Objekte, die heruntergeladen werden können, und wird im Mozilla Developer Network (MDN) ausführlicher beschrieben. Die Standardwerte sind wie folgt:

Richtlinie Standardwert Anpassbar
script-src * 'unsafe-inline' 'unsafe-eval' Nein
worker-src 'self' blob: Nein
style-src * 'unsafe-inline' Nein
font-src * data: Nein
frame-ancestors 'self' Ja

Dies führt zu einem Standard-CSP von script-src * 'unsafe-inline' 'unsafe-eval'; worker-src 'self' blob:; style-src * 'unsafe-inline'; font-src * data:; frame-ancestors 'self';. In unserer Roadmap haben wir die Möglichkeit, derzeit nicht anpassbare Header zu ändern.

Anforderungen

  • Für Dynamics 365 Customer Engagement-Apps und andere modellgesteuerte Apps ist CSP nur in Onlineumgebungen und in Organisationen mit Dynamics 365 Customer Engagement (on-premises), Version 9.1 oder höher verfügbar.

CSP konfigurieren

CSP kann über das Power Platform Admin Center umgeschaltet und konfiguriert werden. Es ist wichtig, zuerst in einer Entwicklungs-/Testumgebung zu aktivieren, da die Aktivierung von CSP Szenarien blockieren könnte, wenn gegen die Richtlinie verstoßen wird. Wir unterstützen außerdem einen „Nur-Bericht-Modus“, um einen einfacheren Produktionsstart zu ermöglichen.

Um CSP zu konfigurieren, navigieren Sie zum Power Platform Admin Center ->Umgebungen ->Einstellungen ->Sicherheit und Datenschutz. Das folgende Bild zeigt den Standardstatus der Einstellungen:

Standardeinstellungen der Inhaltssicherheitsrichtlinie

Berichterstellung

Der Schalter „Berichterstellung aktivieren“ steuert, ob Modellgesteuerte und Canvas-Apps Verstoßberichte senden. Um es zu aktivieren, muss ein Endpunkt angegeben werden. Berichte über Verstöße werden an diesen Endpunkt gesendet, unabhängig davon, ob CSP erzwungen wird oder nicht (unter Verwendung des Nur-Bericht-Modus, wenn CSP nicht erzwungen wird). Weitere Informationen finden Sie in der Dokumentation zur Berichterstellung.

Aktivieren des Berichterstellungsendpunkts

Durchsetzung

Die Durchsetzung von CSP wird für Modellgesteuerte und Canvas-Apps unabhängig gesteuert, um eine granulare Kontrolle über Richtlinien zu ermöglichen. Verwenden Sie die Modellgesteuerte/Canvas-Navigationssteuerung, um den beabsichtigten App-Typ zu ändern.

Der Schalter „Richtlinie für Inhaltssicherheit erzwingen“ aktiviert die Standardrichtlinie für die Durchsetzung für den angegebenen App-Typ. Durch Aktivieren dieses Schalters wird das Verhalten von Apps in dieser Umgebung geändert, um die Richtlinie einzuhalten. Daher wäre der vorgeschlagene Aktivierungsflow:

  1. In einer Entwicklungs-/Testumgebung erzwingen.
  2. Nur-Bericht-Modus in der Produktion aktivieren.
  3. In der Produktion erzwingen, sobald keine Verstöße gemeldet werden.

Konfigurieren von Richtlinien

Der letzte Abschnitt ist „Richtlinien konfigurieren“. In diesem Abschnitt können Sie einzelne Anweisungen innerhalb der Richtlinie steuern. Aktuell kann nur frame-ancestors angepasst werden.

CSP-Richtlinien konfigurieren

Wenn Sie die Standardanweisung aktiviert lassen, wird der Standardwert verwendet, der in der Tabelle weiter oben in diesem Artikel angegeben ist. Durch Deaktivieren des Schalters können Administratoren benutzerdefinierte Werte für die Direktive angeben und diese an den Standardwert anhängen. Im folgenden Beispiel werden benutzerdefinierte Werte für frame-ancestors festgelegt. Die Direktive würde in diesem Beispiel auf frame-ancestors: 'self' https://www.foo.com https://www.bar.com gesetzt sein, was bedeutet, dass die App im selben Ursprung, https://www.foo.com und https://www.bar.com, gehostet werden könnte, jedoch nicht in anderen Ursprüngen. Verwenden Sie die Schaltfläche „Hinzufügen“, um Einträge zur Liste hinzuzufügen, und das Symbol „Löschen“, um sie zu entfernen.

Festlegen benutzerdefinierter CSP-Richtlinien

Häufige Konfigurationen

Für die Microsoft Teams Integration mit der Dynamics 365-App fügen Sie Folgendes zu frame-ancestors hinzu:

  • https://teams.microsoft.com/
  • https://msteamstabintegration.dynamics.com/

Für Dynamics 365 App for Outlook müssen Sie den Ursprung Ihrer Outlook Web App-Startseite zu frame-ancestors hinzufügen.

Um Power Apps in Power BI-Berichte einzubetten, fügen Sie Folgendes zu frame-ancestors hinzu:

  • https://app.powerbi.com
  • https://msi-pbi.pbi.microsoft.com

Wichtige Überlegungen

Deaktivieren der Standarddirektive und Speichern mit einer leeren Liste deaktiviert die Direktive komplett und sendet sie nicht als Teil des CSP-Antwortheaders.

Beispiele

Werfen wir einen Blick auf ein paar Beispiele für die CSP-Konfiguration:

Beispiel 1

CSP-Beispiel 1

Im obigen Beispiel:

  • Die Berichterstellung ist deaktiviert.
  • Die modellgesteuerte Erzwingung ist aktiviert.
    • frame-ancestors ist auf https://www.foo.com und https://www.bar.com angepasst
  • Canvas-Erzwingung ist deaktiviert.

Die effektiven Header wären:

  • Modellgesteuerte Apps: Content-Security-Policy: script-src * 'unsafe-inline' 'unsafe-eval'; worker-src 'self' blob:; style-src * 'unsafe-inline'; font-src * data:; frame-ancestors https://www.foo.com https://www.bar.com;
  • Canvas-Apps: CSP-Header würde nicht gesendet.

Beispiel 2

CSP-Beispiel 2

Im obigen Beispiel:

  • Die Berichterstellung ist aktiviert.
    • Berichterstellungsendpunkt ist auf https://www.mysite.com/myreportingendpoint festgelegt
  • Die Modellgesteuerte Erzwingung ist aktiviert.
    • frame-ancestors wird standardmäßig beibehalten
  • Canvas-Erzwingung ist deaktiviert.
    • frame-ancestors ist auf https://www.baz.com angepasst

Die effektiven CSP-Header wären:

  • Modellgesteuerte Apps: Content-Security-Policy: script-src * 'unsafe-inline' 'unsafe-eval'; worker-src 'self' blob:; style-src * 'unsafe-inline'; font-src * data:; frame-ancestors 'self'; report-uri https://www.mysite.com/myreportingendpoint;
  • Canvas Apps: Content-Security-Policy-Report-Only: script-src * 'unsafe-inline' 'unsafe-eval'; worker-src 'self' blob:; style-src * 'unsafe-inline'; font-src * data:; frame-ancestors https://www.baz.com; report-uri https://www.mysite.com/myreportingendpoint;

Organisationseinstellungen

CSP kann ohne Verwendung der Benutzeroberfläche konfiguriert werden, indem die folgenden Organisationseinstellungen direkt geändert werden:

  • IsContentSecurityPolicyEnabled steuert, ob der Inhaltssicherheitsrichtlinien-Header in Modellgesteuerten Apps gesendet wird.

  • ContentSecurityPolicyConfiguration csteuert den Wert des frame-ancestors-Teils (wie oben zu sehen, wird er auf 'self' gesetzt, wenn ContentSecurityPolicyConfiguration nicht gesetzt ist). Diese Einstellung wird durch ein JSON-Objekt mit der folgenden Struktur dargestellt – { "Frame-Ancestor": { "sources": [ { "source": "foo" }, { "source": "bar" } ] } }. Dies würde übersetzt werden in script-src * 'unsafe-inline' 'unsafe-eval'; worker-src 'self' blob:; style-src * 'unsafe-inline'; font-src * data:; frame-ancestors 'foo' 'bar';

    • (Von MDN) Die frame-ancestors-Direktive von HTTP Content-Security-Policy (CSP) gibt gültige übergeordnete Elemente an, die eine Seite mit <frame>, <iframe>, <object>, <embed> oder <applet> einbetten können.
  • IsContentSecurityPolicyEnabledForCanvas steuert, ob der Inhaltssicherheitsrichtlinien-Header in Canvas-Apps gesendet wird.

  • ContentSecurityPolicyConfigurationForCanvas steuert die Richtlinie für Canvas mithilfe des gleichen Prozesses, der in ContentSecurityPolicyConfiguration oben beschrieben wurde.

  • ContentSecurityPolicyReportUri steuert, ob die Berichterstellung verwendet werden soll. Diese Einstellung wird sowohl von Modellgesteuerten Apps als auch von Canvas-Apps verwendet. Eine gültige Zeichenfolge sendet Verstoßberichte an den angegebenen Endpunkt, wobei der Nur-Bericht-Modus verwendet wird, wenn IsContentSecurityPolicyEnabled/IsContentSecurityPolicyEnabledForCanvas deaktiviert ist. Eine leere Zeichenfolge deaktiviert die Berichterstellung. Weitere Informationen finden Sie in der Dokumentation zur Berichterstellung.

Konfigurieren von CSP ohne Benutzeroberfläche

Besonders für Umgebungen, die nicht im Power Platform Admin Center sind, wie lokale Konfigurationen, möchten Administratoren möglicherweise CSP mithilfe von Skripts konfigurieren, um Einstellungen direkt zu ändern.

Aktivieren von CSP ohne Benutzeroberfläche

Schritte:

  • Öffnen Sie Browser-Entwicklertools, während Sie die Modellgesteuerte App als Benutzer mit Aktualisierungsberechtigungen für Organisationsentitäten verwenden (Systemadministrator ist eine gute Option).
  • Fügen Sie das folgende Skript in die Konsole ein, und führen Sie es aus.
  • Um CSP einfach zu aktivieren, übergeben Sie die Standardkonfiguration – enableFrameAncestors(["'self'"])
  • Als Beispiel für die Aktivierung zusätzlicher Ursprünge zum Einbetten der App – enableFrameAncestors(["*.powerapps.com", "'self'", "abcxyz"])
async function enableFrameAncestors(sources) {
    const baseUrl = Xrm.Utility.getGlobalContext().getClientUrl();

    if (!Array.isArray(sources) || sources.some(s => typeof s !== 'string')) {
        throw new Error('sources must be a string array');
    }

    const orgResponse = await fetch(`${baseUrl}/api/data/v9.1/organizations`);
    if (!orgResponse.ok) throw new Error('Failed to retrieve org info');
    const orgs = await orgResponse.json();
    const { organizationid, contentsecuritypolicyconfiguration, iscontentsecuritypolicyenabled } = orgs.value[0];

    console.log(`Organization Id: ${organizationid}`);
    console.log(`CSP Enabled?: ${iscontentsecuritypolicyenabled}`);
    console.log(`CSP Config: ${contentsecuritypolicyconfiguration}`);

    const orgProperty = prop => `${baseUrl}/api/data/v9.1/organizations(${organizationid})/${prop}`;

    console.log('Updating CSP configuration...')
    const config = {
        'Frame-Ancestor': {
            sources: sources.map(source => ({ source })),
        },
    };
    const cspConfigResponse = await fetch(orgProperty('contentsecuritypolicyconfiguration'), {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            value: JSON.stringify(config),
        }),
    });

    if (!cspConfigResponse.ok) {
        throw new Error('Failed to update csp configuration');
    }
    console.log('Successfully updated CSP configuration!')

    if (iscontentsecuritypolicyenabled) {
        console.log('CSP is already enabled! Skipping update.')
        return;
    }

    console.log('Enabling CSP...')
    const cspEnableResponse = await fetch(orgProperty('iscontentsecuritypolicyenabled'), {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            value: true,
        }),
    });

    if (!cspEnableResponse.ok) {
        throw new Error('Failed to enable csp');
    }
    console.log('Successfully enabled CSP!')
}

Deaktivieren von CSP ohne Benutzeroberfläche

Schritte:

  • Öffnen Sie Browser-Entwicklertools, während Sie die Modellgesteuerte App als Benutzer mit Aktualisierungsberechtigungen für Organisationsentitäten verwenden (Systemadministrator ist eine gute Option).
  • Fügen Sie das folgende Skript in die Konsole ein, und führen Sie es aus.
  • Um CSP zu deaktivieren, fügen Sie in die Konsole ein: disableCSP()
async function disableCSP() {
    const baseUrl = Xrm.Utility.getGlobalContext().getClientUrl();

    const orgResponse = await fetch(`${baseUrl}/api/data/v9.1/organizations`);
    if (!orgResponse.ok) throw new Error('Failed to retrieve org info');
    const orgs = await orgResponse.json();
    const { organizationid, iscontentsecuritypolicyenabled } = orgs.value[0];

    console.log(`Organization Id: ${organizationid}`);
    console.log(`CSP Enabled?: ${iscontentsecuritypolicyenabled}`);

    const orgProperty = prop => `${baseUrl}/api/data/v9.1/organizations(${organizationid})/${prop}`;

    if (!iscontentsecuritypolicyenabled) {
        console.log('CSP is already disabled! Skipping update.')
        return;
    }

    console.log('Disabling CSP...')
    const cspEnableResponse = await fetch(orgProperty('iscontentsecuritypolicyenabled'), {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            value: false,
        }),
    });

    if (!cspEnableResponse.ok) {
        throw new Error('Failed to disable csp');
    }
    console.log('Successfully disabled CSP!')
}