לתוספים יש גישה להרשאות מיוחדות בדפדפן, ולכן הם מהווים יעד אטרקטיבי לתוקפים. אם תוסף נפרץ, כל משתמש בתוסף הזה הופך לפגיע לפריצות זדוניות ולא רצויות. כדי לשמור על האבטחה של תוסף ולהגן על המשתמשים שלו, כדאי להשתמש בשיטות הבאות.
הגנה על חשבונות פיתוח
קוד התוסף מועלה ומתעדכן דרך חשבונות Google. אם חשבונות המפתחים נפרצים, התוקף יכול להפיץ קוד זדוני ישירות לכל המשתמשים. כדי להגן על החשבונות האלה, כדאי להפעיל אימות דו-שלבי, ועדיף להשתמש במפתח אבטחה.
שימוש בתפקידים מתאימים של חברים
אם לבעל התוכן הדיגיטלי יש כמה חברים, צריך לוודא שהתפקיד שהוקצה לכל משתמש מתאים.
אף פעם לא להשתמש ב-HTTP
כשמבקשים או שולחים נתונים, צריך להימנע מחיבור HTTP. צריך להניח שחיבורי HTTP יהיו חשופים להאזנות או לשינויים. תמיד עדיף להשתמש ב-HTTPS, כי יש לו אבטחה מובנית שמונעת את רוב ההתקפות מסוג Man-in-the-middle.
בקשת הרשאות מינימליות
דפדפן Chrome מגביל את הגישה של תוסף להרשאות שנדרשו באופן מפורש במניפסט. כדי למזער את ההרשאות, התוספים צריכים לרשום רק את ממשקי ה-API והאתרים שהם תלויים בהם.
הגבלת ההרשאות של תוסף מגבילה את מה שתוקף פוטנציאלי יכול לנצל.
fetch() ממקורות שונים
תוסף יכול להשתמש רק ב-fetch() וב-XMLHttpRequest() כדי לקבל משאבים מהתוסף ומדומיינים שצוינו בהרשאות. שימו לב שהקריאות לשניהם נחסמות על ידי רכיב ה-handler של fetch בקובץ ה-service worker.
{
"name": "Very Secure Extension",
"version": "1.0",
"description": "Example of a Secure Extension",
"host_permissions": [
"https://developer.chrome.com/*",
"https://*.google.com/*"
],
"manifest_version": 3
}
התוסף הזה בדוגמה שלמעלה מבקש גישה לכל מה שנמצא ב-developer.chrome.com ולתתי-דומיין של Google. הוא עושה זאת על ידי רישום "https://developer.chrome.com/*" ו-"https://*.google.com/*" בהרשאות. גם אם התוסף ייפרץ, הוא עדיין יוכל לקיים אינטראקציה רק עם אתרים שעומדים בתבנית ההתאמה. התוקף יוכל לגשת ל-"https://user_bank_info.com" רק באופן מוגבל, או ליצור אינטראקציה עם "https://malicious_website.com".
הגבלת שדות המניפסט
הכללה של מפתחות והרשאות מיותרים במניפסט יוצרת נקודות חולשה והופכת את התוסף לגלוי יותר. מגבילים את השדות במניפסט לאלה שהתוסף מסתמך עליהם.
אפשר להתחבר אליהם באופן חיצוני
משתמשים בשדה "externally_connectable" כדי להצהיר עם אילו תוספים חיצוניים ודפי אינטרנט התוסף יחליף מידע. להגביל את המקורות החיצוניים שהתוסף יכול להתחבר אליהם למקורות מהימנים.
{
"name": "Super Safe Extension",
"externally_connectable": {
"ids": [
"iamafriendlyextensionhereisdatas"
],
"matches": [
"https://developer.chrome.com/*",
"https://*.google.com/*"
],
"accepts_tls_channel_id": false
},
...
}
משאבים שאפשר לגשת אליהם באינטרנט
אם תאפשרו גישה למשאבים דרך האינטרנט, בקטע "web_accessible_resources", האתרים והתוקפים יוכלו לזהות את התוסף.
{
...
"web_accessible_resources": [
{
"resources": [ "test1.png", "test2.png" ],
"matches": [ "https://web-accessible-resources-1.glitch.me/*" ]
}
]
...
}
ככל שיש יותר משאבים שנגישים דרך האינטרנט, כך יש לתוקף פוטנציאלי יותר דרכים לנצל אותם. כדאי לצמצם את מספר הקבצים האלה.
לכלול מדיניות מפורשת בנושא אבטחת תוכן
כדי למנוע מתקפות שמקורן בפרצת אבטחה XSS (cross-site scripting), צריך לכלול במניפסט מדיניות אבטחת תוכן עבור התוסף. אם התוסף טוען רק משאבים מעצמו, צריך לרשום את הדברים הבאים:
{
"name": "Very Secure Extension",
"version": "1.0",
"description": "Example of a Secure Extension",
"content_security_policy": {
"extension_pages": "default-src 'self'"
},
"manifest_version": 3
}
אם התוסף צריך להשתמש ב-WebAssembly או להגדיל את ההגבלות על דפים ב-Sandbox, אפשר להוסיף אותם:
{
"name": "Very Secure Extension",
"version": "1.0",
"description": "Example of a Secure Extension",
"content_security_policy": {
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';",
"sandboxed_pages":"script-src 'self' 'wasm-unsafe-eval'; object-src 'self';"
},
"manifest_version": 3
}
הימנעו משימוש ב-document.write() וב-innerHTML
יכול להיות שיהיה פשוט יותר ליצור באופן דינמי רכיבי HTML באמצעות document.write() ו-innerHTML, אבל כך התוסף ודפי האינטרנט שהתוסף תלוי בהם יהיו חשופים להחדרת סקריפטים זדוניים על ידי תוקפים. במקום זאת, צריך ליצור ידנית צמתי DOM ולהשתמש ב-innerText כדי להוסיף תוכן דינמי.
function constructDOM() {
let newTitle = document.createElement('h1');
newTitle.innerText = host;
document.appendChild(newTitle);
}
שימוש זהיר בסקריפטים של תוכן
למרות שסקריפטים של תוכן פועלים בסביבה מבודדת, הם לא חסינים מפני התקפות:
- סקריפטים של תוכן הם החלק היחיד בתוסף שמקיים אינטראקציה ישירה עם דף האינטרנט. לכן, דפי אינטרנט עוינים עשויים לתפעל חלקים ב-DOM שהסקריפט תלוי בהם, או לנצל התנהגות מפתיעה של תקן האינטרנט, כמו פריטים עם שם.
- כדי ליצור אינטראקציה עם DOM של דפי אינטרנט, סקריפטים של תוכן צריכים לפעול באותו תהליך עיבוד כמו דף האינטרנט. כך, סקריפטים של תוכן חשופים לדליפת נתונים דרך מתקפות בערוצים צדדיים (למשל, Spectre), וגם להשתלטות של תוקף אם דף אינטרנט זדוני פוגע בתהליך העיבוד.
פעולות שמשתמשות במידע אישי רגיש (כמו מידע פרטי של משתמש) או בממשקי API של Chrome עם גישה לפונקציות של הדפדפן צריכות להתבצע בקובץ השירות (service worker) של התוספים. כדי למנוע חשיפה לא מכוונת של הרשאות התוסף לסקריפטים של תוכן:
- צריך להניח שהודעות מסקריפט תוכן עשויות להיות מנוסחות על ידי תוקף (לדוגמה, צריך לאמת ולנקות את כל הקלט ולהגן על הסקריפטים מפני פרצת אבטחה XSS (cross-site scripting)).
- צריך להניח שכל נתון שנשלח לסקריפט התוכן עלול לדלוף לדף האינטרנט. אל תשלחו מידע אישי רגיש (למשל, סודות מהתוסף, נתונים ממקורות אינטרנט אחרים, היסטוריית גלישה) לסקריפטים של תוכן.
- להגביל את היקף הפעולות עם הרשאות מיוחדות שאפשר להפעיל באמצעות סקריפטים של תוכן. אל תאפשרו לסקריפטים של תוכן להפעיל בקשות לכתובות URL שרירותיות או להעביר ארגומנטים שרירותיים לממשקי API של תוספים (לדוגמה, אל תאפשרו העברה של כתובות URL שרירותיות לשיטות
fetch()אוbrowser.tabs.create()).
רישום וניקוי של קלט
כדי להגן על תוסף מפני סקריפטים זדוניים, צריך להגביל את המאזינים רק למה שהתוסף מצפה, לאמת את השולחים של נתונים נכנסים ולבצע סניטציה של כל הקלטים.
תוסף צריך להירשם רק ל-runtime.onMessageExternal אם הוא צפוי לקבל תקשורת מאתר או מתוסף חיצוניים. תמיד צריך לוודא שהשולח תואם למקור מהימן.
// The ID of an external extension
const kFriendlyExtensionId = "iamafriendlyextensionhereisdatas";
browser.runtime.onMessageExternal.addListener(
function(request, sender, sendResponse) {
if (sender.id === kFriendlyExtensionId)
doSomething();
});
גם הודעות דרך אירוע runtime.onMessage מהתוסף עצמו צריכות להיבדק כדי לוודא ש-MessageSender לא מגיע מסקריפט תוכן שנפרץ.
browser.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.allowedAction)
console.log("This is an allowed action.");
});