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

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

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

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

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

นโยบายรักษาความปลอดภัยเนื้อหา (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 เมื่อพิจารณาปัญหาใหม่ ทีม DevTools จะดำเนินการตามกระบวนการโดยคร่าวๆ ดังนี้

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

ขั้นตอนที่ 1: กำหนด User Story สำหรับปัญหา CSP

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


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


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

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

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

เรานำข้อมูลเชิงลึกนี้มาร่างเป็นข้อมูลฉบับร่างแรกที่ต้องการให้เครื่องมือสำหรับนักพัฒนาเว็บใช้งานได้ผ่าน Chrome DevTools Protocol (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 (ภาษาข้อมูลโปรโตคอล) PDL มีไว้เพื่อวัตถุประสงค์ 2 อย่าง ก่อนอื่น เราจะใช้ PDL เพื่อสร้างคําจํากัดความ TypeScript ที่ส่วนหน้าของ DevTools ต้องใช้ ตัวอย่างเช่น คําจํากัดความ 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++ จากคําจํากัดความที่จัดการการสร้างและส่งโครงสร้างข้อมูลเหล่านี้จากแบ็กเอนด์ Chromium C++ ไปยังฟีดเอนด์ DevTools เมื่อใช้ไลบรารีดังกล่าว คุณสามารถสร้างออบเจ็กต์ 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 DevTools Protocol (CDP) ใช้งานได้ในรูปแบบที่อธิบายไว้ในส่วนที่แล้ว โชคดีที่โค้ด CSP มีจุดคอขวดที่ใช้สำหรับโหมดรายงานเท่านั้นอยู่แล้ว ซึ่งเราใช้เพื่อเชื่อมต่อกับ ContentSecurityPolicy::ReportViolation ที่รายงานปัญหาไปยังปลายทางการรายงาน (ไม่บังคับ) ซึ่งกำหนดค่าได้ในส่วนหัว HTTP ของ CSP ข้อมูลส่วนใหญ่ที่เราต้องการรายงานมีอยู่แล้ว จึงไม่จำเป็นต้องมีการเปลี่ยนแปลงครั้งใหญ่ในแบ็กเอนด์เพื่อให้เครื่องมือวัดผลทำงานได้

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

ความซับซ้อนเล็กน้อยคือเราต้องการรายงานปัญหาที่เกิดขึ้นก่อนที่จะเปิดเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ด้วย ซึ่งคล้ายกับวิธีจัดการข้อความคอนโซล ซึ่งหมายความว่าเราจะไม่รายงานปัญหาไปยังส่วนหน้าทันที แต่จะใช้พื้นที่เก็บข้อมูลที่มีข้อมูลปัญหาไม่ว่าจะเปิดเครื่องมือสำหรับนักพัฒนาเว็บอยู่หรือไม่ก็ตาม เมื่อเปิด DevTools (หรือแนบไคลเอ็นต์ 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

การแก้ไขข้อบกพร่องของ Trusted Types

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

การพิมพ์คอนโซลที่ปรับปรุงแล้ว

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

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

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

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

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

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

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

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

สิ่งที่ทําเสร็จแล้วและสิ่งที่ต้องทำต่อไป

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

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

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

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

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

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