הפוסט הזה בבלוג עוסק בהטמעה של תמיכה בכלי הפיתוח לניפוי באגים בבעיות שקשורות ל-Content Security Policy (CSP) בעזרת הכרטיסייה בעיות שהושקה לאחרונה.
עבודת ההטמעה בוצעה במהלך שתי התמחויות: 1. בשלב הראשון, בנינו את מסגרת הדיווח הכללית ועיצבנו את הודעות הבעיה ל-3 בעיות של הפרת CSP. 2. בשלב השני, הוספנו בעיות שקשורות ל-Trusted Types לצד כמה תכונות מיוחדות של כלי הפיתוח לניפוי באגים ב-Trusted Types.
מהי Content Security Policy?
Content Security Policy (CSP) מאפשר להגביל התנהגויות מסוימות באתר כדי להגביר את האבטחה. לדוגמה, אפשר להשתמש ב-CSP כדי לא לאפשר סקריפטים מוטבעים או כדי לא לאפשר eval, שניהם מצמצמים את שטח המתקפה של פרצת אבטחה XSS (cross-site scripting). כאן אפשר לקרוא מבוא מפורט ל-CSP.
מדיניות CSP חדשה במיוחד היא Trusted Types(TT), שמאפשרת ניתוח דינמי שיכול למנוע באופן שיטתי סוגים רבים של מתקפות החדרת קוד באתרים. כדי לעשות את זה, TT תומך באתר בפיקוח על קוד ה-JavaScript שלו, כך שרק סוגים מסוימים של דברים יוקצו ל-DOM sinks כמו innerHTML.
אתר יכול להפעיל מדיניות אבטחת תוכן על ידי הכללת כותרת HTTP מסוימת. לדוגמה, הכותרת
content-security-policy: require-trusted-types-for 'script'; trusted-types default
מפעילה את מדיניות ה-TT בדף.
כל מדיניות יכולה לפעול באחד מהמצבים הבאים:
- מצב אכיפה – שבו כל הפרת מדיניות היא שגיאה,
- מצב דיווח בלבד – מצב שבו הודעת השגיאה מדווחת כאזהרה, אבל לא גורמת לכשל בדף האינטרנט.
הטמעת בעיות שקשורות למדיניות אבטחת תוכן בכרטיסייה Issues
המטרה של העבודה הזו הייתה לשפר את חוויית ניפוי הבאגים בבעיות שקשורות ל-CSP. כשצוות כלי הפיתוח בוחן בעיות חדשות, הוא פועל פחות או יותר לפי התהליך הבא:
- הגדרת סיפורי משתמשים. מזהים קבוצה של סיפורי משתמשים בממשק הקצה של כלי הפיתוח, שמתארת איך מפתח אתרים צריך לחקור את הבעיה.
- הטמעה בצד הלקוח. על סמך סיפורי המשתמשים, זהו את המידע שנדרש כדי לחקור את הבעיה בממשק הקצה (למשל: בקשה קשורה, שם של קובץ Cookie, שורה בסקריפט או בקובץ HTML וכו').
- זיהוי בעיות. מזהים את המקומות בדפדפן שבהם אפשר לזהות את הבעיה ב-Chrome, ומגדירים את המקום לדיווח על בעיה, כולל המידע הרלוונטי משלב (2).
- שומרים ומציגים את הבעיות. אחסון הבעיות במקום מתאים והצגה שלהן בכלי הפיתוח כשהם נפתחים
- עיצוב הטקסט של הבעיות. הסבר שיעזור למפתח האתר להבין את הבעיה, וחשוב מכך – לתקן אותה
שלב 1: הגדרת סיפורי משתמשים לבעיות ב-CSP
לפני שהתחלנו בעבודת ההטמעה, יצרנו מסמך עיצוב עם סיפורי משתמשים כדי להבין טוב יותר מה אנחנו צריכים לעשות. לדוגמה, כתבנו את סיפור המשתמש הבא:
As a developer, who just realized that some part of my website are blocked, I want to:- - ...find out if CSP is a reason for blocked iframes / images on my website - ...learn which CSP directive causes the blockage of a certain resource - ...know how to change the CSP of my website to allow display of currently blocked resources / execution of currently blocked js.
כדי לבחון את סיפור המשתמש הזה, יצרנו כמה דפי אינטרנט פשוטים לדוגמה שהציגו את הפרות ה-CSP שעניינו אותנו, ובחנו את הדפים לדוגמה כדי להכיר את התהליך בעצמנו. הנה כמה דוגמאות לדפי אינטרנט (צריך לפתוח את ההדגמה כשהכרטיסייה Issues פתוחה):
בעזרת התהליך הזה, למדנו שמיקום המקור הוא המידע הכי חשוב לניפוי באגים בבעיות שקשורות ל-CSP. בנוסף, גילינו שזה עוזר למצוא במהירות את ה-iframe והבקשה המשויכים במקרה שמשאב נחסם, וגם שקישור ישיר לרכיב ה-HTML בחלונית Elements של כלי הפיתוח יכול להיות שימושי.
שלב 2: הטמעה בצד הלקוח (front-end)
הפכנו את התובנה הזו לטיוטה הראשונה של המידע שרצינו להפוך לזמין לכלי הפיתוח באמצעות פרוטוקול כלי הפיתוח ל-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 יש שתי מטרות. קודם כל, אנחנו משתמשים ב-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++ מההגדרה שמטפלת ביצירה ובשליחה של מבני הנתונים האלה מה-back-end של C++ Chromium אל ה-front-end של כלי הפיתוח. באמצעות הספרייה הזו, אפשר ליצור אובייקט 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: שומרים ומציגים את הבעיות
סיבוך קטן הוא העובדה שרצינו גם לדווח על בעיות שהתרחשו לפני פתיחת כלי הפיתוח, בדומה לאופן שבו מטופלות הודעות במסוף. כלומר, אנחנו לא מדווחים על בעיות ישירות לממשק הקצה, אלא משתמשים באחסון שמאוכלס בבעיות בלי קשר לשאלה אם כלי הפיתוח פתוחים או לא. אחרי שפותחים את DevTools (או כל לקוח 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 Types
עבודה עם TT בקנה מידה גדול יכולה להיות מאתגרת בלי הכלים המתאימים למפתחים.
הדפסה משופרת של המסוף
כשאנחנו עובדים עם אובייקטים מהימנים, אנחנו רוצים להציג לפחות את אותה כמות מידע כמו באובייקטים המקבילים הלא מהימנים. לצערנו, כרגע כשמוצג אובייקט מהימן, לא מוצג מידע על האובייקט שעטוף.
הסיבה לכך היא שהערך שמוצג במסוף נלקח מקריאה ל-.valueOf() באובייקט כברירת מחדל. עם זאת, במקרה של Trusted Type, הערך שמוחזר לא שימושי במיוחד. במקום זאת, אנחנו רוצים משהו דומה למה שמקבלים כשמתקשרים אל .toString(). כדי לעשות את זה, אנחנו צריכים לשנות את V8 ו-Blink כדי להוסיף טיפול מיוחד לאובייקטים של סוגים מהימנים.
מסיבות היסטוריות, הטיפול המותאם אישית הזה בוצע ב-V8, אבל לגישה הזו יש חסרונות משמעותיים. יש הרבה אובייקטים שצריך להציג בהתאמה אישית, אבל הסוג שלהם זהה ברמת ה-JS. מכיוון ש-V8 הוא JS טהור, הוא לא יכול להבחין במושגים שתואמים ל-Web API כמו Trusted Type. לכן, V8 צריך לבקש עזרה מהמטמיע שלו (Blink) כדי להבחין ביניהם.
לכן, העברת החלק הזה של הקוד ל-Blink או לכל כלי הטמעה אחר נשמעת כמו בחירה הגיונית. חוץ מהבעיה שחשפנו, יש עוד הרבה יתרונות:
- לכל הטמעה יכול להיות תיאור משלה
- הרבה יותר קל ליצור את התיאור באמצעות Blink API
- ל-Blink יש גישה להגדרה המקורית של האובייקט. לכן, אם נשתמש ב-
.toString()כדי ליצור את התיאור, אין סיכון ש-.toString()יוגדר מחדש.
הפסקה במקרה של הפרה (במצב דיווח בלבד)
נכון לעכשיו, הדרך היחידה לנפות באגים בהפרות של TT היא להגדיר נקודות עצירה (breakpoint) בחריגות של JS. התכונה הזו יכולה להיות שימושית כי הפרות של אכיפת TT יגרמו לחריגה. עם זאת, בתרחישים בעולם האמיתי, אתם צריכים שליטה מפורטת יותר על הפרות של TT. באופן ספציפי, אנחנו רוצים לעצור רק בהפרות של TT (ולא בחריגות אחרות), לעצור גם במצב של דיווח בלבד ולהבחין בין הסוגים השונים של הפרות TT.
כלי הפיתוח כבר תומכים במגוון רחב של נקודות עצירה, כך שהארכיטקטורה ניתנת להרחבה. כדי להוסיף סוג חדש של נקודת עצירה, צריך לבצע שינויים בקצה העורפי (Blink), ב-CDP ובקצה הקדמי.
אנחנו צריכים להוסיף פקודת CDP חדשה, נקרא לה setBreakOnTTViolation. הפקודה הזו תשמש את ממשק המשתמש כדי להורות לבק-אנד על אילו סוגים של הפרות TT הוא צריך להפסיק. הקצה העורפי, ובמיוחד InspectorDOMDebuggerAgent, יספק "בדיקה", onTTViolation(), שתופעל בכל פעם שתתרחש הפרה של TT. לאחר מכן, InspectorDOMDebuggerAgent יבדוק אם ההפרה הזו אמורה להפעיל נקודת עצירה, ואם כן, הוא ישלח הודעה לקצה הקדמי כדי להשהות את ההפעלה.
מה כבר נעשה ומה השלב הבא?
מאז שהבעיות שמתוארות כאן הופיעו, הכרטיסייה Issues (בעיות) עברה כמה שינויים:
- הקישוריות שלו לחלוניות אחרות בכלי הפיתוח שופרה.
- הדיווח על מספר בעיות נוספות עבר לכרטיסייה Issues (בעיות): low-contrast (ניגודיות נמוכה), trusted web-activity (פעילות Trusted Web), quirks mode (מצב תאימות), attribution reporting API (API לדיווח על שיוך) ובעיות שקשורות ל-CORS, בין היתר.
- הוספנו אפשרות להסתיר בעיות
בהמשך, אנחנו מתכננים להשתמש בכרטיסייה בעיות כדי להציג בעיות נוספות, וכך נוכל להסיר מהמסוף את זרם הודעות השגיאה הבלתי קריאות בטווח הארוך.
הורדת הערוצים בגרסת טרום-השקה (Preview)
כדאי להשתמש ב-Chrome Canary, ב-Dev או ב-Beta כדפדפן ברירת המחדל לפיתוח. ערוצי התצוגה המקדימה האלה נותנים לכם גישה לתכונות העדכניות ביותר של כלי הפיתוח, מאפשרים לכם לבדוק ממשקי API מתקדמים של פלטפורמות אינטרנט ועוזרים לכם למצוא בעיות באתר לפני שהמשתמשים שלכם ייתקלו בהן.
יצירת קשר עם הצוות של כלי הפיתוח ל-Chrome
אתם יכולים להשתמש באפשרויות הבאות כדי לדון בתכונות החדשות, בעדכונים או בכל נושא אחר שקשור לכלי הפיתוח.
- אפשר לשלוח משוב ובקשות להוספת תכונות בכתובת crbug.com.
- כדי לדווח על בעיה בכלי הפיתוח, לוחצים על אפשרויות נוספות > עזרה > דיווח על בעיה בכלי הפיתוח.
- לצייץ ב-@ChromeDevTools.
- להגיב על סרטונים ב-YouTube בנושא "מה חדש בכלי הפיתוח" או על סרטונים ב-YouTube בנושא "טיפים לשימוש בכלי הפיתוח".