לתוספים יש גישה להרשאות מיוחדות בדפדפן, ולכן הם יעד אטרקטיבי לתוקפים. אם תוסף נפרץ, כל המשתמשים בתוסף הזה חשופים לפריצה זדונית ולא רצויה. כדי לשמור על אבטחת התוסף ולהגן על המשתמשים שלו, כדאי להשתמש בשיטות האלה.
הגנה על חשבונות פיתוח
הקוד של התוסף מועלה ומעודכן דרך חשבונות Google. אם חשבונות המפתחים נפרצו, תוקף יכול לדחוף קוד זדוני ישירות לכל המשתמשים. כדי להגן על החשבונות האלה, כדאי להפעיל אימות דו-שלבי, רצוי באמצעות מפתח אבטחה.
שמירה על קבוצות נבחרות
אם אתם משתמשים בפרסום קבוצתי, חשוב שהקבוצה תכלול רק מפתחים מהימנים. אל תאשרו בקשות להצטרפות לקבוצה מאנשים לא מוכרים.
לעולם לא להשתמש ב-HTTP
כששולחים או מבקשים נתונים, כדאי להימנע משימוש בחיבור HTTP. צריך להניח שכל חיבורי ה-HTTP יהיו חשופים למאזינים או יכילו שינויים. תמיד עדיף להשתמש ב-HTTPS, כי יש לו אבטחה מובנית שמאפשרת לעקוף את רוב התקפות ה-Man-in-the-middle.
בקשה להרשאות מינימליות
דפדפן Chrome מגביל את הגישה של תוסף להרשאות שביקשת במפורש בmanifest. תוספים צריכים לצמצם את ההרשאות שלהם על ידי רישום רק של ממשקי API ואתרים שהם תלויים בהם.
הגבלת ההרשאות של תוסף מגבילה את האפשרויות של תוקף פוטנציאלי לנצל לרעה.
fetch() חוצה-דומיינים
תוסף יכול להשתמש ב-fetch()
וב-XMLHttpRequest()
רק כדי לקבל משאבים מהתוסף ומדומיינים שצוינו בהרשאות. חשוב לזכור שהקריאות לשניהם מנותבות על ידי הטיפול ב-fetch בקובץ השירות.
{
"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, צריך לכלול במניפסט מדיניות אבטחת תוכן לתוסף. אם התוסף טוען משאבים רק מעצמו, צריך לרשום את הפרטים הבאים:
{
"name": "Very Secure Extension",
"version": "1.0",
"description": "Example of a Secure Extension",
"content_security_policy": {
"extension_pages": "default-src 'self'"
},
"manifest_version": 3
}
אם התוסף צריך להשתמש ב-Web Assembly או להגדיל את ההגבלות על דפים ב-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), וגם לאפשרות של השתלטות על המחשב על ידי תוקף אם דף אינטרנט זדוני יפגע בתהליך העיבוד.
פעולות שמשתמשות בנתונים רגישים (כמו פרטים אישיים של משתמש) או ב-Chrome APIs עם גישה לפונקציות של הדפדפן צריכות להתבצע ב-service worker של התוספים. כדי להימנע מחשיפת זכויות של תוספים בטעות לסקריפטים של תוכן:
- להניח שהודעות מסקריפט תוכן עשויות להיות מעשה ידי תוקף (למשל, אימות וחיטוי של כל הקלט והגנה על הסקריפטים מפני סקריפטים בין אתרים).
- צריך להניח שכל נתון שנשלח לסקריפט התוכן עלול לדלוף לדף האינטרנט. אין לשלוח סקריפטים של תוכן עם מידע אישי רגיש (למשל סודות מהתוסף, נתונים ממקורות אחרים באינטרנט, היסטוריית גלישה).
- להגביל את היקף הפעולות עם הרשאות שסקריפטים של תוכן יכולים להפעיל. אסור לאפשר לסקריפטים של תוכן להפעיל בקשות לכתובות URL שרירותיות או להעביר ארגומנטים שרירותיים לממשקי API של תוספים (למשל, אסור לאפשר העברה של כתובות URL שרירותיות לשיטות
fetch()
אוchrome.tabs.create()
).
רישום וסינון של מקורות קלט
כדי להגן על תוסף מסקריפטים זדוניים, מגבילים את המאזינים רק למה שהתוסף מצפה לו, מאמתים את השולחים של הנתונים הנכנסים ומטפלים בכל הקלט.
תוסף צריך להירשם ל-runtime.onMessageExternal
רק אם הוא מצפה לתקשורת מאתר או מתוסף חיצוני. תמיד צריך לוודא שהשולח תואם למקור מהימן.
// The ID of an external extension
const kFriendlyExtensionId = "iamafriendlyextensionhereisdatas";
chrome.runtime.onMessageExternal.addListener(
function(request, sender, sendResponse) {
if (sender.id === kFriendlyExtensionId)
doSomething();
});
גם הודעות שמתקבלות דרך האירוע runtime.onMessage מהתוסף עצמו צריכות לעבור בדיקה קפדנית כדי לוודא ש-MessageSender לא מגיע מסקריפט תוכן שנפרץ.
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.allowedAction)
console.log("This is an allowed action.");
});