Политика безопасности содержимого

Политика безопасности содержимого (CSP) в настоящее время поддерживается в приложениях Power Apps на основе модели и на основе холста. Администраторы могут контролировать, отправляется ли заголовок CSP и, в некоторой степени, что он содержит. Эти параметры находятся на уровне среды, что означает, что они будут применяться ко всем приложениям в среде после включения.

Каждый компонент значения заголовка CSP управляет активами, которые могут быть загружены, и более подробно описан в Mozilla Developer Network (MDN). Значения по умолчанию приведены ниже:

Директива Значение по умолчанию Настраивается
script-src * 'unsafe-inline' 'unsafe-eval' Нет
worker-src 'self' blob: Нет
style-src * 'unsafe-inline' Нет
font-src * data: нет
frame-ancestors 'self' Да

Это приводит к CSP по умолчанию script-src * 'unsafe-inline' 'unsafe-eval'; worker-src 'self' blob:; style-src * 'unsafe-inline'; font-src * data:; frame-ancestors 'self';. В нашей дорожной карте есть возможность изменять ненастраиваемые в настоящее время заголовки.

Предварительные условия

  • Для приложений Dynamics 365 Customer Engagement и других приложений на основе модели CSP доступна только в онлайн-средах и в организациях с Dynamics 365 Customer Engagement (on-premises) версии 9.1 или более поздней.

Настройка CSP

CSP можно включать/выключать и настраивать в центре администрирования Power Platform. Важно сначала включить в среде разработки/тестирования, поскольку включение CSP может привести к блокировке сценариев в случае нарушения политики. Мы также поддерживаем "режим только для отчетов", чтобы упростить ввод в работу.

Чтобы настроить CSP, перейдите в центр администрирования Power Platform ->Среды ->Параметры ->Конфиденциальность + безопасность. В следующем изображении показано состояние параметров по умолчанию.

Параметры политики безопасности содержимого по умолчанию

Отправка сообщения

Переключатель «Включить отчеты» определяет, будут ли приложения на основе модели и холста отправлять отчеты о нарушениях. Для его включения необходимо указать конечную точку. Отчеты о нарушениях отправляются на эту конечную точку независимо от того, применяется CSP или нет (используется режим только для отчетов, если CSP не применяется). Дополнительные сведения см. в документации по отчетности.

Включение конечной точки отчетности

Увеличение

Применение CSP контролируется независимо для приложений на основе моделей и приложений на основе холста, чтобы обеспечить детальный контроль над политиками. Используйте сводку на основе модели/холста, чтобы изменить предполагаемый тип приложения.

Переключатель «Применять политику безопасности контента» включает политику по умолчанию для принудительного применения для данного типа приложения. Включение этого переключателя изменяет поведение приложений в этой среде, чтобы они соответствовали политике. Таким образом, предлагаемый поток включения будет следующим:

  1. Принудительно примените в среде разработки/тестирования.
  2. Включите режим только для отчетов в рабочей среде.
  3. Включите принудительное применение после того, как не будет сообщений о нарушениях.

Настройка директив

Последний раздел — «Настройка директив». Этот раздел позволяет вам управлять отдельными директивами в политике. В настоящее время только frame-ancestors можно настроить.

Настройка директив CSP

Если оставить включенной директиву по умолчанию, используется значение по умолчанию, указанное в таблице, показанной ранее в этой статье. Отключение переключателя позволяет администраторам указывать собственные значения для директивы и добавлять их к значению по умолчанию. В приведенном ниже примере задаются пользовательские значения для frame-ancestors. В этом примере для директивы будет установлено значение frame-ancestors: 'self' https://www.foo.com https://www.bar.com, что означает, что приложение может размещаться в одном и том же источнике, https://www.foo.com и https://www.bar.com, но не в других источниках. Используйте кнопку «Добавить», чтобы добавить записи в список, и значок «Удалить», чтобы удалить их.

Установка пользовательских директив CSP

Распространенные способы конфигурирования

Для Microsoft Teams интеграции с помощью приложения Dynamics 365 добавьте следующее в frame-ancestors:

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

Для Dynamics 365 App for Outlook необходимо добавить источник домашней страницы Outlook Web App в frame-ancestors.

Для встраивания Power Apps в отчеты Power BI, добавьте следующее в frame-ancestors:

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

Важные замечания

Отключение директивы по умолчанию и сохранение с пустым списком полностью отключает директиву и не отправляет ее как часть заголовка ответа CSP.

Примеры

Давайте рассмотрим пару примеров конфигурации CSP:

Пример 1

Пример CSP 1

В приведенном выше примере:

  • Отчетность отключена.
  • Принудительное применение на основе модели включено.
    • frame-ancestors настроен на https://www.foo.com и https://www.bar.com
  • Принудительное использование холста отключено.

Эффективными заголовками будут:

  • Приложения на основе модели: 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;
  • Приложения на основе холста: заголовок CSP не будет отправлен.

Пример 2

Пример CSP 2

В приведенном выше примере:

  • Отчетность включена.
    • Конечная точка отчетности установлена на https://www.mysite.com/myreportingendpoint
  • Принудительное применение на основе модели включено.
    • frame-ancestors сохраняется по умолчанию
  • Принудительное использование холста отключено.
    • frame-ancestors настраивается на https://www.baz.com

Эффективными значениями CSP будут:

  • Приложения на основе модели: 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;
  • Приложения на основе холста: 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;

Параметры организации

CSP можно настроить без использования пользовательского интерфейса, напрямую изменив следующие параметры организации:

  • IsContentSecurityPolicyEnabled определяет, отправляется ли заголовок Content-Security-Policy в приложениях на основе модели.

  • ContentSecurityPolicyConfiguration управляет значением части frame-ancestors (как показано выше, для него установлено значение 'self', если ContentSecurityPolicyConfiguration не установлено). Этот параметр представлен объектом JSON со следующей структурой — { "Frame-Ancestor": { "sources": [ { "source": "foo" }, { "source": "bar" } ] } }. Это преобразуется в script-src * 'unsafe-inline' 'unsafe-eval'; worker-src 'self' blob:; style-src * 'unsafe-inline'; font-src * data:; frame-ancestors 'foo' 'bar';

    • (Из MDN) Директива HTTP Content-Security-Policy (CSP) frame-ancestors указывает действительные родительские элементы, которые могут встраивать страницу, используя <frame>, <iframe>, <object>, <embed> или <applet>.
  • IsContentSecurityPolicyEnabledForCanvas определяет, отправляется ли заголовок Content-Security-Policy в приложениях на основе холста.

  • ContentSecurityPolicyConfigurationForCanvas управляет политикой для холста, используя тот же процесс, который описан в ContentSecurityPolicyConfiguration выше.

  • ContentSecurityPolicyReportUri определяет, следует ли использовать отчетность. Этот параметр используется как приложениями на основе модели, так и приложениями на основе холста. Действительная строка отправляет отчеты о нарушениях на указанную конечную точку, используя режим только отчетов, если IsContentSecurityPolicyEnabled/IsContentSecurityPolicyEnabledForCanvas выключен. Пустая строка отключает отчетность. Дополнительные сведения см. в документации по отчетности.

Настройка CSP без пользовательского интерфейса

Особенно для сред, отсутствующих в центре администрирования Power Platform, таких как локальные конфигурации, администраторы могут захотеть настроить CSP с помощью сценариев для прямого изменения параметров.

Включение CSP без пользовательского интерфейса

Шаги:

  • Откройте средства разработки браузера при использовании приложения на основе модели в качестве пользователя с привилегиями обновления сущности организации (системный администратор — хороший вариант).
  • Вставьте и выполните приведенный ниже скрипт в консоль.
  • Чтобы просто включить CSP, передайте конфигурацию по умолчанию — enableFrameAncestors(["'self'"])
  • В качестве примера включения дополнительных источников для встраивания приложения — 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!')
}

Отключение CSP без пользовательского интерфейса

Шаги:

  • Откройте средства разработки браузера при использовании приложения на основе модели в качестве пользователя с привилегиями обновления сущности организации (системный администратор — хороший вариант).
  • Вставьте и выполните приведенный ниже скрипт в консоль.
  • Чтобы отключить CSP, вставьте в консоль: 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!')
}