บล็อกโพสต์นี้เกี่ยวกับการใช้งานการสนับสนุนเครื่องมือสำหรับนักพัฒนาเว็บเพื่อแก้ไขข้อบกพร่องของนโยบายรักษาความปลอดภัยเนื้อหา (CSP) ด้วยความช่วยเหลือของแท็บปัญหาที่เพิ่งเปิดตัว
เราได้ดำเนินการติดตั้งใช้งานในการฝึกงาน 2 หลักสูตรดังนี้ 1. ในช่วงแรก เราสร้างกรอบการรายงานทั่วไปและออกแบบข้อความปัญหาสำหรับปัญหาการละเมิด CSP 3 ข้อ 2. ในครั้งที่ 2 เราได้เพิ่มปัญหาประเภท Trusted ควบคู่ไปกับฟีเจอร์พิเศษสำหรับเครื่องมือสำหรับนักพัฒนาเว็บบางส่วนสำหรับการแก้ไขข้อบกพร่อง Trusted Types
นโยบายรักษาความปลอดภัยเนื้อหาคืออะไร
นโยบายรักษาความปลอดภัยเนื้อหา (CSP) อนุญาตให้จำกัดพฤติกรรมบางอย่างในเว็บไซต์เพื่อเพิ่มความปลอดภัย เช่น คุณสามารถใช้ CSP เพื่อไม่อนุญาตสคริปต์แบบในหน้าหรือเพื่อไม่อนุญาต eval
ซึ่งทั้ง 2 แบบจะลดพื้นที่การโจมตีสำหรับการโจมตี Cross-Site Scripting (XSS) อ่านข้อมูลเบื้องต้นโดยละเอียดเกี่ยวกับ CSP ได้ที่นี่
CSP ใหม่โดยเฉพาะคือนโยบาย Trusted Types(TT) ซึ่งเปิดใช้การวิเคราะห์แบบไดนามิกซึ่งสามารถป้องกันการโจมตีแบบแทรกข้อมูลจำนวนมากในเว็บไซต์ได้อย่างเป็นระบบ ด้วยเหตุนี้ TT จึงสนับสนุนเว็บไซต์ในการควบคุมโค้ด JavaScript เพื่ออนุญาตให้มีการกำหนดสิ่งบางประเภทให้กับซิงก์ DOM เช่น InnerHTML
เว็บไซต์สามารถเปิดใช้งานนโยบายรักษาความปลอดภัยเนื้อหาโดยรวมส่วนหัว HTTP ที่เฉพาะเจาะจงได้ ตัวอย่างเช่น ส่วนหัว
content-security-policy: require-trusted-types-for 'script'; trusted-types default
เปิดใช้งานนโยบาย TT สำหรับหน้าเว็บ
แต่ละนโยบายจะทำงานได้ในโหมดใดโหมดหนึ่งต่อไปนี้
- โหมดบังคับใช้ - ทุกการละเมิดนโยบายล้วนเกิดจากข้อผิดพลาด
- โหมดรายงานเท่านั้น - ซึ่งรายงานข้อความแสดงข้อผิดพลาดเป็นคําเตือน แต่ไม่ทําให้หน้าเว็บเกิดข้อผิดพลาด
การใช้ปัญหาเกี่ยวกับนโยบายความปลอดภัยของเนื้อหาในแท็บปัญหา
เป้าหมายของการดำเนินงานนี้คือเพื่อปรับปรุงประสบการณ์การแก้ไขข้อบกพร่องสำหรับปัญหา CSP เมื่อพิจารณาปัญหาใหม่ๆ ทีมเครื่องมือสำหรับนักพัฒนาเว็บจะปฏิบัติตามกระบวนการนี้คร่าวๆ
- การอธิบายเรื่องราวของผู้ใช้ ระบุชุดเรื่องราวของผู้ใช้ในฟรอนท์เอนด์ของเครื่องมือสำหรับนักพัฒนาเว็บ ซึ่งครอบคลุมวิธีที่นักพัฒนาเว็บจะต้องตรวจสอบปัญหา
- การใช้งานส่วนหน้า ระบุข้อมูลที่ต้องใช้ในการตรวจสอบปัญหาในส่วนหน้า (เช่น คำขอที่เกี่ยวข้อง ชื่อของคุกกี้ บรรทัดในสคริปต์หรือไฟล์ HTML เป็นต้น) โดยอิงตามเรื่องราวของผู้ใช้
- การตรวจหาปัญหา ระบุตำแหน่งในเบราว์เซอร์ที่สามารถตรวจพบปัญหาใน Chrome และเครื่องมือที่ใช้สถานที่ในการรายงานปัญหา รวมถึงข้อมูลที่เกี่ยวข้องจากขั้นตอนที่ (2)
- บันทึกและแสดงปัญหา เก็บปัญหาไว้ในที่ที่เหมาะสมและเผยแพร่ในเครื่องมือสำหรับนักพัฒนาเว็บเมื่อเปิด
- การออกแบบข้อความปัญหา เขียนข้อความอธิบายที่ช่วยให้นักพัฒนาเว็บเข้าใจและแก้ปัญหาที่สำคัญกว่านั้น
ขั้นตอนที่ 1: การระบุเรื่องราวของผู้ใช้สำหรับปัญหา CSP
ก่อนที่จะเริ่มงานติดตั้งใช้งาน เราได้สร้างเอกสารการออกแบบพร้อมเรื่องราวของผู้ใช้เพื่อให้เข้าใจถึงสิ่งที่เราต้องทำได้ดียิ่งขึ้น ตัวอย่างเช่น เราเขียนเรื่องราวของผู้ใช้ดังต่อไปนี้
ในฐานะนักพัฒนาซอฟต์แวร์ เพิ่งทราบว่าบางส่วนของเว็บไซต์ถูกบล็อก ฉันอยากจะดำเนินการดังนี้ - ...ค้นหาว่า CSP เป็นสาเหตุที่ทำให้ iframe / รูปภาพถูกบล็อกในเว็บไซต์ของฉันหรือไม่ - ...ดูว่าคำสั่ง CSP ใดทำให้เกิดการบล็อกทรัพยากรบางรายการ - ...รู้วิธีเปลี่ยน CSP ของเว็บไซต์ของฉันเพื่ออนุญาตการแสดงทรัพยากร/การดำเนินการที่บล็อกอยู่ในปัจจุบัน /
เพื่อสำรวจเรื่องราวของผู้ใช้นี้ เราได้สร้างหน้าเว็บตัวอย่างง่ายๆ ซึ่งแสดงการละเมิด CSP ที่เราสนใจ และสำรวจหน้าเว็บตัวอย่างเพื่อทำความคุ้นเคยกับขั้นตอนดังกล่าว ตัวอย่างหน้าเว็บบางส่วนมีดังนี้ (เปิดเดโมโดยเปิดแท็บปัญหาไว้)
จากการใช้กระบวนการนี้ เราพบว่าตําแหน่งของแหล่งที่มาเป็นข้อมูลที่สำคัญที่สุดในการแก้ไขข้อบกพร่องของ CSP นอกจากนี้ เรายังพบว่าการค้นหา iframe ที่เกี่ยวข้องและคำขออย่างรวดเร็วในกรณีที่ทรัพยากรถูกบล็อก และการใช้ลิงก์โดยตรงไปยังองค์ประกอบ HTML ในแผงElementsของเครื่องมือสำหรับนักพัฒนาเว็บก็อาจเป็นประโยชน์เช่นกัน
ขั้นตอนที่ 2: การใช้งานฟรอนท์เอนด์
เราได้เปลี่ยนข้อมูลเชิงลึกนี้ให้เป็นข้อมูลฉบับร่างฉบับแรกที่เราต้องการเผยแพร่ในเครื่องมือสำหรับนักพัฒนาเว็บผ่านโปรโตคอลเครื่องมือสำหรับนักพัฒนาเว็บ (CDP) ของ Chrome ดังนี้
ด้านล่างนี้เป็นข้อความที่ตัดตอนมาจาก 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 ที่ฟรอนท์เอนด์ของเครื่องมือสำหรับนักพัฒนาเว็บใช้ ตัวอย่างเช่น คำจำกัดความของ 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 ไปยังฟรอนท์เอนด์ของเครื่องมือสำหรับนักพัฒนาเว็บ เมื่อใช้ไลบรารีดังกล่าว คุณจะสร้างออบเจ็กต์ 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: บันทึกและแสดงปัญหา
ข้อมูลแทรกเล็กๆ ก็คือเราต้องการรายงานปัญหาที่เกิดขึ้นก่อนที่จะมีการเปิดเครื่องมือสำหรับนักพัฒนาเว็บด้วย ซึ่งคล้ายกับวิธีจัดการข้อความในคอนโซล ซึ่งหมายความว่าเราจะไม่รายงานปัญหาไปยังฟรอนท์เอนด์ทันที แต่จะใช้พื้นที่เก็บข้อมูลที่เต็มไปด้วยปัญหาโดยไม่แยกว่าเครื่องมือสำหรับนักพัฒนาเว็บเปิดอยู่หรือไม่ เมื่อเปิดเครื่องมือสำหรับนักพัฒนาเว็บแล้ว (หรือในกรณีที่มีไคลเอ็นต์ 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/
หลังจากทำซ้ำ เราก็ได้มาที่
จะเห็นได้ว่าการรวมทีมฟีเจอร์และ DevRel ทำให้คำอธิบายชัดเจนและแม่นยำขึ้นมาก
นอกจากนี้ คุณยังตรวจสอบปัญหา CSP ในหน้าเว็บได้ในแท็บที่เกี่ยวข้องกับการละเมิด CSP โดยเฉพาะ
การดีบักปัญหาประเภท Trusted
การทำงานกับ TT ในวงกว้างอาจเป็นเรื่องท้าทายหากไม่มีเครื่องมือที่เหมาะสมสำหรับนักพัฒนาซอฟต์แวร์
ปรับปรุงการพิมพ์คอนโซล
เมื่อเราทำงานกับออบเจ็กต์ที่เชื่อถือ เราต้องการแสดงข้อมูลในจำนวนที่เท่ากับออบเจ็กต์ที่ไม่น่าเชื่อถือเป็นอย่างน้อย ขออภัย ขณะนี้ขณะแสดงออบเจ็กต์ที่เชื่อถือ ระบบจะไม่แสดงข้อมูลเกี่ยวกับออบเจ็กต์ที่รวมไว้
เนื่องจากค่าที่แสดงในคอนโซลมาจากการเรียกใช้ .valueOf()
ในออบเจ็กต์โดยค่าเริ่มต้น แต่ในกรณีของประเภทที่เชื่อถือ ค่าที่ส่งคืนจะไม่มีประโยชน์มากนัก แต่เราอยากได้สินค้าที่คล้ายกันกับสิ่งที่คุณได้รับเมื่อโทรหา .toString()
เพื่อให้บรรลุเป้าหมายนี้ เราต้องแก้ไข V8 และ Blink เพื่อเริ่มใช้การจัดการพิเศษสำหรับออบเจ็กต์ประเภทที่เชื่อถือได้
เนื่องด้วยเหตุผลในอดีตที่มีการจัดการแบบกำหนดเองใน V8 แต่วิธีการดังกล่าวก็มีข้อเสียที่สำคัญ มีออบเจ็กต์หลายรายการที่ต้องมีการแสดงผลที่กำหนดเองแต่มีประเภทเหมือนกันที่ระดับ 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
จะตรวจสอบว่าการละเมิดดังกล่าวควรทริกเกอร์เบรกพอยท์หรือไม่ และหากเป็นเช่นนั้น ระบบจะส่งข้อความไปยังส่วนหน้าเพื่อหยุดการดำเนินการชั่วคราว
สิ่งที่ทำเสร็จแล้วและสิ่งที่ควรทำต่อไป
เนื่องจากมีการเปิดตัวปัญหาที่อธิบายในที่นี้ แท็บปัญหาจึงมีการเปลี่ยนแปลงอย่างมาก ดังนี้
- ปรับปรุงการเชื่อมต่อของแผงอื่นๆ ในเครื่องมือสำหรับนักพัฒนาเว็บแล้ว
- เราได้ย้ายรายงานปัญหาอื่นๆ ไปยังแท็บปัญหาแล้ว ซึ่งได้แก่ คอนทราสต์ต่ำ กิจกรรมบนเว็บที่เชื่อถือได้ โหมดที่ไม่มาตรฐาน API การรายงานการระบุแหล่งที่มา และ ปัญหาเกี่ยวกับ CORS และอื่นๆ
- เปิดตัวโอกาสในการซ่อนปัญหา
นับจากนี้ไป เราวางแผนที่จะใช้แท็บปัญหาเพื่อแสดงปัญหาเพิ่มเติม ซึ่งจะช่วยให้ยกเลิกการโหลด Console ของโฟลว์ข้อความแสดงข้อผิดพลาดที่อ่านไม่ได้ในระยะยาวได้
ดาวน์โหลดเวอร์ชันตัวอย่าง
ลองใช้ Chrome Canary, Dev หรือ เบต้า เป็นเบราว์เซอร์เริ่มต้นสำหรับการพัฒนา ช่องทางพรีวิวเหล่านี้จะทำให้คุณเข้าถึงฟีเจอร์ล่าสุดของเครื่องมือสำหรับนักพัฒนาเว็บ ทดสอบ API แพลตฟอร์มเว็บที่ล้ำสมัย และพบปัญหาในเว็บไซต์ก่อนผู้ใช้
ติดต่อทีม Chrome DevTools
ใช้ตัวเลือกต่อไปนี้เพื่อพูดคุยเกี่ยวกับฟีเจอร์ใหม่และการเปลี่ยนแปลงในโพสต์ หรืออื่นๆ ที่เกี่ยวข้องกับเครื่องมือสำหรับนักพัฒนาเว็บ
- ส่งข้อเสนอแนะหรือความคิดเห็นถึงเราทาง crbug.com
- รายงานปัญหาเกี่ยวกับเครื่องมือสำหรับนักพัฒนาเว็บโดยใช้ตัวเลือกเพิ่มเติม
> ความช่วยเหลือ > รายงานปัญหาเกี่ยวกับเครื่องมือสำหรับนักพัฒนาเว็บในเครื่องมือสำหรับนักพัฒนาเว็บ
- ทวีตที่ @ChromeDevTools
- แสดงความคิดเห็นว่ามีอะไรใหม่ในวิดีโอ YouTube เครื่องมือสำหรับนักพัฒนาเว็บ หรือวิดีโอ YouTube สำหรับเครื่องมือสำหรับนักพัฒนาเว็บ