הפוסט הזה עוסק בהטמעת תמיכה של DevTools לניפוי באגים בבעיות שקשורות למדיניות אבטחת תוכן (CSP) בעזרת הכרטיסייה בעיות שהושקה לאחרונה.
עבודת ההטמעה בוצעה במהלך 2 תקופות התמחות: 1. במהלך הפגישה הראשונה, פיתחנו את מסגרת הדיווח הכללית ותכננו את הודעות הבעיה לגבי 3 הפרות של ספקי שירותי צד שלישי. 2. במהלך הפגישה השנייה הוספנו בעיות שקשורות ל-Trusted Types, לצד כמה תכונות מיוחדות של DevTools לניפוי באגים של Trusted Types.
מהי מדיניות אבטחת תוכן?
מדיניות אבטחת תוכן (CSP) מאפשרת להגביל התנהגויות מסוימות באתר כדי לשפר את האבטחה. לדוגמה, אפשר להשתמש ב-CSP כדי לאסור סקריפטים בקוד או לאסור את השימוש ב-eval
. שתי הפעולות האלה מפחיתות את שטח ההתקפה של תקיפות Cross-Site Scripting (XSS). כאן אפשר לקרוא מבוא מפורט ל-CSP.
מדיניות CSP חדשה במיוחד היא המדיניות של סוגים מהימנים(TT), שמאפשרת ניתוח דינמי שיכול למנוע באופן שיטתי סוג גדול של התקפות הזרקה באתרים. כדי להשיג זאת, TT תומכת באתר בביצוע אכיפה של קוד ה-JavaScript שלו, כדי לאפשר רק הקצאה של סוגים מסוימים של פריטים למנקזי DOM, כמו innerHTML.
אתר יכול להפעיל מדיניות אבטחת תוכן על ידי הוספת כותרת HTTP ספציפית. לדוגמה, הכותרת content-security-policy: require-trusted-types-for 'script'; trusted-types default
מפעילה את מדיניות TT בדף.
כל מדיניות יכולה לפעול באחת מהשיטות הבאות:
- מצב אכיפה – שבו כל הפרת מדיניות היא שגיאה,
- מצב דיווח בלבד – דיווח על הודעת השגיאה כאזהרה, אבל ללא כשל בדף האינטרנט.
הטמעת בעיות שקשורות ל-Content Security Policy בכרטיסייה בעיות
המטרה של העבודה הזו הייתה לשפר את חוויית ניפוי הבאגים בבעיות שקשורות ל-CSP. כשהצוות של DevTools בוחן בעיות חדשות, הוא פועל בערך לפי התהליך הבא:
- הגדרת סיפורי משתמשים. מזהים קבוצה של סיפורי משתמשים בממשק הקצה של DevTools שמתארים איך מפתח אינטרנט יצטרך לחקור את הבעיה.
- הטמעה בחזית. על סמך סיפורי המשתמשים, מזהים אילו פריטים של מידע נדרשים כדי לחקור את הבעיה בחזית (למשל, בקשה קשורה, שם של קובץ cookie, שורה בסקריפט או בקובץ HTML וכו').
- זיהוי בעיות. מזהים את המקומות בדפדפן שבהם ניתן לזהות את הבעיה ב-Chrome ומגדירים את המקום לדיווח על בעיה, כולל המידע הרלוונטי משלב 2.
- שומרים את הבעיות ומציגים אותן. שומרים את הבעיות במקום מתאים ומאפשרים להן להיות זמינות ל-DevTools אחרי שהוא נפתח
- עיצוב הטקסט של הבעיות. צריך לנסח הסברים שיעזרו למפתח האתר להבין את הבעיה, וחשוב יותר לתקן אותה
שלב 1: הגדרת סיפורי משתמשים לבעיות ב-CSP
לפני שהתחלנו בתהליך ההטמעה, יצרנו מסמך עיצוב עם סיפורי משתמשים כדי להבין טוב יותר מה עלינו לעשות. לדוגמה, כתבנו את סיפור המשתמש הבא:
בתור מפתח / ת שברגע הבין שחלק מסוים מהאתר שלי חסום, אני רוצה:- - ...לבדוק אם CSP הוא הסיבה לחסימת iframes / תמונות באתר שלי - ...ללמוד איזו הוראת CSP גורמת לחסימה של משאב מסוים - ...כדאי לדעת איך לשנות את ה-CSP של האתר כדי לאפשר הצגה של משאבים חסומים או הפעלה של js שנחסם כרגע.
כדי לבדוק את סיפור המשתמש הזה, יצרנו כמה דפי אינטרנט לדוגמה שהכילו את הפרות ה-CSP שבהן התעניינו, ובדקנו את הדפים האלה כדי להכיר את התהליך בעצמנו. ריכזנו כאן כמה דוגמאות לדפי אינטרנט (פותחים את הדמו כשהכרטיסייה בעיות פתוחה):
בעזרת התהליך הזה, למדנו שמיקום המקור הוא פריט המידע החשוב ביותר לניפוי באגים בבעיות של CSP. גילינו גם שאפשר למצוא במהירות את ה-iframe והבקשה המשויכים במקרה שמשאב חסום, וגם שקישור ישיר לרכיב ה-HTML בחלונית Elements ב-DevTools יכול להיות שימושי.
שלב 2: הטמעה בחזית
הפכנו את התובנה הזו לטיוטה הראשונה של המידע שרצינו להפוך לזמין ב-DevTools דרך פרוטוקול Chrome DevTools (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 שחזית 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++ מההגדרה שמטפלת ביצירה ובשליחת מבני הנתונים האלה מקצה העורפי של 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 (CDP) יהיה זמין בפורמט שמתואר בקטע האחרון, היינו צריכים למצוא את המקום שבו המידע היה זמין בפועל בקצה העורפי. למרבה המזל, בקוד ה-CSP כבר היה צוואר בקבוק שמשמש למצב 'דיווח בלבד', שבו הצלחנו להתחבר: ContentSecurityPolicy::ReportViolation
מדווח על בעיות לנקודת קצה (אופציונלית) לדיווח שאפשר להגדיר בכותרת ה-HTTP של CSP. רוב המידע שרצינו לדווח עליו כבר היה זמין, כך שלא נדרשו שינויים גדולים בקצה העורפי כדי שהמכשירים שלנו יפעלו.
שלב 4: שומרים את הבעיות ומציגים אותן
הבעיה היחידה היא שרצינו גם לדווח על בעיות שהתרחשו לפני פתיחת DevTools, בדומה לאופן שבו מטפלים בהודעות במסוף. כלומר, אנחנו לא מדווחים על בעיות ישירות לקצה הקדמי, אלא משתמשים במאגר שמאוכלס בבעיות ללא קשר לכך ש-DevTools פתוח או לא. אחרי שפותחים את 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.
ניפוי באגים בבעיות שקשורות לסוגים מהימנים
עבודה עם TT בהיקף גדול יכולה להיות מאתגרת בלי הכלים המתאימים למפתחים.
הדפסה משופרת של המסוף
כשאנחנו עובדים עם אובייקטים מהימנים, אנחנו רוצים להציג לפחות את אותה כמות מידע כמו לגבי המקבילה הלא מהימנה. לצערנו, כרגע כשמציגים אובייקט מהימן, לא מוצג מידע על האובייקט הארוז.
הסיבה לכך היא שהערך שמוצג במסוף נלקח מקריאת .valueOf()
באובייקט כברירת מחדל. עם זאת, במקרה של 'סוג מהימן', הערך המוחזר לא מועיל במיוחד. במקום זאת, אנחנו רוצים להציג משהו דומה למה שמופיע כשקוראים לפונקציה .toString()
. כדי לעשות זאת, אנחנו צריכים לשנות את V8 ואת Blink כדי להוסיף טיפול מיוחד באובייקטים מסוג מהימן.
למרות שעקב סיבות היסטוריות טיפול מותאם אישית זה בוצע ב-V8, לגישה כזו יש חסרונות חשובים. יש הרבה אובייקטים שדורשים תצוגה מותאמת אישית, אבל הסוג שלהם זהה ברמת ה-JS. V8 הוא JS טהור, לכן הוא לא יכול ליצור הבחנה בין מושגים שתואמים לממשק API לאינטרנט, כמו סוג מהימן. לכן, V8 צריך לבקש עזרה מהכלי להטמעה (Blink) כדי להבדיל ביניהם.
לכן, העברת החלק הזה של הקוד ל-Blink או לכל כלי להטמעת קוד נשמעת כבחירה הגיונית. מלבד הבעיה שנחשפה, יש עוד הרבה יתרונות נוספים:
- לכל מי שמטמיע את הקוד יכול להיות תיאור משלו
- קל יותר ליצור את התיאור באמצעות Blink API
- ל-Blink יש גישה להגדרה המקורית של האובייקט. לכן, אם נשתמש ב-
.toString()
כדי ליצור את התיאור, לא קיים סיכון ש-.toString()
יוגדר מחדש.
הפסקה במקרה של הפרה (במצב 'דוחות בלבד')
בשלב זה, הדרך היחידה לנפות באגים בהפרות של 'משימות טכני' היא להגדיר נקודות עצירה (breakpoint) בחריגים של JS. מאחר שהפרות של TT שחלות עליהם אכיפה יגרמו להפעלת חריגה, התכונה הזו יכולה להיות שימושית. עם זאת, בתרחישים בעולם האמיתי, צריך יותר שליטה מפורטת על הפרות של TT. באופן ספציפי, אנחנו רוצים להפסיק את השימוש רק בהפרות של 'TTD' (ולא בחריגים אחרים), להפסיק את החלוקה גם במצב 'דיווח בלבד' ולהבחין בין הסוגים השונים של הפרות מסוג 'TT'.
כבר יש תמיכה במגוון רחב של נקודות עצירה ב-DevTools, כך שהארכיטקטורה ניתנת להרחבה. כדי להוסיף סוג חדש של נקודת עצירה, צריך לבצע שינויים בקצה העורפי (Blink), ב-CDP ובקצה הקדמי.
כדאי להציג פקודה חדשה של CDP, נקרא לה setBreakOnTTViolation
. הפקודה הזו תשמש את הקצה העורפי כדי ליידע את הקצה העורפי על סוג ההפרות של 'דברים שאפשר לעשות' שהיא צריכה להפסיק. הקצה העורפי, במיוחד InspectorDOMDebuggerAgent
, יספק 'בדיקה', onTTViolation()
, שתיקרא בכל פעם שמתרחשת הפרה של הסכם 'TT'. לאחר מכן, InspectorDOMDebuggerAgent
יבדוק אם צריך להפעיל נקודת עצירה בגלל ההפרה הזו, ואם כן, הוא ישלח הודעה לקצה הקדמי כדי להשהות את הביצוע.
מה כבר בוצע ומה השלב הבא?
מאז שהבעיות המתוארות כאן הופיעו, בכרטיסייה בעיות בוצעו כמה שינויים:
- שופרה הקישור שלו עם חלוניות אחרות בכלי הפיתוח.
- הדיווח על מספר בעיות נוספות הועבר לכרטיסייה בעיות: ניגודיות נמוכה, פעילות מהימנה באינטרנט, מצב תאימות, Attribution Reporting API ובעיות שקשורות ל-CORS ועוד.
- נוספה אפשרות להסתיר בעיות
בהמשך, אנחנו מתכננים להשתמש בכרטיסייה בעיות כדי להציג בעיות נוספות. כך נוכל להפחית את העומס על מסוף Google בטווח הארוך, ולהפסיק להציג בו הודעות שגיאה שלא ניתן לקרוא.
הורדת הערוצים לתצוגה מקדימה
מומלץ להשתמש ב-Chrome Canary, ב-Dev או ב-Beta כדפדפן הפיתוח שמוגדר כברירת מחדל. ערוצי התצוגה המקדימה האלה מעניקים לכם גישה לתכונות העדכניות ביותר של DevTools, מאפשרים לכם לבדוק ממשקי API מתקדמים לפלטפורמות אינטרנט ולמצוא בעיות באתר לפני שהמשתמשים שלכם יעשו זאת.
פנייה לצוות של כלי הפיתוח ל-Chrome
אפשר לבחור מבין האפשרויות הבאות כדי לדון בתכונות החדשות, בעדכונים או בכל נושא אחר שקשור לכלי פיתוח.
- אתם יכולים לשלוח לנו משוב ובקשות להוספת תכונות בכתובת crbug.com.
- מדווחים על בעיה בכלי הפיתוח באמצעות הסמל אפשרויות נוספות > עזרה > דיווח על בעיה בכלי הפיתוח ב-DevTools.
- שולחים ציוץ אל @ChromeDevTools.
- אפשר להשאיר תגובות בסרטונים של מה חדש בכלי הפיתוח ב-YouTube או בסרטונים של טיפים לכלי הפיתוח ב-YouTube.