283 lines
10 KiB
JavaScript
283 lines
10 KiB
JavaScript
/**
|
|
* Mercedes-Benz MYP Platform - CSP Violation Handler
|
|
* Protokolliert und behandelt Content Security Policy Verletzungen
|
|
*/
|
|
|
|
class CSPViolationHandler {
|
|
constructor() {
|
|
this.violations = [];
|
|
this.init();
|
|
}
|
|
|
|
init() {
|
|
// CSP Violation Event Listener
|
|
document.addEventListener('securitypolicyviolation', this.handleViolation.bind(this));
|
|
|
|
// Report-To API fallback
|
|
if ('ReportingObserver' in window) {
|
|
const observer = new ReportingObserver((reports, observer) => {
|
|
for (const report of reports) {
|
|
if (report.type === 'csp-violation') {
|
|
this.handleViolation(report.body);
|
|
}
|
|
}
|
|
});
|
|
observer.observe();
|
|
}
|
|
|
|
console.log('🛡️ CSP Violation Handler initialisiert');
|
|
}
|
|
|
|
/**
|
|
* CSP-Verletzung behandeln
|
|
*/
|
|
handleViolation(violationEvent) {
|
|
const violation = {
|
|
timestamp: new Date().toISOString(),
|
|
blockedURI: violationEvent.blockedURI || 'unknown',
|
|
violatedDirective: violationEvent.violatedDirective || 'unknown',
|
|
originalPolicy: violationEvent.originalPolicy || 'unknown',
|
|
documentURI: violationEvent.documentURI || window.location.href,
|
|
sourceFile: violationEvent.sourceFile || 'unknown',
|
|
lineNumber: violationEvent.lineNumber || 0,
|
|
columnNumber: violationEvent.columnNumber || 0,
|
|
sample: violationEvent.sample || '',
|
|
disposition: violationEvent.disposition || 'enforce'
|
|
};
|
|
|
|
this.violations.push(violation);
|
|
this.logViolation(violation);
|
|
this.suggestFix(violation);
|
|
|
|
// Violation an Server senden (falls API verfügbar)
|
|
this.reportViolation(violation);
|
|
}
|
|
|
|
/**
|
|
* Verletzung protokollieren
|
|
*/
|
|
logViolation(violation) {
|
|
console.group('🚨 CSP Violation detected');
|
|
console.error('Blocked URI:', violation.blockedURI);
|
|
console.error('Violated Directive:', violation.violatedDirective);
|
|
console.error('Source:', `${violation.sourceFile}:${violation.lineNumber}:${violation.columnNumber}`);
|
|
console.error('Sample:', violation.sample);
|
|
console.error('Full Policy:', violation.originalPolicy);
|
|
console.groupEnd();
|
|
}
|
|
|
|
/**
|
|
* Lösungsvorschlag basierend auf Verletzungstyp
|
|
*/
|
|
suggestFix(violation) {
|
|
const directive = violation.violatedDirective;
|
|
const blockedURI = violation.blockedURI;
|
|
|
|
console.group('💡 Lösungsvorschlag');
|
|
|
|
if (directive.includes('script-src')) {
|
|
if (blockedURI === 'inline') {
|
|
console.log('Problem: Inline-Script blockiert');
|
|
console.log('Lösung 1: Script in externe .js-Datei auslagern');
|
|
console.log('Lösung 2: data-action Attribute für Event-Handler verwenden');
|
|
console.log('Lösung 3: Nonce verwenden (nicht empfohlen für Entwicklung)');
|
|
console.log('Beispiel: <button data-action="refresh-dashboard">Aktualisieren</button>');
|
|
} else if (blockedURI.includes('eval')) {
|
|
console.log('Problem: eval() oder ähnliche Funktionen blockiert');
|
|
console.log('Lösung: Verwende sichere Alternativen zu eval()');
|
|
} else {
|
|
console.log(`Problem: Externes Script von ${blockedURI} blockiert`);
|
|
console.log('Lösung: URL zur CSP script-src Richtlinie hinzufügen');
|
|
}
|
|
} else if (directive.includes('style-src')) {
|
|
console.log('Problem: Style blockiert');
|
|
console.log('Lösung: CSS in externe .css-Datei auslagern oder CSP erweitern');
|
|
} else if (directive.includes('connect-src')) {
|
|
console.log(`Problem: Verbindung zu ${blockedURI} blockiert`);
|
|
console.log('Lösung: URL zur CSP connect-src Richtlinie hinzufügen');
|
|
console.log('Tipp: Für API-Calls relative URLs verwenden');
|
|
} else if (directive.includes('img-src')) {
|
|
console.log(`Problem: Bild von ${blockedURI} blockiert`);
|
|
console.log('Lösung: URL zur CSP img-src Richtlinie hinzufügen');
|
|
}
|
|
|
|
console.groupEnd();
|
|
}
|
|
|
|
/**
|
|
* Verletzung an Server senden
|
|
*/
|
|
async reportViolation(violation) {
|
|
try {
|
|
// Nur in Produktion an Server senden
|
|
if (window.location.hostname !== 'localhost' && window.location.hostname !== '127.0.0.1') {
|
|
await fetch('/api/security/csp-violation', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(violation)
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.warn('Fehler beim Senden der CSP-Verletzung:', error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Alle Verletzungen abrufen
|
|
*/
|
|
getViolations() {
|
|
return this.violations;
|
|
}
|
|
|
|
/**
|
|
* Verletzungsstatistiken
|
|
*/
|
|
getStats() {
|
|
const stats = {
|
|
total: this.violations.length,
|
|
byDirective: {},
|
|
byURI: {},
|
|
recent: this.violations.slice(-10)
|
|
};
|
|
|
|
this.violations.forEach(violation => {
|
|
// Nach Direktive gruppieren
|
|
const directive = violation.violatedDirective;
|
|
stats.byDirective[directive] = (stats.byDirective[directive] || 0) + 1;
|
|
|
|
// Nach URI gruppieren
|
|
const uri = violation.blockedURI;
|
|
stats.byURI[uri] = (stats.byURI[uri] || 0) + 1;
|
|
});
|
|
|
|
return stats;
|
|
}
|
|
|
|
/**
|
|
* Entwickler-Debugging-Tools
|
|
*/
|
|
enableDebugMode() {
|
|
// Debug-Panel erstellen
|
|
this.createDebugPanel();
|
|
|
|
// Konsolen-Hilfe ausgeben
|
|
console.log('🔧 CSP Debug Mode aktiviert');
|
|
console.log('Verfügbare Befehle:');
|
|
console.log('- cspHandler.getViolations() - Alle Verletzungen anzeigen');
|
|
console.log('- cspHandler.getStats() - Statistiken anzeigen');
|
|
console.log('- cspHandler.clearViolations() - Verletzungen löschen');
|
|
console.log('- cspHandler.exportViolations() - Als JSON exportieren');
|
|
}
|
|
|
|
/**
|
|
* Debug-Panel erstellen
|
|
*/
|
|
createDebugPanel() {
|
|
const panel = document.createElement('div');
|
|
panel.id = 'csp-debug-panel';
|
|
panel.style.cssText = `
|
|
position: fixed;
|
|
top: 10px;
|
|
right: 10px;
|
|
width: 300px;
|
|
max-height: 400px;
|
|
background: rgba(0, 0, 0, 0.9);
|
|
color: white;
|
|
font-family: monospace;
|
|
font-size: 12px;
|
|
padding: 10px;
|
|
border-radius: 5px;
|
|
z-index: 10000;
|
|
overflow-y: auto;
|
|
display: none;
|
|
`;
|
|
|
|
panel.innerHTML = `
|
|
<div style="display: flex; justify-content: space-between; margin-bottom: 10px;">
|
|
<strong>CSP Violations</strong>
|
|
<button onclick="this.parentElement.parentElement.style.display='none'"
|
|
style="background: none; border: none; color: white; cursor: pointer;">×</button>
|
|
</div>
|
|
<div id="csp-violations-list"></div>
|
|
<div style="margin-top: 10px;">
|
|
<button onclick="cspHandler.clearViolations()"
|
|
style="background: #333; color: white; border: none; padding: 5px; margin-right: 5px; cursor: pointer;">Clear</button>
|
|
<button onclick="cspHandler.exportViolations()"
|
|
style="background: #333; color: white; border: none; padding: 5px; cursor: pointer;">Export</button>
|
|
</div>
|
|
`;
|
|
|
|
document.body.appendChild(panel);
|
|
|
|
// Shortcut zum Anzeigen/Verstecken
|
|
document.addEventListener('keydown', (event) => {
|
|
if (event.ctrlKey && event.shiftKey && event.key === 'C') {
|
|
panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
|
|
this.updateDebugPanel();
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Debug-Panel aktualisieren
|
|
*/
|
|
updateDebugPanel() {
|
|
const list = document.getElementById('csp-violations-list');
|
|
if (!list) return;
|
|
|
|
const recent = this.violations.slice(-5);
|
|
list.innerHTML = recent.map(v => `
|
|
<div style="margin-bottom: 5px; padding: 5px; background: rgba(255, 255, 255, 0.1);">
|
|
<div><strong>${v.violatedDirective}</strong></div>
|
|
<div style="color: #ff6b6b;">${v.blockedURI}</div>
|
|
<div style="color: #ffd93d; font-size: 10px;">${v.timestamp}</div>
|
|
</div>
|
|
`).join('');
|
|
}
|
|
|
|
/**
|
|
* Verletzungen löschen
|
|
*/
|
|
clearViolations() {
|
|
this.violations = [];
|
|
this.updateDebugPanel();
|
|
console.log('🗑️ CSP Violations gelöscht');
|
|
}
|
|
|
|
/**
|
|
* Verletzungen exportieren
|
|
*/
|
|
exportViolations() {
|
|
const data = {
|
|
timestamp: new Date().toISOString(),
|
|
stats: this.getStats(),
|
|
violations: this.violations
|
|
};
|
|
|
|
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = `csp-violations-${new Date().toISOString().split('T')[0]}.json`;
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
|
|
console.log('📄 CSP Violations exportiert');
|
|
}
|
|
}
|
|
|
|
// Globale Instanz erstellen
|
|
const cspHandler = new CSPViolationHandler();
|
|
|
|
// In Entwicklungsumgebung Debug-Mode aktivieren
|
|
if (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1') {
|
|
cspHandler.enableDebugMode();
|
|
console.log('🔍 CSP Debug Mode aktiv - Drücken Sie Ctrl+Shift+C für Debug-Panel');
|
|
}
|
|
|
|
// Global verfügbar machen
|
|
window.cspHandler = cspHandler;
|
|
|
|
console.log('🛡️ CSP Violation Handler geladen');
|