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

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

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

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

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

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

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

เว็บไซต์สามารถเปิดใช้งานนโยบายรักษาความปลอดภัยเนื้อหาโดยรวมส่วนหัว 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 (ภาษาของข้อมูลโปรโตคอล) 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;
}

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

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

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

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

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

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

โดยปกติ ทีมเครื่องมือสำหรับนักพัฒนาเว็บจะเริ่มต้นจากแบบร่างคร่าวๆ ของสิ่งที่จะจินตนาการ


## 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() ในออบเจ็กต์โดยค่าเริ่มต้น อย่างไรก็ตาม ในกรณีของ Trusted Type ค่าที่แสดงผลไม่มีประโยชน์มากนัก แต่เราอยากได้ข้อมูลที่คล้ายกับสิ่งที่คุณจะได้รับเมื่อโทรหา .toString() แทน เราจำเป็นต้องแก้ไข V8 และ Blink เพื่อเปิดตัวการจัดการพิเศษสำหรับออบเจ็กต์ประเภท Trusted

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

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

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

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

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

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

สิ่งที่ต้องทำและขั้นตอนต่อไป

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

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

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

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

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

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

  • ส่งคำแนะนำหรือความคิดเห็นถึงเราผ่าน crbug.com
  • รายงานปัญหาเกี่ยวกับเครื่องมือสำหรับนักพัฒนาเว็บโดยใช้ตัวเลือกเพิ่มเติม   เพิ่มเติม   > ความช่วยเหลือ > รายงานปัญหาเกี่ยวกับเครื่องมือสำหรับนักพัฒนาเว็บในเครื่องมือสำหรับนักพัฒนาเว็บ
  • ทวีตที่ @ChromeDevTools
  • แสดงความคิดเห็นเกี่ยวกับ "มีอะไรใหม่ในวิดีโอ YouTube สำหรับเครื่องมือสำหรับนักพัฒนาเว็บ" หรือเคล็ดลับเครื่องมือสำหรับนักพัฒนาเว็บวิดีโอ YouTube