แชร์ผ่าน


นโยบายความปลอดภัยของเนื้อหา

นโยบายความปลอดภัยของเนื้อหา (CSP) รองรับทั้ง Power Apps แบบจำลองและพื้นที่ทำงาน ผู้ดูแลระบบสามารถควบคุมได้ว่าจะส่งส่วนหัว CSP หรือไม่ และส่วนหัวของ 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' 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 และแอปตามโมเดลอื่นๆ CSP จะพร้อมใช้งานในสภาพแวดล้อมออนไลน์เท่านั้นและในองค์กรที่มี Dynamics 365 Customer Engagement (ในสถานที่) เวอร์ชัน 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://*.powerapps.com https://www.foo.com https://www.bar.com ในตัวอย่างนี้ ซึ่งหมายความว่าแอปสามารถโฮสต์ในต้นทางเดียวกัน คือ https://*.powerapps.com, https://www.foo.com และ https://www.bar.com แต่ไม่ใช่ในต้นทางอื่น ใช้ปุ่มเพิ่มเพื่อเพิ่มรายการลงในรายการและไอคอนลบเพื่อลบออก

การตั้งค่าคำสั่ง CSP แบบกําหนดเอง

การตั้งค่าคอนฟิกทั่วไป

สำหรับการรวม 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

ตัวอย่าง 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' 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>
  • 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!')
}