内容安全策略
备注
全新改进的 Power Platform 管理中心现已进入公开预览阶段! 我们将新的管理中心设计为更易于使用,具有面向任务的导航功能,可帮助你更快地实现特定结果。 随着新的 Power Platform 管理中心进入正式发布阶段,我们将发布新的更新文档。
内容安全策略 (CSP) 目前在模型驱动和画布 Power Apps 中受支持。 管理员可以控制是否发送 CSP 标头,并在一定程度上控制它包含的内容。 这些设置处于环境级别,这意味着启用后,它将应用于环境中的所有应用。
备注
内容安全策略仅适用于使用 Dataverse 的环境。
CSP 标头值的每个组件都控制可以下载的资产,在 Mozilla 开发人员网络 (MDN) 上有更详细的描述。 默认值如下:
指令 | 默认值 | 可自定义 |
---|---|---|
script-src | * 'unsafe-inline' 'unsafe-eval' |
否 |
worker-src | 'self' blob: |
否 |
style-src | * 'unsafe-inline' |
否 |
font-src | * data: |
否 |
frame-ancestors | 'self' https://*.powerapps.com |
是 |
这会导致默认 CSP 为 script-src * 'unsafe-inline' 'unsafe-eval'; worker-src 'self' blob:; style-src * 'unsafe-inline'; font-src * data:; frame-ancestors 'self' https://*.powerapps.com;
。 在我们的路线图中,我们能够修改当前不可定制的标题。
先决条件
- 对于 Dynamics 365 Customer Engagement 应用和其他模型驱动应用,CSP 仅在联机环境和具有 Dynamics 365 Customer Engagement (on-premises) 版本 9.1 或更高版本的组织中可用。
配置 CSP
CSP 可以通过 Power Platform 管理中心切换和配置。 首先在开发/测试环境中启用非常重要,因为启用 CSP 可能会在违反策略的情况下开始阻止场景。 我们还支持“仅限报告模式”,以在生产环境中更轻松地实现改进。
要配置 CSP,导航到 Power Platform 管理中心->环境->设置->隐私 + 安全性。 下图显示了设置的默认状态:
正在报告
“启用报告”切换控制模型驱动和画布应用是否发送违规报告。 启用它需要指定一个终结点。 违规报告将被发送到此终结点,无论是否强制执行 CSP(如果未强制执行 CSP,使用仅限报告模式)。 有关详细信息,请参阅报告文档。
实施
对于模型驱动和画布应用,CSP 的强制执行是独立控制的,以提供对策略的精细控制。 使用模型驱动/画布数据透视修改预期的应用类型。
“实施内容安全策略”开关打开给定应用类型的默认实施策略。 打开此切换将更改此环境中应用的行为以遵守此政策。 因此,建议启用流为:
- 在开发/测试环境中强制执行。
- 在生产环境中启用仅限报告模式。
- 未报告违规即在生产环境中强制执行。
配置指令
此部分允许您控制策略中的各个指令。 当前只能自定义 frame-ancestors
。
保持默认指令打开,使用本文前面表中指定的默认值。 关闭开关允许管理员为指令指定自定义值,并将其附加到默认值。 下面的示例为 frame-ancestors
设置自定义值。 在本例中,该指令将被设置为 frame-ancestors: 'self' https://*.powerapps.com https://www.foo.com https://www.bar.com
,这意味着应用程序可以在相同的源、https://*.powerapps.com
、https://www.foo.com
和 https://www.bar.com
中托管,但不能在其他源中托管。 使用“添加”按钮将条目添加到列表中,使用删除图标将其删除。
常见配置
对于使用 Dynamics 365 应用 的 Microsoft Teams,请将以下内容添加至 frame-ancestors
:
https://teams.microsoft.com/
https://teams.cloud.microsoft/
https://msteamstabintegration.dynamics.com/
对于 Dynamics 365 App for Outlook,将以下内容添加到 frame-ancestors
:
- 您的 Outlook Web 应用程序主页来源
https://outlook.office.com
https://outlook.office365.com
要将 Power Apps 嵌入 Power BI 报告,请添加以下内容至 frame-ancestors
:
https://app.powerbi.com
https://ms-pbi.pbi.microsoft.com
重要考虑因素
关闭默认指令并使用空列表保存将完全关闭指令,不会将其作为 CSP 响应头的一部分发送。
示例
我们来看几个 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
在示例中:
- 报告打开。
- 报告终结点设置为
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' https://*.powerapps.com; 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;
组织设置
通过直接修改以下组织设置,可以在不使用 UI 的情况下配置 CSP:
IsContentSecurityPolicyEnabled 控制是否在模型驱动应用中发送 Content-Security-Policy 标头。
ContentSecurityPolicyConfiguration 控制 frame-ancestors 部分的值(如上图所示,如果未设置
ContentSecurityPolicyConfiguration
,则将其设置为'self'
)。 此设置由具有以下结构的 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>
嵌入页面的有效父级。
- (来自 MDN)HTTP Content-Security-Policy (CSP) frame-ancestors 指令指定可以使用
IsContentSecurityPolicyEnabledForCanvas 控制是否在画布应用中发送 Content-Security-Policy 标头。
ContentSecurityPolicyConfigurationForCanvas 使用上面
ContentSecurityPolicyConfiguration
中所述的相同过程控制画布策略。ContentSecurityPolicyReportUri 控制是否应使用报告。 模型驱动和画布应用均使用此设置。 如果
IsContentSecurityPolicyEnabled
/IsContentSecurityPolicyEnabledForCanvas
关闭,有效字符串将使用仅限报告模式将违规报告发送到指定终结点。 空字符串会禁用报告。 有关详细信息,请参阅报告文档。
不使用 UI 配置 CSP
特别是对于不在 Power Platform 管理中心的环境,如本地配置,管理员可能需要使用脚本配置 CSP 以直接修改设置。
不使用 UI 启用 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!')
}
不使用 UI 禁用 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!')
}