นโยบายความปลอดภัยของเนื้อหา
นโยบายความปลอดภัยของเนื้อหา (CSP) รองรับทั้ง Power Apps แบบจำลองและพื้นที่ทำงาน ผู้ดูแลระบบสามารถควบคุมได้ว่าจะส่งส่วนหัว CSP หรือไม่ และส่วนหัวของ CSP มีอะไรอยู่บ้าง การตั้งค่าอยู่ที่ระดับสภาพแวดล้อม ซึ่งหมายความว่าจะนำไปใช้กับแอปทั้งหมดในสภาพแวดล้อมเมื่อเปิด
หมายเหตุ
นโยบายความปลอดภัยของเนื้อหาใช้กับสภาพแวดล้อมที่ใช้ Dataverse เท่านั้น
แต่ละองค์ประกอบของค่าส่วนหัว 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' 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
แต่ไม่ใช่ในต้นทางอื่น ใช้ปุ่มเพิ่มเพื่อเพิ่มรายการลงในรายการและไอคอนลบเพื่อลบออก
การตั้งค่าคอนฟิกทั่วไป
สำหรับการรวม Microsoft Teams โดยใช้ แอป Dynamics 365 ให้เพิ่มสิ่งต่อไปนี้ใน frame-ancestors
:
https://teams.microsoft.com/
https://teams.cloud.microsoft/
https://msteamstabintegration.dynamics.com/
สำหรับ Dynamics 365 App for Outlook ให้เพิ่มรายการต่อไปนี้ใน frame-ancestors
:
- ที่มาของหน้าแรกของเว็บแอป Outlook ของคุณ
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;
การตั้งค่าองค์กร
CSP สามารถกำหนดค่าได้โดยไม่ต้องใช้ UI โดยแก้ไขการตั้งค่าองค์กรต่อไปนี้โดยตรง:
IsContentSecurityPolicyEnabled ควบคุมว่าจะส่งส่วนหัว Content-Security-Policy ในแอปแบบจำลองหรือไม่
ContentSecurityPolicyConfiguration ควบคุมค่าของส่วนเดิมของกรอบ (ดังที่แสดงด้านบน ถูกตั้งค่าเป็น
'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>
- (จาก MDN) คำสั่ HTTP Content-Security-Policy (CSP) frame-ancestors ระบุหลักที่ถูกต้องที่อาจฝังเพจโดยใช้
IsContentSecurityPolicyEnabledForCanvas ควบคุมว่าจะส่งส่วนหัว Content-Security-Policy ในแอปพื้นที่ทำงานหรือไม่
ContentSecurityPolicyConfigurationForCanvas ควบคุมนโยบายสำหรับพื้นที่ทำงานใบโดยใช้กระบวนการเดียวกันกับที่อธิบายไว้ใน
ContentSecurityPolicyConfiguration
ข้างบนContentSecurityPolicyReportUri ควบคุมว่าควรใช้การรายงานหรือไม่ การตั้งค่านี้ใช้โดยทั้งแอปแบบจำลองและพื้นที่ทำงาน สตริงที่ถูกต้องส่งรายงานการละเมิดไปยังตำแหน่งข้อมูลที่ระบุ โดยใช้โหมดรายงานเท่านั้นหาก
IsContentSecurityPolicyEnabled
/IsContentSecurityPolicyEnabledForCanvas
ถูกปิด สตริงว่างปิดใช้งานการรายงาน สำหรับข้อมูลเพิ่มเติม ดูที่ คู่มือการรายงาน
การกำหนดค่า CSP โดยไม่มี UI
โดยเฉพาะอย่างยิ่งสำหรับสภาพแวดล้อมที่ไม่ได้อยู่ในศูนย์การจัดการ Power Platform เช่น การกำหนดค่าในสถานที่ ผู้ดูแลระบบอาจต้องการกำหนดค่า CSP โดยใช้สคริปต์เพื่อแก้ไขการตั้งค่าโดยตรง
เปิดใช้งาน CSP โดยไม่มี UI
ขั้นตอน:
- เปิดเครื่องมือนักพัฒนาของเบราว์เซอร์ในขณะที่ใช้แอปแบบจำลองเป็นผู้ใช้ที่มีสิทธิ์อัปเดตเอนทิตีองค์กร (ผู้ดูแลระบบเป็นตัวเลือกที่ดี)
- วางและรันสคริปต์ด้านล่างลงในคอนโซล
- หากต้องการเปิดใช้งาน 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 โดยไม่มี UI
ขั้นตอน:
- เปิดเครื่องมือนักพัฒนาของเบราว์เซอร์ในขณะที่ใช้แอปแบบจำลองเป็นผู้ใช้ที่มีสิทธิ์อัปเดตเอนทิตีองค์กร (ผู้ดูแลระบบเป็นตัวเลือกที่ดี)
- วางและเรียกใช้สคริปต์ต่อไปนี้ลงในคอนโซล
- หากต้องการปิดใช้งาน 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!')
}