Anwendungssicherheit

DHTMLX Gantt ist eine JavaScript-Bibliothek, die entwickelt wurde, um Gantt-Diagrammfunktionalität nahtlos in Webanwendungen zu integrieren. Sie bietet eine breite Palette an Anpassungsfunktionen, die Entwicklern ermöglichen, sie an ihre spezifischen Projektanforderungen anzupassen. Es ist jedoch wichtig zu beachten, dass DHTMLX Gantt keinen integrierten Schutz gegen Bedrohungen wie SQL-Injection, XSS oder CSRF-Angriffe bietet. Die Sicherheit Ihrer Anwendung sicherzustellen, erfordert, dass Sie die notwendigen Konfigurationen und Schutzmaßnahmen selbst implementieren. Nachfolgend finden Sie einige Empfehlungen für den effektiven Umgang mit HTML-Sanitisierung.

Grundlegende Sicherheitsmaßnahmen

Cybersicherheit ist ein weites Feld, und kein einzelner Leitfaden kann alles abdecken. Das Befolgen dieser praktischen Schritte kann jedoch helfen, häufige Schwachstellen zu adressieren und Risiken zu verringern.

1. Verwenden Sie die Content Security Policy (CSP)

Das Hinzufügen eines CSP-Headers wie diesem kann die Ausführung von Inline-Skripten blockieren und das Risiko von XSS- und CSRF-Angriffen erheblich reduzieren:

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

Je nach den Anforderungen Ihrer App benötigen Sie möglicherweise eine detailliertere Richtlinie, aber das Deaktivieren von Inline-Skripten ist ein guter Ausgangspunkt.

2. Sanitieren Sie Benutzereingaben im Backend

Bevor Sie Benutzereingaben in Ihrer Datenbank speichern, stellen Sie sicher, dass die Daten ordnungsgemäß gesäubert werden, um bösartigen Inhalt zu entfernen. Anstatt beispielsweise rohe Werte direkt einzufügen:

db.query("INSERT INTO gantt_tasks(text, start_date, duration, progress, parent)"
    + " VALUES (?,?,?,?,?)",
    [task.text, task.start_date, task.duration, task.progress, task.parent])

Verwenden Sie eine Bibliothek wie DOMPurify mit Node.js, um Eingaben zu reinigen:

const createDOMPurify = require('dompurify');
const { JSDOM } = require('jsdom');
 
const window = new JSDOM('').window;
const DOMPurify = createDOMPurify(window);
 
...
 
db.query("INSERT INTO gantt_tasks(text, start_date, duration, progress, parent)"
    + " VALUES (?,?,?,?,?)",
    [task.text, task.start_date, task.duration, task.progress, task.parent]
        .map((input) => DOMPurify.sanitize(input))

3. HTML-Entitäten vor der Datenanzeige escapen

Um zu verhindern, dass HTML-Markup während der Anzeige ausgeführt wird, escapen Sie HTML-Zeichen in benutzergenerierten Daten. Zum Beispiel mit der validator Bibliothek:

const validator = require('validator');
...
 
// GET /data
 
Promise.all([
  db.query("SELECT * FROM gantt_tasks"),
  db.query("SELECT * FROM gantt_links")
]).then(results => {
    let tasks = results[0],
        links = results[1];
 
    tasks.forEach((task) => {
        Object.entries(task).forEach(([key, value]) => {
            if(typeof value === "string") {
                task[key] = validator.escape(value); //#!
            }
        });
        task.open = true;
        task.start_date = task.start_date.format("YYYY-MM-DD hh:mm:ss");
    });
 
    links.forEach((link) => {
        Object.entries(link).forEach(([key, value]) => {
            if(typeof value === "string") {
                link[key] = validator.escape(value); //#!
            }
        });
    });
 
 
    res.send({
        tasks,
        links 
   });

4. Verwenden Sie Parametrisierte Abfragen oder ORM für SQL-Datenbanken

Um SQL-Injection-Angriffe zu verhindern, vermeiden Sie den Aufbau von SQL-Abfragen durch das Verketten von Zeichenfolgen. Verwenden Sie stattdessen parametrisierte Abfragen oder einen Abfrage-Builder/ORM. Wenn Sie nicht escapte oder nicht validierte Benutzereingaben in Ihren Abfragen verwenden, lohnt es sich, den Code umzuschreiben, um sicherere Praktiken zu befolgen.

5. Konsultieren Sie Sicherheitsexperten und befolgen Sie Unternehmensrichtlinien

Sicherheit ist ein fortlaufender Prozess. Durch die Implementierung dieser Schritte, das Einhalten der Sicherheitsrichtlinien Ihrer Organisation und die Überprüfung Ihrer Arbeit durch Spezialisten können Sie die meisten gängigen Bedrohungen adressieren.

Mit diesen Grundlagen im Hinterkopf, werfen wir einen Blick auf sicherheitsrelevante Überlegungen, die speziell für Gantt gelten.

Verwundbare Bereiche in Gantt auf der Client-Seite

Bei der Einbindung komplexer Tools wie Gantt auf der Client-Seite gibt es einige wichtige Punkte zu beachten:

  • DHTMLX Gantt verarbeitet Daten, die in ihrer rohen Form vom Server empfangen werden. Da die Daten auf dem Server gespeichert sind, ist die Backend-Sicherheit entscheidend, obwohl sie außerhalb des Gantt-Bereichs liegt.
  • Angreifer können DevTools für Self-XSS-Angriffe ausnutzen, indem sie Benutzer dazu bringen, bösartigen Code auszuführen. Jeder Code, der in den Text einer Aufgabe eingefügt wird, verhält sich, als ob er über DevTools ausgeführt würde.
  • Wenn ein Angreifer Zugriff auf die Gantt-Instanz erhält, kann er Sicherheitsmaßnahmen umgehen, Konfigurationen ändern und die volle Kontrolle übernehmen.

Einige Bereiche, in denen Schwachstellen auftreten können, sind:

  • Von Benutzern eingegebene und gespeicherte Daten
  • Angezeigte Gantt-Daten (Text, visuelle Elemente)
  • Benutzerdefinierte HTML-Elemente, die mit Gantt-Daten interagieren
  • Zugriff auf das Gantt-Objekt selbst

Isolierung des Gantt-Zugriffs

Der Schutz von Gantt beginnt mit der Isolierung von unbefugtem Zugriff, sei es durch kompromittierte Komponenten oder Self-XSS-Angriffe.

Wenn Angreifer Zugriff auf Konfigurationsdateien (einschließlich Gantt-Konfigurationen) erhalten, können XSS-Schutzmaßnahmen wirkungslos sein. Dieses Szenario liegt außerhalb des hier behandelten Umfangs.

Um unbefugten Zugriff auf die Gantt-Instanz zu verhindern, kapseln Sie sie innerhalb einer Funktion. Dies stellt sicher, dass die Instanz außerhalb des Funktionsbereichs nicht zugänglich ist. Zum Beispiel:

function addGantt(){
  const gantt = Gantt.getGanttInstance();
}
addGantt()

Sie können die Instanz auch umbenennen, um Klarheit zu schaffen:

function addGantt(){
  const protectedGantt = Gantt.getGanttInstance();
}
addGantt()

Sobald der Gantt-Zugriff gesichert ist, konzentrieren Sie sich darauf, die Dateneingabe und -anzeige sicher zu handhaben.

Dateneingabe in Gantt

Dateneingabepunkte sind häufige Ziele für XSS-Angriffe. In Gantt können Daten eingegeben werden durch:

  • Lightbox
  • Inline-Editoren
  • Modale Boxen mit benutzerdefinierten Elementen
  • Drittanbieter-Bibliotheken
  • Ressourcenzuweisungen in der Ressourcenlastzeitleiste
  • Zusätzliche Schichten mit benutzerdefinierten Eingabeelementen
  • Benutzerdefinierte Lösungen unter Verwendung der Gantt-API (z.B. Toolbars oder benutzerdefinierte Aufgabenbearbeitungsformulare)

Das Aufgabenobjekt enthält verschiedene Parameter basierend auf den aktivierten Funktionen. Je mehr bearbeitbare Parameter, desto mehr Daten müssen bei der Eingabe bereinigt werden.

Beispielübersicht

Hier ist ein Beispiel, das zeigt, wie Sie den Schutz vor XSS-Angriffen verstärken können, indem Sie HTML bei der Arbeit mit DHTMLX Gantt sanitisieren.

Related sample:  Beispiel zur Verhinderung von XSS-Angriffen (Sicherheit, csp)

In diesem Beispiel können Sie den Namen einer Aufgabe, die Daten, die Dauer, Ressourcenzuweisungen ändern und Notizen hinzufügen. Die Anpassung des Startdatums und der Dauer ist auf die Lightbox und Inline-Editoren beschränkt. Für Inline-Editoren sind die date und number Typen explizit definiert. In der Lightbox können Sie nur die Dauer festlegen, während das Datum aus einem Dropdown ausgewählt wird.

Diese UI-Elemente sind so gestaltet, dass sie die Einfügung von bösartigem Code verhindern. Wenn Sie versuchen, die Elementtypen mit einem DOM-Inspektor zu ändern, führen ungültige Werte für Datum oder Dauer zu Fehlern, die die Funktionalität von Gantt stoppen, bis die Seite neu geladen wird. In solchen Fällen werden keine Daten an den Server gesendet, da die Daten nicht neu gezeichnet werden.

Aufgabennamen, die den string Wertetyp verwenden, können jedoch ein Schwachpunkt für XSS-Angriffe sein. Um dies anzugehen, wird die Eingabe gesäubert. Das Beispiel zeigt ein XSS-Angriffsszenario und eine Möglichkeit, es zu mildern.

Für reale Projekte ist es wichtig, eine umfassende Datenbereinigung zu implementieren. In diesem Beispiel werden die Zeichen "<" und ">" durch ihre HTML-Entitäten &lt; und &gt; ersetzt, um zu verhindern, dass HTML-Elemente im Aufgabentext angezeigt werden.

Die Ersetzungslogik wird in der Funktion sanitizeText() implementiert:

function sanitizeText(text){
    // zum Testen von XSS auskommentieren
    // return text
 
    // XSS verhindern, indem HTML-Elemente deaktiviert werden
    return text.split("<").join("&lt;").split(">").join("&gt;");
}

Diese Funktion wird in Ereignishandlern wie onLightboxSave für die Lightbox und onBeforeSave für Inline-Editoren verwendet.

Das Beispiel enthält auch benutzerdefinierte Inline-Editoren und Lightbox-Abschnitte zum Hinzufügen von Textnotizen. Die Bereinigung wird in den Funktionen dieser benutzerdefinierten Objekte angewendet, bevor Werte gerendert oder Änderungen aus DOM-Elementen abgerufen werden:

// für einen Inline-Editor:
set_value: function(value, id, column, node){
    node.firstChild.value = sanitizeText(value || "");
},
get_value: function(id, column, node){
    return sanitizeText(node.firstChild.value);
},
 
// für die Lightbox:
set_value: function(node, value, task){
    node.value = sanitizeText(value || "");
},
get_value: function(node, task){
    return sanitizeText(node.value);
},

Alternativ können Sie die Textnotizbereinigung mit onLightboxSave und onBeforeSave Ereignishandlern bearbeiten:

protectedGantt.attachEvent("onLightboxSave", function(id, task, is_new){
    if (task.notes) {
        task.notes = sanitizeText(task.notes);
    }
    return true;
});
 
protectedGantt.ext.inlineEditors.attachEvent("onBeforeSave", function(state){
    if (state.columnName == "notes") {
        state.newValue = sanitizeText(state.newValue);
    }
    return true;
});

Ressourcenzuweisungen in der Lightbox erfordern ebenfalls Aufmerksamkeit. Da Gantt Zeichenfolgenwerte zulässt, ist die Bereinigung entscheidend, um XSS-Angriffe zu verhindern. Die Funktion sanitizeResourceValues() iteriert durch Ressourcenzuweisungen und wendet sanitizeText() an:

function sanitizeResourceValues(task){
    const resources = task[protectedGantt.config.resource_property];
    if (resources && resources.length) {
        resources.forEach(function (resource) {
            if (typeof resource.value == "string") {
                resource.value = sanitizeText(resource.value);
            }
        })
    }
}

Diese Funktion ist an den Ereignishandler onLightboxSave gebunden:

protectedGantt.attachEvent("onLightboxSave", function(id, task, is_new) {
    sanitizeResourceValues(task)
    return true;
});

Vergessen Sie nicht, alle zusätzlichen Zeichenfolgenparameter in Ihrer Gantt-Konfiguration zu bereinigen.

Im Beispiel werden nur numerische Werte für Ressourcenzuweisungen in der Ressourcenzeitleiste akzeptiert. Andere Typen speichern keine Änderungen.

Verwendung von Drittanbieter-Tools zur Dateneingabe

Gantt ermöglicht Anpassungen, einschließlich der Aufgabenbearbeitung mit Formularen, Tools oder Bibliotheken von Drittanbietern. Diese Szenarien basieren häufig auf der Gantt-API. Da Anpassungen variieren, gibt es keine einheitliche Lösung für die Datenbereinigung.

Im Beispiel wird ein benutzerdefiniertes Formular verwendet, um Aufgabennamen zu bearbeiten. Die Funktion sanitizeText() wird einbezogen, um das Escaping von Text zu behandeln:

document.body.querySelector("[name='save']").onclick = function(){
    const newTaskName = document.body.querySelector("[name='text']").value;
    task.text = sanitizeText(newTaskName);
    protectedGantt.updateTask(task.id);
}

Durch die Bereinigung von Daten bei der Eingabe in Gantt werden potenzielle XSS-Angriffe neutralisiert, sodass sie nicht den Server erreichen.

Anzeige von Daten in Gantt

Ein weiterer Bereich, den es zu beachten gilt, ist die Anzeige von Daten im Gantt-Diagramm. Obwohl dies nicht so kritisch ist wie die Dateneingabe, kann die Bereinigung angezeigter Daten XSS-Angriffsserien unterbrechen. Wenn beispielsweise der Server kompromittiert wird, Gantt jedoch unzugänglich bleibt, kann die Bereinigung den Angriff blockieren.

Der sicherste Ansatz besteht darin, alle Bereiche zu bereinigen, in denen Daten angezeigt werden. Dies umfasst die Verwendung von Vorlagen in Grid-Spaltenkonfigurationen und aller verfügbaren Vorlagen, um die Anzeige von bösartigem Inhalt zu verhindern.

Eine einfachere Alternative besteht darin, den Datenfluss in Gantt zu begrenzen. Dies stellt sicher, dass kein bösartiger Code den Inhalt beeinflussen kann. Beispielsweise können Aufgabenparameter beim Laden von Daten vom Server mithilfe des Ereignishandlers onTaskLoading bereinigt werden:

protectedGantt.attachEvent("onTaskLoading", function (task) {
    task.text = sanitizeText(task.text);
    if (task.notes) {
        task.notes = sanitizeText(task.notes);
    }
    sanitizeResourceValues(task);
    return true;
});

Wenn Aufgaben einzeln geladen oder in Gantt aktualisiert werden, sollten sie bereinigt werden, bevor sie hinzugefügt oder aktualisiert werden:

let newTask = await loadFromServer(23);
sanitizeTaskProperties(newTask);
gantt.addTask(newTask);

Während Benutzer Gantt-DOM-Elemente mit Browser-Inspektoren manipulieren können, bleiben solche Änderungen nicht bestehen und gehen bei einer Neudarstellung oder Serveraktualisierungen verloren.

Serverseitige Überlegungen

Beachten Sie, dass die clientseitige Validierung nicht narrensicher ist und umgangen werden kann. Sie bietet Benutzern sofortiges Feedback bei fehlerhaften Eingaben, aber die endgültige Validierung muss immer auf dem Server erfolgen.

SQL-Injection

Da dhtmlxGantt vollständig clientseitig ist, liegt die Verhinderung von SQL-Injection in der Verantwortung des Backends.

Wichtige Punkte:

  • Die Lightbox bietet keine Standardvalidierung, sodass Benutzer beliebige Werte eingeben können, wenn sie nicht behandelt werden.
  • Die Backend-API kann mit PUT/POST-Anfragen mit schädlichen Werten angegriffen werden.

Wenn Sie dhtmlxConnector und eine Tabellenkonfiguration wie in der Dokumentation beschrieben verwenden, werden Werte automatisch escapt. Andernfalls befolgen Sie bewährte Verfahren für sichere CRUD-Implementierungen basierend auf Ihrer Plattform. Die How to Start Guides bieten sichere Beispiele zur Vermeidung von SQL-Injection.

CSRF-Angriffe

Für das Hinzufügen benutzerdefinierter Autorisierungstoken oder Header zu Backend-Anfragen von Gantt lesen Sie diesen Artikel.

Content Security Policy

Um Ihre dhtmlxGantt-Anwendung mit dem CSP (Content Security Policy)-Standard in Einklang zu bringen, bietet die Bibliothek eine spezielle Konfigurationsoption. Dies hilft, Code-Injektionsangriffe zu verhindern und die Sicherheit Ihrer Anwendung zu stärken.

Erfahren Sie mehr über die Anwendung von CSP-Standards auf dhtmlxGantt-Anwendungen.

Zurück nach oben