Unsichere Drittanbieter-Ressource

Beschreibung

Unsichere Drittanbieter-Ressource tritt auf, wenn eine Webanwendung ausführbaren Code oder Ressourcen von einer Drittanbieter-Quelle einbindet, die böswillig modifiziert werden könnten. Dies umfasst JavaScript-Bibliotheken, die von CDNs geladen werden, externe Stylesheets, Schriftarten, Bilder und iframes. Wenn die Drittanbieter-Ressource kompromittiert, modifiziert oder über eine unsichere Verbindung bereitgestellt wird, können Angreifer bösartigen Code in Websites injizieren, die von diesen Ressourcen abhängen. Dies ist eine Form von Supply-Chain-Angriff, die auf Webanwendungen abzielt.

Risiko

Die Kompromittierung von Drittanbieter-Ressourcen hat massive Sicherheitsvorfälle verursacht. Die Magecart-Angriffe haben Tausende von E-Commerce-Seiten durch kompromittierte gemeinsame JavaScript-Bibliotheken betroffen. British Airways erlitt eine Datenschutzverletzung, die 380.000 Kunden durch kompromittierte Drittanbieter-Skripte betraf. CDN-Kompromittierungen können Millionen von Websites gleichzeitig betreffen. Selbst legitime CDNs können durch Cache-Poisoning korrumpierte Inhalte liefern. Man-in-the-Middle-Angriffe auf HTTP-Ressourcen ermöglichen Code-Injektion.

Lösung

Verwenden Sie Subresource Integrity (SRI), um zu überprüfen, dass abgerufene Ressourcen den erwarteten Hashes entsprechen. Laden Sie Ressourcen nur über HTTPS. Hosten Sie kritische JavaScript-Bibliotheken selbst, anstatt sich auf CDNs zu verlassen. Implementieren Sie Content Security Policy (CSP), um Ressourcenquellen einzuschränken. Überprüfen Sie regelmäßig Drittanbieter-Abhängigkeiten. Verwenden Sie npm audit, Snyk oder ähnliche Tools zum Abhängigkeits-Scanning. Minimieren Sie Drittanbieter-Abhängigkeiten. Überwachen Sie Änderungen an Drittanbieter-Ressourcen.

Häufige Auswirkungen

AuswirkungDetails
IntegritätBereich: Code-Injektion

Kompromittierte Drittanbieter-Ressourcen können beliebiges JavaScript in den Browsern der Benutzer ausführen.
VertraulichkeitBereich: Datendiebstahl

Bösartige Skripte können Anmeldedaten, Zahlungsinformationen und Session-Token stehlen.
VerfügbarkeitBereich: Dienststörung

Verunstaltete oder defekte Ressourcen können Websites unbenutzbar machen.

Beispielcode und Lösung

Verwundbarer Code

<!-- VERWUNDBAR: Keine Integritätsprüfung bei CDN-Ressourcen -->
<script src="https://cdn.example.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.example.com/bootstrap.min.js"></script>

<!-- VERWUNDBAR: Laden über HTTP -->
<script src="http://cdn.example.com/library.js"></script>

<!-- VERWUNDBAR: Drittanbieter-Analytics ohne Integrität -->
<script src="https://analytics.thirdparty.com/tracker.js"></script>

<!-- VERWUNDBAR: Externe Stylesheets -->
<link rel="stylesheet" href="https://cdn.example.com/styles.css">

<!-- VERWUNDBAR: Drittanbieter-iframe ohne Sandbox -->
<iframe src="https://widget.thirdparty.com/embed"></iframe>

<!-- VERWUNDBAR: Dynamisches Laden von Skripten -->
<script>
    var script = document.createElement('script');
    script.src = 'https://cdn.example.com/dynamic.js';
    document.head.appendChild(script);
</script>
# VERWUNDBAR: Server-seitige Einbindung von Drittanbieter-Ressource
import requests

@app.route('/proxy/script')
def proxy_script():
    # Abrufen und Bereitstellen eines Drittanbieter-Skripts ohne Überprüfung
    response = requests.get('https://cdn.example.com/library.js')
    return response.text, 200, {'Content-Type': 'application/javascript'}

# VERWUNDBAR: Template bindet externe Ressourcen ein
@app.route('/page')
def render_page():
    # Externe Ressourcen-URL aus Konfiguration - könnte kompromittiert sein
    cdn_url = config.get('CDN_URL')
    return render_template('page.html', cdn_url=cdn_url)
// VERWUNDBAR: Dynamisches Laden von Ressourcen in Node.js/Express
app.get('/widget', (req, res) => {
    const widgetUrl = req.query.url;  // Benutzer-kontrolliert!
    res.send(`<script src="${widgetUrl}"></script>`);
});

// VERWUNDBAR: npm-Paket ohne Lock-Datei
// package.json erlaubt schwankende Versionen
{
    "dependencies": {
        "lodash": "^4.0.0",  // Könnte kompromittierte Version erhalten
        "express": "*"       // Jede Version!
    }
}

Sichere Lösung

<!-- SICHER: Subresource Integrity (SRI) -->
<script
    src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"
    integrity="sha384-vtXRMe3mGCbOeY7l30aIg8H9p3GdeSe4IFlP6G8JMa7o7lXvnz3GFKzPxzJdPfGK"
    crossorigin="anonymous">
</script>

<script
    src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"
    integrity="sha384-ODmDIVzN+pFdexxHEHFBQH3/9EggsS7T6UFxMIUY4OHsW9A7EjdgLCw3K9cPRmFw"
    crossorigin="anonymous">
</script>

<!-- SICHER: SRI für Stylesheets -->
<link
    rel="stylesheet"
    href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
    integrity="sha384-gH2yIJqKdNHPEq0n4Mqa/HGKIhSkIHeL5AyhkYV8i59U5AR6csBvApHHNl/vI1Bx"
    crossorigin="anonymous">

<!-- SICHER: Sandboxed iframe -->
<iframe
    src="https://widget.trusted.com/embed"
    sandbox="allow-scripts allow-same-origin"
    loading="lazy">
</iframe>

<!-- SICHER: Content Security Policy -->
<meta http-equiv="Content-Security-Policy"
      content="script-src 'self' https://cdn.jsdelivr.net;
               style-src 'self' https://cdn.jsdelivr.net;
               img-src 'self' data:;
               frame-src https://widget.trusted.com;">
# SICHER: Server-seitige Ressourcenüberprüfung
import requests
import hashlib

KNOWN_HASHES = {
    'jquery-3.6.0.min.js': 'sha384-vtXRMe3mGCbOeY7l30aIg8H9p3GdeSe4IFlP6G8JMa7o7lXvnz3GFKzPxzJdPfGK',
}

def verify_resource(url, content):
    """Überprüft, ob Ressourceninhalt mit bekanntem Hash übereinstimmt."""
    filename = url.split('/')[-1]
    expected_hash = KNOWN_HASHES.get(filename)

    if not expected_hash:
        raise ValueError(f"Unknown resource: {filename}")

    # Hash parsen
    algorithm, expected = expected_hash.split('-')
    if algorithm == 'sha384':
        actual = base64.b64encode(
            hashlib.sha384(content).digest()
        ).decode()

    if actual != expected:
        raise ValueError(f"Resource integrity check failed for {filename}")

    return True

@app.route('/proxy/script')
def proxy_script_safe():
    url = 'https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js'
    response = requests.get(url)

    # Integrität vor Bereitstellung überprüfen
    verify_resource(url, response.content)

    return response.text, 200, {'Content-Type': 'application/javascript'}

# SICHER: Kritische Ressourcen selbst hosten
@app.route('/static/js/<filename>')
def serve_local_script(filename):
    # Aus lokaler verifizierter Kopie bereitstellen
    allowed_files = {'jquery.min.js', 'bootstrap.min.js'}
    if filename not in allowed_files:
        abort(404)
    return send_from_directory('static/js', filename)

# SICHER: CSP-Header
@app.after_request
def add_security_headers(response):
    csp = (
        "default-src 'self'; "
        "script-src 'self' https://cdn.jsdelivr.net 'sha256-...'; "
        "style-src 'self' https://cdn.jsdelivr.net; "
        "img-src 'self' data:; "
        "frame-ancestors 'self';"
    )
    response.headers['Content-Security-Policy'] = csp
    return response
// SICHER: SRI-Hashes beim Build generieren
const crypto = require('crypto');
const fs = require('fs');

function generateSRI(filePath) {
    const content = fs.readFileSync(filePath);
    const hash = crypto.createHash('sha384').update(content).digest('base64');
    return `sha384-${hash}`;
}

// Build-Skript zum Generieren von Integritäts-Hashes
const scripts = [
    { file: 'vendor/jquery.min.js', output: 'jquery' },
    { file: 'vendor/bootstrap.min.js', output: 'bootstrap' }
];

const integrityHashes = {};
scripts.forEach(script => {
    integrityHashes[script.output] = generateSRI(script.file);
});

fs.writeFileSync('sri-hashes.json', JSON.stringify(integrityHashes, null, 2));

// SICHER: Gesperrte Abhängigkeiten
// package-lock.json oder yarn.lock stellt exakte Versionen sicher
{
    "dependencies": {
        "lodash": "4.17.21",  // Exakte Version
        "express": "4.18.2"   // Exakte Version
    }
}

// SICHER: Dynamisches Laden mit Integritätsprüfung
async function loadScriptWithSRI(url, expectedHash) {
    const script = document.createElement('script');
    script.src = url;
    script.integrity = expectedHash;
    script.crossOrigin = 'anonymous';

    return new Promise((resolve, reject) => {
        script.onload = resolve;
        script.onerror = () => reject(new Error(`Failed to load ${url}`));
        document.head.appendChild(script);
    });
}

// Verwendung
await loadScriptWithSRI(
    'https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js',
    'sha384-...'
);

// SICHER: CSP-Konfiguration in Express
const helmet = require('helmet');

app.use(helmet.contentSecurityPolicy({
    directives: {
        defaultSrc: ["'self'"],
        scriptSrc: [
            "'self'",
            "https://cdn.jsdelivr.net",
            // Bestimmte Inline-Skripte per Hash erlauben
            "'sha256-abc123...'"
        ],
        styleSrc: ["'self'", "https://cdn.jsdelivr.net"],
        imgSrc: ["'self'", "data:"],
        frameSrc: ["'none'"],
        upgradeInsecureRequests: []
    }
}));

Ausgenutzt in der Praxis

British Airways Datenschutzverletzung (2018)

Angreifer kompromittierten eine Drittanbieter-JavaScript-Bibliothek auf der British-Airways-Website und injizierten Code, der Zahlungskartendaten von 380.000 Kunden über einen Zeitraum von zwei Wochen abgriff.

Magecart-Angriffe (2018-heute)

Mehrere E-Commerce-Seiten wurden durch gemeinsam genutzte JavaScript-Bibliotheken kompromittiert, wobei Angreifer Zahlungs-Skimming-Code injizierten, der Millionen von Kunden auf Tausenden von Websites betraf.

event-stream npm-Paket-Kompromittierung (2018)

Ein beliebtes npm-Paket (event-stream) wurde durch einen böswilligen Maintainer kompromittiert, der Code zum Stehlen von Kryptowährung aus bestimmten Anwendungen hinzufügte.


Tools zum Testen und Ausnutzen


CVE-Beispiele


Referenzen

  1. MITRE. "CWE-1035: Insecure Third Party Resource." https://cwe.mitre.org/data/definitions/1035.html

  2. MDN. "Subresource Integrity." https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity