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