การใช้การแก้ไขข้อบกพร่อง CSP และ Trusted Types ใน Chrome DevTools

Kateryna Prokopenko
Kateryna Prokopenko
Alfonso Castaño
Alfonso Castaño

บล็อกโพสต์นี้เกี่ยวกับการใช้การรองรับเครื่องมือสำหรับนักพัฒนาเว็บเพื่อแก้ไขข้อบกพร่องของปัญหาเกี่ยวกับนโยบายรักษาความปลอดภัยเนื้อหา (CSP) ด้วยความช่วยเหลือจากแท็บปัญหาที่เพิ่งเปิดตัว

การติดตั้งใช้งานดำเนินการในระหว่างการฝึกงาน 2 ครั้ง ดังนี้ 1. ในระหว่างการทดสอบครั้งแรก เราได้สร้างเฟรมเวิร์กการรายงานทั่วไปและออกแบบข้อความปัญหาสำหรับการละเมิด CSP 3 รายการ 2. ในระหว่างการทดสอบครั้งที่ 2 เราได้เพิ่มปัญหาเกี่ยวกับ Trusted Types ควบคู่ไปกับฟีเจอร์ DevTools เฉพาะบางอย่างสำหรับการแก้ไขข้อบกพร่องของ Trusted Types

นโยบายรักษาความปลอดภัยเนื้อหาคืออะไร

นโยบายรักษาความปลอดภัยเนื้อหา (CSP) ช่วยจำกัดลักษณะการทำงานบางอย่างในเว็บไซต์เพื่อเพิ่มความปลอดภัย ตัวอย่างเช่น คุณสามารถใช้ CSP เพื่อไม่อนุญาตสคริปต์ในบรรทัดหรือไม่อนุญาต eval ซึ่งทั้ง 2 อย่างนี้จะช่วยลดพื้นที่การโจมตีสำหรับการโจมตีด้วย Cross-Site Scripting (XSS) อ่านข้อมูลเบื้องต้นโดยละเอียดเกี่ยวกับ CSP ได้ที่นี่

CSP ใหม่โดยเฉพาะคือนโยบาย Trusted Types(TT) ซึ่งช่วยให้สามารถวิเคราะห์แบบไดนามิกที่ป้องกันการโจมตีแบบแทรกโค้ดในเว็บไซต์ได้อย่างเป็นระบบ เพื่อให้บรรลุเป้าหมายนี้ TT จะรองรับเว็บไซต์ในการควบคุมโค้ด JavaScript เพื่ออนุญาตให้กำหนดสิ่งบางประเภทให้กับ DOM Sink เช่น innerHTML เท่านั้น

เว็บไซต์สามารถเปิดใช้งานนโยบายรักษาความปลอดภัยเนื้อหาได้โดยใส่ส่วนหัว HTTP ที่เฉพาะเจาะจง เช่น ส่วนหัว content-security-policy: require-trusted-types-for 'script'; trusted-types default จะเปิดใช้งานนโยบาย TT สำหรับหน้าเว็บ

นโยบายแต่ละรายการจะทำงานในโหมดใดโหมดหนึ่งต่อไปนี้

  • โหมดบังคับใช้ - การละเมิดนโยบายทุกครั้งถือเป็นข้อผิดพลาด
  • โหมดรายงานเท่านั้น - ซึ่งจะรายงานข้อความแสดงข้อผิดพลาดเป็นคำเตือน แต่ไม่ทำให้หน้าเว็บทำงานล้มเหลว

การใช้ปัญหาเกี่ยวกับนโยบายรักษาความปลอดภัยเนื้อหาในแท็บปัญหา

เป้าหมายของงานนี้คือการปรับปรุงประสบการณ์การแก้ไขข้อบกพร่องสำหรับปัญหา CSP เมื่อพิจารณาปัญหาใหม่ ทีมเครื่องมือสำหรับนักพัฒนาเว็บจะทำตามกระบวนการต่อไปนี้คร่าวๆ

  1. การกำหนดเรื่องราวของผู้ใช้ ระบุชุดเรื่องราวของผู้ใช้ในฟรอนท์เอนด์ของเครื่องมือสำหรับนักพัฒนาเว็บที่ครอบคลุมวิธีที่นักพัฒนาเว็บจะต้องตรวจสอบปัญหา
  2. การติดตั้งใช้งานฟรอนท์เอนด์ ระบุข้อมูลที่จำเป็นสำหรับการตรวจสอบปัญหาในฟรอนท์เอนด์ (เช่น คำขอที่เกี่ยวข้อง ชื่อคุกกี้ บรรทัดในสคริปต์หรือไฟล์ HTML เป็นต้น) โดยอิงตามเรื่องราวของผู้ใช้
  3. การตรวจหาปัญหา ระบุตำแหน่งในเบราว์เซอร์ที่ตรวจพบปัญหาใน Chrome และกำหนดตำแหน่งเพื่อรายงานปัญหา รวมถึงข้อมูลที่เกี่ยวข้องจากขั้นตอนที่ (2)
  4. บันทึกและแสดงปัญหา จัดเก็บปัญหาไว้ในที่ที่เหมาะสมและทำให้เครื่องมือสำหรับนักพัฒนาเว็บเข้าถึงได้เมื่อเปิดขึ้นมา
  5. การออกแบบข้อความเกี่ยวกับปัญหา คิดข้อความอธิบายที่ช่วยให้นักพัฒนาเว็บเข้าใจ และที่สำคัญกว่านั้นคือแก้ไขปัญหาได้

ขั้นตอนที่ 1: กำหนดเรื่องราวของผู้ใช้สำหรับปัญหา CSP

ก่อนเริ่มงานติดตั้งใช้งาน เราได้สร้างเอกสารการออกแบบที่มีเรื่องราวของผู้ใช้เพื่อทำความเข้าใจสิ่งที่เราต้องทำได้ดียิ่งขึ้น ตัวอย่างเช่น เราเขียนเรื่องราวของผู้ใช้ต่อไปนี้


ในฐานะนักพัฒนาซอฟต์แวร์ที่เพิ่งทราบว่าบางส่วนของเว็บไซต์ถูกบล็อก ฉันต้องการทำสิ่งต่อไปนี้ - ...ดูว่า CSP เป็นสาเหตุที่ทำให้ iframe / รูปภาพในเว็บไซต์ถูกบล็อกหรือไม่ - ...ดูว่าคำสั่ง CSP ใดเป็นสาเหตุที่ทำให้ทรัพยากรบางอย่างถูกบล็อก - ...ดูวิธีเปลี่ยน CSP ของเว็บไซต์เพื่ออนุญาตให้แสดงทรัพยากรที่ถูกบล็อกอยู่ในปัจจุบัน / การดำเนินการ JS ที่ถูกบล็อกอยู่ในปัจจุบัน


ในการสำรวจเรื่องราวของผู้ใช้นี้ เราได้สร้างหน้าเว็บตัวอย่างง่ายๆ ที่แสดงการละเมิด CSP ที่เราสนใจ และสำรวจหน้าตัวอย่างเพื่อทำความคุ้นเคยกับกระบวนการด้วยตนเอง ตัวอย่างหน้าเว็บมีดังนี้ (เปิดการสาธิตโดยเปิดแท็บปัญหาไว้)

เมื่อใช้กระบวนการนี้ เราพบว่าตำแหน่งแหล่งที่มาเป็นข้อมูลที่สำคัญที่สุดสำหรับการแก้ไขข้อบกพร่องของปัญหา CSP นอกจากนี้ เรายังพบว่าการค้นหา iframe และคำขอที่เกี่ยวข้องอย่างรวดเร็วในกรณีที่ทรัพยากรถูกบล็อกนั้นมีประโยชน์ และลิงก์โดยตรงไปยังองค์ประกอบ HTML ในแผงองค์ประกอบของเครื่องมือสำหรับนักพัฒนาเว็บก็มีประโยชน์เช่นกัน

ขั้นตอนที่ 2: การติดตั้งใช้งานส่วนหน้า

เราเปลี่ยนข้อมูลเชิงลึกนี้เป็นฉบับร่างแรกของข้อมูลที่ต้องการให้พร้อมใช้งานในเครื่องมือสำหรับนักพัฒนาเว็บผ่านโปรโตคอลเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome (CDP)

ด้านล่างนี้คือข้อความที่ตัดตอนมาจาก third_party/blink/public/devtools_protocol/browser_protocol.pdl

 type ContentSecurityPolicyIssueDetails extends object
   properties
     # The url not included in allowed sources.
     optional string blockedURL
     # Specific directive that is violated, causing the CSP issue.
     string violatedDirective
     boolean isReportOnly
     ContentSecurityPolicyViolationType contentSecurityPolicyViolationType
     optional AffectedFrame frameAncestor
     optional SourceCodeLocation sourceCodeLocation
     optional DOM.BackendNodeId violatingNodeId

คำจำกัดความข้างต้นจะเข้ารหัสโครงสร้างข้อมูล JSON เป็นหลัก ซึ่งเขียนด้วยภาษาที่เข้าใจง่ายที่เรียกว่า PDL (Protocol Data Language) PDL ใช้เพื่อวัตถุประสงค์ 2 ประการ ก่อนอื่น เราใช้ PDL เพื่อสร้างคำจำกัดความ TypeScript ที่ฟรอนท์เอนด์ของเครื่องมือสำหรับนักพัฒนาเว็บใช้ ตัวอย่างเช่น คำจำกัดความ PDL ข้างต้นจะสร้างอินเทอร์เฟซ TypeScript ต่อไปนี้

export interface ContentSecurityPolicyIssueDetails {
  /**
  * The url not included in allowed sources.
  */
  blockedURL?: string;
  /**
  * Specific directive that is violated, causing the CSP issue.
  */
  violatedDirective: string;
  isReportOnly: boolean;
  contentSecurityPolicyViolationType: ContentSecurityPolicyViolationType;
  frameAncestor?: AffectedFrame;
  sourceCodeLocation?: SourceCodeLocation;
  violatingNodeId?: DOM.BackendNodeId;
}

ประการที่ 2 และอาจสำคัญกว่านั้นคือเราสร้างไลบรารี C++ จากคำจำกัดความที่จัดการการสร้างและส่งโครงสร้างข้อมูลเหล่านี้จากแบ็กเอนด์ C++ Chromium ไปยังฟรอนท์เอนด์ของเครื่องมือสำหรับนักพัฒนาเว็บ เมื่อใช้ไลบรารีดังกล่าว คุณจะสร้างออบเจ็กต์ ContentSecurityPolicyIssueDetails ได้โดยใช้โค้ด C++ ต่อไปนี้

protocol::Audits::ContentSecurityPolicyIssueDetails::create()
  .setViolatedDirective(d->violated_directive)
  .setIsReportOnly(d->is_report_only)
  .setContentSecurityPolicyViolationType(BuildViolationType(
      d->content_security_policy_violation_type)))
  .build();

เมื่อตัดสินใจได้แล้วว่าต้องการให้ข้อมูลใดพร้อมใช้งาน เราก็ต้องสำรวจว่าจะรับข้อมูลนี้จาก Chromium ได้จากที่ใด

ขั้นตอนที่ 3: การตรวจหาปัญหา

เพื่อให้ข้อมูลพร้อมใช้งานสำหรับโปรโตคอลเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome (CDP) ในรูปแบบที่อธิบายไว้ในส่วนที่แล้ว เราจำเป็นต้องค้นหาตำแหน่งที่ข้อมูลพร้อมใช้งานจริงในแบ็กเอนด์ โชคดีที่โค้ด CSP มีจุดคอขวดที่ใช้สำหรับโหมดรายงานเท่านั้นอยู่แล้ว ซึ่งเราสามารถเชื่อมต่อได้ โดย ContentSecurityPolicy::ReportViolation จะรายงานปัญหาไปยังปลายทางการรายงาน (ไม่บังคับ) ที่กำหนดค่าได้ในส่วนหัว HTTP ของ CSP ข้อมูลส่วนใหญ่ที่เราต้องการรายงานมีอยู่แล้ว จึงไม่จำเป็นต้องทำการเปลี่ยนแปลงครั้งใหญ่ในแบ็กเอนด์เพื่อให้เครื่องมือวัดทำงานได้

ขั้นตอนที่ 4: บันทึกและแสดงปัญหา

ความซับซ้อนเล็กน้อยคือเราต้องการรายงานปัญหาที่เกิดขึ้นก่อนเปิดเครื่องมือสำหรับนักพัฒนาเว็บด้วย ซึ่งคล้ายกับวิธีจัดการข้อความในคอนโซล ซึ่งหมายความว่าเราจะไม่รายงานปัญหาไปยังฟรอนท์เอนด์โดยตรง แต่จะใช้พื้นที่เก็บข้อมูลที่มีปัญหาอยู่แล้ว ไม่ว่าเครื่องมือสำหรับนักพัฒนาเว็บจะเปิดอยู่หรือไม่ก็ตาม เมื่อเปิดเครื่องมือสำหรับนักพัฒนาเว็บ (หรือเมื่อแนบไคลเอ็นต์ CDP อื่นๆ) ระบบจะเล่นปัญหาที่บันทึกไว้ก่อนหน้านี้ทั้งหมดซ้ำจากพื้นที่เก็บข้อมูลได้

นี่เป็นขั้นตอนสุดท้ายของการทำงานในส่วนแบ็กเอนด์ และตอนนี้เราต้องมุ่งเน้นไปที่วิธีแสดงปัญหาในส่วนฟรอนท์เอนด์

ขั้นตอนที่ 5: การออกแบบข้อความเกี่ยวกับปัญหา

การออกแบบข้อความปัญหาเป็นกระบวนการที่เกี่ยวข้องกับทีมหลายทีมนอกเหนือจากทีมของเราเอง เช่น เรามักจะอาศัยข้อมูลเชิงลึกจากทีมที่ใช้ฟีเจอร์ (ในกรณีนี้คือทีม CSP) และแน่นอนว่าทีม DevRel ซึ่งออกแบบวิธีที่นักพัฒนาเว็บควรจัดการกับปัญหาบางประเภท โดยปกติแล้ว ข้อความของปัญหาจะได้รับการปรับแต่งจนกว่าจะเสร็จสมบูรณ์

โดยปกติแล้ว ทีม DevTools จะเริ่มต้นด้วยแบบร่างคร่าวๆ ของสิ่งที่จินตนาการไว้ ดังนี้


## Header
Content Security Policy: include all sources of your resources in content security policy header to improve the functioning of your site

## General information
Even though some sources are included in the content security policy header, some resources accessed by your site like images, stylesheets or scripts originate from sources not included in content security policy directives.

Usage of content from not included sources is restricted to strengthen the security of your entire site.

## Specific information

### VIOLATED DIRECTIVES
`img-src 'self'`

### BLOCKED URLs
https://imgur.com/JuXCo1p.jpg

## Specific information
https://web.dev/strict-csp/

หลังจากทำซ้ำ เราก็ได้ผลลัพธ์ดังนี้

ALT_TEXT_HERE

อย่างที่คุณเห็น การให้ทีมฟีเจอร์และ DevRel มีส่วนร่วมทำให้คำอธิบายชัดเจนและแม่นยำมากขึ้น

นอกจากนี้ คุณยังดูปัญหา CSP ในหน้าเว็บได้ในแท็บที่จัดไว้สำหรับการละเมิด CSP โดยเฉพาะ

การแก้ไขข้อบกพร่องของปัญหาเกี่ยวกับประเภทที่เชื่อถือได้

การทำงานกับ TT ในวงกว้างอาจเป็นเรื่องท้าทายหากไม่มีเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ที่เหมาะสม

ปรับปรุงการพิมพ์คอนโซล

เมื่อทำงานกับออบเจ็กต์ที่เชื่อถือได้ เราต้องการแสดงข้อมูลอย่างน้อยในปริมาณที่เท่ากันกับออบเจ็กต์ที่ไม่เชื่อถือ ขออภัย ขณะนี้เมื่อแสดงออบเจ็กต์ที่เชื่อถือได้ ระบบจะไม่แสดงข้อมูลเกี่ยวกับออบเจ็กต์ที่รวมอยู่

เนื่องจากค่าที่แสดงในคอนโซลได้มาจากการเรียก .valueOf() ในออบเจ็กต์โดยค่าเริ่มต้น อย่างไรก็ตาม ในกรณีของ Trusted Type ค่าที่แสดงผลไม่มีประโยชน์มากนัก แต่เราต้องการให้มีลักษณะคล้ายกับสิ่งที่คุณได้รับเมื่อโทรหา .toString() เพื่อให้บรรลุเป้าหมายนี้ เราจำเป็นต้องแก้ไข V8 และ Blink เพื่อแนะนำการจัดการพิเศษสำหรับออบเจ็กต์ประเภทที่เชื่อถือได้

แม้ว่าการจัดการที่กำหนดเองนี้จะทำใน V8 เนื่องจากเหตุผลทางประวัติศาสตร์ แต่วิธีการดังกล่าวก็มีข้อเสียที่สำคัญ มีออบเจ็กต์จำนวนมากที่ต้องมีการแสดงผลที่กำหนดเอง แต่มีประเภทเดียวกันในระดับ JS เนื่องจาก V8 เป็น JS ล้วน จึงไม่สามารถแยกแยะแนวคิดที่สอดคล้องกับ Web API เช่น Trusted Type ได้ ด้วยเหตุนี้ V8 จึงต้องขอความช่วยเหลือจาก Embedder (Blink) เพื่อแยกความแตกต่าง

ดังนั้น การย้ายโค้ดส่วนนั้นไปยัง Blink หรือเครื่องมือฝังใดๆ จึงดูเป็นตัวเลือกที่สมเหตุสมผล นอกจากปัญหาที่เปิดเผยแล้ว ยังมีประโยชน์อื่นๆ อีกมากมาย ดังนี้

  • Embedder แต่ละรายการสามารถสร้างคำอธิบายของตัวเองได้
  • การสร้างคำอธิบายผ่าน Blink API นั้นง่ายกว่ามาก
  • Blink มีสิทธิ์เข้าถึงคำจำกัดความเดิมของออบเจ็กต์ ดังนั้น หากเราใช้ .toString() เพื่อสร้างคำอธิบาย ก็จะไม่มีความเสี่ยงที่ .toString() อาจได้รับการกำหนดใหม่

การหยุดชะงักเมื่อมีการละเมิด (ในโหมดรายงานเท่านั้น)

ปัจจุบันวิธีเดียวในการแก้ไขข้อบกพร่องของการละเมิด TT คือการตั้งค่าเบรกพอยต์ในข้อยกเว้น JS เนื่องจากการละเมิด TT ที่บังคับใช้จะทริกเกอร์ข้อยกเว้น ฟีเจอร์นี้จึงอาจมีประโยชน์ในบางกรณี อย่างไรก็ตาม ในสถานการณ์จริง คุณต้องควบคุมการละเมิด TT ได้ละเอียดยิ่งขึ้น โดยเฉพาะอย่างยิ่ง เราต้องการหยุดเฉพาะการละเมิด TT (ไม่ใช่ข้อยกเว้นอื่นๆ) หยุดในโหมดรายงานเท่านั้น และแยกแยะการละเมิด TT ประเภทต่างๆ

เครื่องมือสำหรับนักพัฒนาเว็บรองรับเบรกพอยต์ที่หลากหลายอยู่แล้ว สถาปัตยกรรมจึงขยายได้ค่อนข้างมาก การเพิ่มเบรกพอยต์ประเภทใหม่ต้องมีการเปลี่ยนแปลงในแบ็กเอนด์ (Blink), CDP และฟรอนท์เอนด์ เราควรเปิดตัวคำสั่ง CDP ใหม่ โดยตั้งชื่อว่า setBreakOnTTViolation ฟรอนท์เอนด์จะใช้คำสั่งนี้เพื่อบอกแบ็กเอนด์ว่าควรหยุดการละเมิด TT ประเภทใด แบ็กเอนด์ โดยเฉพาะ InspectorDOMDebuggerAgent จะมี "โพรบ" onTTViolation() ซึ่งจะถูกเรียกใช้ทุกครั้งที่มีการละเมิด TT จากนั้น InspectorDOMDebuggerAgent จะตรวจสอบว่าการละเมิดนั้นควรทริกเกอร์เบรกพอยต์หรือไม่ และหากเป็นเช่นนั้น ระบบจะส่งข้อความไปยังฟรอนท์เอนด์เพื่อหยุดการดำเนินการชั่วคราว

สิ่งที่ทำไปแล้วและสิ่งที่จะทำต่อไป

ตั้งแต่มีการเปิดตัวปัญหาที่อธิบายไว้ที่นี่ แท็บปัญหามีการเปลี่ยนแปลงไปค่อนข้างมาก ดังนี้

ในอนาคต เราวางแผนที่จะใช้แท็บปัญหาเพื่อแสดงปัญหาเพิ่มเติม ซึ่งจะช่วยให้สามารถนำข้อความแสดงข้อผิดพลาดที่อ่านไม่ได้ออกจากคอนโซลได้ในระยะยาว

ดาวน์โหลดช่องทางตัวอย่าง

ลองใช้ Chrome Canary, Dev หรือ Beta เป็นเบราว์เซอร์สำหรับการพัฒนาเริ่มต้น ช่องทางเวอร์ชันตัวอย่างเหล่านี้ช่วยให้คุณเข้าถึงฟีเจอร์ล่าสุดของเครื่องมือสำหรับนักพัฒนาเว็บ, ทดสอบ API ของแพลตฟอร์มเว็บที่ล้ำสมัย และช่วยคุณค้นหาปัญหาในเว็บไซต์ก่อนที่ผู้ใช้จะพบ

ติดต่อทีมเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome

ใช้ตัวเลือกต่อไปนี้เพื่อพูดคุยเกี่ยวกับฟีเจอร์ใหม่ การอัปเดต หรือสิ่งอื่นๆ ที่เกี่ยวข้องกับเครื่องมือสำหรับนักพัฒนาเว็บ