JavaScript Security – Best Practice

JavaScript ist mittlerweile überall. Neben dem Großteil der Web- und Mobile-Apps werden inzwischen auch Server-Applikationen und selbst Anwendungen in der Automotive-Industrie damit programmiert. Auch Java-Entwickler kommen somit immer öfter mit JavaScript in Kontakt. Mit der Zahl kritischer Anwendungsgebiete steigt aber auch das Schadenpotenzial. Schwachstellen wie XSS, CSRF und SQL-Injections sind hinlänglich bekannt. Doch in vielen Umgebungen mangelt es bislang an der Awareness für das Thema Sicherheit. Dieser Artikel erklärt, wie man die Weichen für eine sichere Entwicklung mit JavaScript stellt.

 

Schritt 1: Validierung des Inputs

In der Web-Application-Security stellt der User-Input mit den zugehörigen Daten schon immer ein enormes Sicherheitsrisiko dar. Daher stellen die Validierung und Bereinigung des Inputs einen Eckpfeiler aller Secure-Coding-Frameworks dar. Sie sollten als Server-Funktion für alle Anwendungsebenen integriert und stets auf einem vertrauenswürdigen System (i.d.R. dem Server) vorgenommen werden. Für einen optimalen Schutz werden sämtliche User-Daten und Eingaben zunächst als unsicher klassifiziert und dürfen erst nach einem Security-Check akzeptiert werden. Da moderne Web-Anwendungen Daten aus unterschiedlichsten Quellen beziehen, etwa über User-Interfaces oder per API angebundene Drittanbieterdienste, gilt es zunächst die Vertrauenswürdigkeit der Datenquellen zu bewerten. Als Faustregel sollten alle dabei unbekannte Quellen grundsätzlich als nicht vertrauenswürdig eingestuft werden. Immer wenn Daten von einer vertrauenswürdigen an eine weniger vertrauenswürdige Quelle übergeben werden, muss über Integritätschecks sichergestellt werden, dass diese nicht manipuliert wurden. Und so gehen Sie bei der Validierung vor:

  • Codieren Sie sämtliche Daten bei Erreichen des Validierungs-Servers standardmäßig in einem etablierten, einheitlichem Zeichensatz wie UTF-8.
  • Stellen Sie mittels White-Listing sicher, dass ausschließlich erlaubte Zeichen verwendet werden. Vermeiden Sie soweit wie möglich Regular-Expressions, da diese über DOS-Attacken angreifbar sind. Greifen Sie lieber zu Validierungsmodulen wie js.
  • Validieren Sie die Datenlängen. Auch wenn Overflows unter JavaScript selten sind, können lange Strings zu Sicherheitsproblemen führen.
  • Überprüfen Sie vorhandene Sonderzeichen, sofern dies nicht bereits im Rahmen der Standardvalidierung erfolgt. Achten Sie vor allem auf Null-Bytes (%00), Zeilenumbrüche (%0d %0a  \r  \n) und Dot-Dot-Slash (../ und ..\ ).
  • Prüfen Sie die Zahlen im Code, und zwar sowohl mit Blick auf den Wert (Number Value), den Typ (Number Type) sowie das Objekt (Number Object).
  • Validieren Sie vom User übermittelte Files. Dazu gehört, einen verbindlichen Speicherort zu definieren und die Dateigröße zu begrenzen. Achten Sie darauf, dass von Usern übermittelte Files weder eingebunden noch ausgeführt werden können.

Im Falle von Web-Anwendungen sollten Sie außerdem unbedingt die Request- und Response-Header validieren, um zu gewährleisten, dass sie diese ASCII-Zeichen enthalten. Viele Sicherheitsprobleme wie das HTTP-Response-Splitting sind auf eine unzureichende Validierung und Bereinigung des Contents zurückzuführen. Denken Sie auch daran, dass HTTP-Headers ebenfalls keine vertrauenswürdige Datenquellen darstellen (z. B. Cookies).

Im Anschluss an die Validierung gilt es den Input zu bereinigen (Sanitization). Dabei werden beispielsweise die Zeichen < und > ersetzt, die im HTML-Kontext eine andere Bedeutung haben, sowie Zeilenumbrüche und Leerzeichen entfernt. Außerdem sollten Sie darauf achten, sämtliche URLs zu vereinheitlichen, u.a. ohne ..\. Die gute Nachricht ist, dass sich dieser Arbeitsschritt über Standardpakete wie validator.js weitgehend automatisieren lässt.

 

Schritt 2: Codierung des Outputs

Die Codierung des Outputs wird in vielen Best-Practice-Empfehlungen sehr kurz abgehandelt. Dabei kommt diesem Schritt angesichts der zunehmend komplexer werdenden Web-Anwendungen eine Schlüsselrolle zu. Die Gleichung ist einfach: Je mehr Daten aus unterschiedlichen Quellen an den Web-Browser (oder andere Medien) übergeben werden, desto mehr Ansatzpunkte haben Angreifer, um eine Injection durchzuführen. Dies lässt sich gut am Beispiel des Cross-Site-Scriptings (XSS) verdeutlichen. XSS-Angriffe, bei denen bösartiger JavaScript-Code injiziert und ausgeführt wird, gehören zu den häufigsten Schwachstellen moderner Web-Anwendungen. Dabei unterscheidet man zwei Varianten:

  • Server-XSS: Schädliche Daten werden in die HTML-Response des Servers integriert.
  • Client-XSS: Mithilfe eines unsicheren JavaScript-Calls werden unsichere User-Daten in das DOM injiziert.

Beide Angriffsformen lassen sich zuverlässig unterbinden, indem der Output sorgfältig codiert wird. In modernen JavaScript-Umgebungen steht den Entwicklern dafür eine Reihe von Tools zur Verfügung:

  • Die mit JavaScript 1.5 implementierte Funktion Vanilla-JavaScript ersetzt problematische Sonderzeichen auf dem Server automatisch durch sichere Zeichen und verhindert so, dass mit der HTTP-Response gefährliche Payloads eingespeist werden.
  • Für Node.js sind im Rahmen von npm heute dedizierte Pakete wie xss-filters verfügbar, mit denen sich UTF-8 kodierter Output zuverlässig vor Cross-Site-Scripting server-seitig schützen lässt.
  • Client-seitige JavaScript-Web-Frameworks wie Angular-JS unterstützen heute ebenfalls bei der sicheren Output-Codierung, indem sämtliche in das DOM eingespeisten Werte (template, property, attribute, style, class binding, interpolation) zunächst als unsicher eingestuft und bereinigt werden.
  • Die JavaScript-Softwarebibliothek React hat mit JSX eine neue Syntaxerweiterung für React-Elemente eingeführt. React ist standardmäßig so konfiguriert, dass ausschließlich im Anwendungscode hinterlegte Werte in das DOM übernommen werden können, was Client-XSS zuverlässig verhindert.

Das Beispiel XSS zeigt, wie wichtig eine zuverlässige Codierung des Outputs ist.

 

Schritt 3: Authentisierung und Passwortmanagement

Eine starke Authentisierung und ein robustes Passwortmanagement sind Schlüsselkomponenten jedes Entwicklungsprozesses. Auch hier gilt zunächst, dass die gesamte Authentisierung auf einem vertrauenswürdigen System umgesetzt werden sollte, typischerweise dem Server, auf dem das Backend der Anwendung läuft. Um das System so einfach wie möglich zu halten und die Zahl der Angriffspunkte zu minimieren, hat sich der Einsatz etablierter Authentisierungsdienste bewährt. Seiten und Ressourcen, die eine sichere Authentisierung erfordern, sollten diese niemals selbst bereitstellen. Denken Sie außerdem daran, nicht nur die Anwender, sondern auch Anwendungen sicher zu authentisieren, wenn diese auf externe Systeme zugreifen und sensible Daten verarbeiten. Bei der client-seitigen Implementierung der Authentisierung sollte die Eingabe stets verdeckt erfolgen. Deaktivieren Sie auch die Remember-Me-Funktion und die Autovervollständigung. Beides ist mit JavaScript sehr einfach möglich, indem Sie ein Eingabefeld mit Typ=”password” anlegen und die Autocomplete Attribute deaktivieren.

Übermitteln Sie Zugangsdaten ausschließlich über HTTP POST Requests, und verwenden Sie stets eine verschlüsselte Verbindung (HTTPS). HTTP GET Requests über TLS/SSL (HTTPS) sehen auf den ersten Blick ebenso sicher aus, i.d.R. werden Sie die angeforderte URL aber mitloggen wollen. Achten Sie darauf, bei Anmeldefehlern nicht zu viele Informationen preiszugeben. Mit der Meldung Benutzername/Passwort ungültig können potenzielle Angreifer weniger anfangen als mit dem expliziten Hinweis Passwort muss Sonderzeichen enthalten.

Schützen Sie Authentisierungsdaten mit geeigneten kryptografischen Maßnahmen. Verwenden Sie dabei etablierte Hashing-Algorithmen wie bcrypt, PDKDF2, Argon2 und scrypt. In Node.js sind für all diese Algorithmen robuste Implementierungen verfügbar.

Stellen Sie ausreichende Passwortstärken sicher. Die meisten Anwendungen geben nach wie vor eine Mindestlänge von acht Zeichen vor. Mindestens 16 Zeichen bieten aber deutlich besseren Schutz. Sorgen Sie auch dafür, dass die Anwender ihre Passwörter regelmäßig aktualisieren müssen. Passwörter sollten frühestens nach einem Tag geändert werden können, um zu verhindern, dass Angreifer den Reset missbrauchen. Wenn Sie mit E-Mail-basierten Resets arbeiten, sollte dieser mitgeloggt werden und Anwender nur einen temporären Passwort-Link mit kurzer Laufzeit erhalten. Achten Sie bei Sicherheitsfragen darauf, dass diese möglichst viele gleichwertige Antworten erzielen. So ist etwa die Frage nach dem Lieblingsbuch denkbar ungeeignet, weil überproportional viele Anwender Die Bibel als Antwort wählen werden.

In kritischen Umgebungen sollte stets starke Multi-Faktor-Authentisierung implementiert werden. Node.js unterstützt dafür eine ganze Reihe einfach zu implementierender Pakete. Ein gutes Beispiel ist etwa speakeasy. Integrieren Sie geeignete Monitoring-Tools, um Angriffe auf multiple Accounts schneller zu identifizieren. Auch hier werden Sie bei Node.js fündig. Dort gibt es Pakete, mit denen Sie die Zugriffsraten im Falle eines Brute-Force-Angriffs automatisch senken können. Denken Sie daran, herstellerseitige Default-Passwörter zu ändern und Zugangsdaten nicht mehr aktiver User zu löschen.

 

Schritt 4: Session-Management

Moderne Web-Anwendungen nutzen den nachfolgend illustrierten Session-Flow, um die User-Identität über multiple HTTP-Anfragen hinweg mit zu übergeben. Dies kann unter Sicherheitsaspekten problematisch sein und sollte daher mit gebührender Sorgfalt implementiert werden. An sich ist der Aufbau einer User-Session ganz einfach:

  1. Der Client sendet einen Request.
  2. Der Server generiert einen Identifier und sendet ihn mit Response zurück.
  3. Der Client liest den Identifier.
  4. Der Client sendet eine weitere Requests, diesmal mit dem unveränderten Identifier.
  5. Der Server liest und validiert den Identifier. Der Workflow kehrt zu Schritt 2 zurück.

Der Identifier muss aus Sicherheitsgründen stets auf einem vertrauenswürdigen System (dem Server) angelegt werden. Die Anwendung sollte dementsprechend auch nur Identifier akzeptieren, die von diesem System erstellt wurden. Verwenden Sie für die Generierung ausschließlich etablierte Tools, um sicherzustellen, dass die Identifier auch wirklich zufällig generiert werden. Denken Sie auch daran, dass die Session beim Log-out vollständig terminiert werden muss und achten Sie darauf, dass Sie auf jeder autorisierten Seite einen Log-out ermöglichen.

Kommunizieren Sie Session-Identifier nicht in URLs, Log-Files oder Fehlermeldungen. Ältere Web-Frameworks und -Anwendungen übergeben den Session-Identifier mitunter als GET Parameter (oft als Parameter jsessionid oder PHPSESSID). Dies macht es Angreifern leicht, Identitäten zu übernehmen und ist heute ein klares No-Go.

 

Schritt 5: Access Control

Schützen Sie den Zugang zu folgenden Bereichen durch eine zuverlässige Autorisierung, um unerwünschte Zugriffe zu verhindern:

  • Geschützte Files und andere Ressourcen
  • Geschützte URLs
  • Funktionen direkter Objekte
  • Referenzdienste
  • Anwendungsdaten
  • User- und Daten-Attribute
  • Informationen zur Policy

Dabei müssen Sie zunächst dafür sorgen, dass die Autorisierung der Zugriffe ausschließlich auf der Basis vertrauenswürdiger Objekte erfolgt. Die Autorisierungsvorgaben müssen überdies bei jeder Anfrage durchgesetzt werden – bei serverseitigen Scripts ebenso wie bei client-seitigen Technologien wie AJAX oder Flash. Achten Sie auch darauf, die privilegierten Informationen sorgfältig vom Rest des Anwendungs-Codes zu trennen.

Das Web-Application-Framework von Express für Node.js macht es Entwicklern leicht, bestimmte Zugriffe ausschließlich für autorisierte Anwender zu öffnen. Darüber hinaus ist mit dem Access-Control-Package eine leistungsfähige Suite für die Umsetzung von rollen- und attributbasierter Modelle erhältlich, mit der sich überaus granulare Zugriffe implementieren lassen.

Begrenzen Sie die Höchstzahl von Transaktionen, die Ihre Anwender in einer vorgegebenen Zeitspanne durchführen können, um DoS-Angriffe zu verhindern. Kontrollieren Sie in festen Zeitabständen, ob sich die Privilegien der User geändert haben und passen Sie die Rechte zeitnah an.

 

Schritt 6: Kryptografie

Bei der Entwicklung in JavaScript-Umgebungen kommen zwei unterschiedliche kryptografische Verfahren zum Einsatz: Hashing und Verschlüsselung. Ein Hash ist ein String (oder eine Zahl) fester Länge, der mithilfe einer Hash-Funktion aus Quelldaten generiert wird, wobei sich die Quelldatei nicht mehr wiederherstellen lässt. Damit eignet sich das Verfahren um beispielsweise Dateiidentitäten nach der Validierung sicher zu dokumentieren. Der meist genutzte Hashing-Algorithmus ist MD5. BLAKE2 gilt unter Sicherheitsgesichtspunkten als etwas stärker und flexibler, wird in Node.js aber kaum unterstützt.

Bei der Verschlüsselung werden lesbare Daten mithilfe eines Schlüssels in unlesbare Daten umgewandelt. Im Gegensatz zum Hash lassen sie sich aber wieder entschlüsseln. Verschlüsselung ist damit erste Wahl, wenn sensible Daten oder Kommunikationsströme geschützt werden sollen. Dabei unterscheidet man zwei Verfahren:

  • Symmetrische Verschlüsselung (etwa via AES), die sich einfach und sicher über Tools wie node-forge implementieren lässt.
  • Asymmetrische Verschlüsselung, die eine zuverlässige Authentisierung ermöglicht. Diese lässt sich etwa über das Node.js-Package sodium implementieren.

Achten Sie bei der Implementierung der Kryptografiepakete darauf, geeignete Policies und Verfahren für das Management der Schlüssel zu etablieren und die Master-Secrets vor unerwünschten Zugriffen zu schützen. Achtung: Ihre Keys dürfen niemals im Quellcode hinterlegt sein!

 

Schritt 7: Fehlerbehebung und Logging

Fehlerbehebung und Logging sind für sichere Anwendungen und Infrastrukturen unverzichtbar. Die Fehlerbehebung dient dazu, Fehler in der Anwendungslogik frühzeitig zu identifizieren und zu beheben. Beim Logging geht es darum, Abläufe und Anfragen zu protokollieren und daraus geeignete Schutzmaßnahmen abzuleiten.

  1. Fehlerbehebung
    JavaScript unterstützt einen Error Constructor, der Error-Objekte generiert. Typischerweise geschieht das, wenn es in der Laufzeitumgebung zu einer Ausnahme kommt. Man unterscheidet dabei zwischen Betriebs- und Programmfehlern. Betriebsfehler sind Fehler, die im laufenden Betrieb auftreten. Das bedeutet, dass die Anwendungslogik korrekt ist, aber ein unerwartetes Event auftritt, z.B. ein Input-/Output-Fehler, ein Netzwerkausfall oder ein Speicherproblem. Programmierfehler sind logische Fehler im Anwendungscode. Beispiele sind Zugriffe auf undefinierte Variablen, falsche Typzuweisungen und ähnliches mehr. Node.js kennt drei Arten mit Fehlern umzugehen:
  • Fehlermeldung (Exception).
  • Übergabe des Fehlers an einen callback(), eine dedizierte Funktion für das Handling von Fehlern und asynchronen Betriebsabläufen.
  • Verwendung eines EventEmitters.

Als Entwickler müssen Sie den Unterschied zwischen einem Fehler (Error) und einer Exception kennen. Fehler werden erfasst und können dann an eine andere Funktion übergeben oder angezeigt werden. Sobald ein Fehler angezeigt wird, wird er zur Ausnahme. In einfachem synchronem JavaScript sieht die Syntax einer Exception wie folgt aus: throw new Error (‚Some error.‘);

Die Anzeige solcher Exceptioins ist bei JavaScript oder Node.js aber eher die Ausnahme. Die meisten nativen APIs übergeben Fehlermeldungen an die Callback-Funktion. Die Verwendung von callbacks() ist auf die asynchrone Natur von JavaScript zurückzuführen. Da bei diesem Verfahren aber keine explizite Fehlermeldung erfolgt, birgt es die Gefahr, dass Fehler unentdeckt bleiben und nicht behoben werden können. Das mit ES6 eingeführte Paket Promises hat das Error-Handling in JavaScript-Umgebungen in vielen Bereichen verbessert und hilft insbesondere dabei, Callback-Pyramiden zu vermeiden. Dennoch sollten Entwickler in event-orientierten Programmierumgebungen oder stream-basiertem Code zusätzlich einen dedizierten Error-Handler verwenden.

  1. Logging

Das Logging sollte stets in der Applikation erfolgen. Implementieren Sie dafür eine Master-Routine auf einem vertrauenswürdigen System und stellen Sie sicher, dass die Logs keine sensiblen Daten enthalten. Für JavaScript-Umgebungen ist eine breite Palette guter Logging-Tools verfügbar, darunter das beliebte winston-package (für das mit dem winston-daily-rotate-file-package sogar ein Tool für rotierende Logs bereitsteht) sowie die Pakete log4js, bunya und morgan. Der Entwickler sollte zudem geeignete Tools für die Log-Analyse implementieren, um zu verhindern, dass über das Analyse-Interface nicht vertrauenswürdige Daten als Code ausgeführt werden. Hierfür sind bewährte Open-Source-Tools der ELK-Stack (Elasticsearch, Logstash, Kibana) verfügbar. Um die Integrität der validierten Log-Files dauerhaft sicherzustellen, sollten die Dateien überdies durch Hashing geschützt werden.

 

Schritt 8: Datensicherheit

Die Daten in den Web-Anwendungen müssen zuverlässig geschützt werden. Der erste Schritt ist es dabei, geeignete Rechte und Rollen zu definieren und sicherzustellen, dass jeder User nur auf die Funktionen zugreifen kann, die er auch wirklich benötigt. Anschließend muss für jeden Anwender passende Rollen zugewiesen werden. Achten Sie darauf, sensible Informationen die nicht benötigt werden zeitnah zu löschen. Dies betrifft Daten in temporären Verzeichnissen und Caches, aber auch Kommentare im Quellcode. Vermeiden Sie es, Informationen über das HTTP-GET-Verfahren weiterzugeben. Das macht die Anwendung angreifbar, vor allem wenn die URL unbefristete Session-IDs oder Token enthält. Außerdem könnten Ihre Daten über MITM-Attacken abgefangen werden. Wenn Ihre Web-Anwendung versucht, Informationen über Ihren API-Key auf Drittanbieterseiten abzurufen, könnte dieser nicht nur von Insidern gestohlen werden. Nutzen Sie daher immer HTTPS, übergeben Sie Paramater über POST und verwenden Sie möglichst Einmal-IDs und Einmal-Token. Achten Sie auf eine lückenlose Verschlüsselung kritischer Daten und speichern Sie diese niemals in Klartext auf dem Client. Hierzu gehört auch die Einbettung in unsicheren Formaten wie Adobe-Flash oder in kompiliertem Code. Definieren Sie abgestufte Rechte für den Zugriff auf Code und beschränken Sie die Zugriffsoptionen für den Quellcode. User dürfen niemals in der Lage sein, den server-seitigen Quellcode einzusehen oder herunterzuladen.

 

Schritt 9: Sicherheit der Kommunikation

Als Entwickler müssen Sie jederzeit die Gewissheit haben, dass Ihre Kommunikationskanäle sicher sind. Die betrifft die Kommunikation zwischen Server und Client, zwischen Server und Datenbank sowie die gesamte Backend-Kommunikation. Verschlüsseln Sie diese Kommunikationskanäle, um die Integrität und Vertraulichkeit der Daten zu gewährleisten und einen Man-in-the-Middle-Angriff zu verhindern. Verwenden Sie dafür einfach das tls-module von Node.js. Es hat sich bewährt durchgängig über HTTPS zu kommunizieren, statt immer wieder zwischen HTTP und HTTPS zu wechseln. Für einen optimalen Schutz vor bekannten Attacken wie POODLE und BEAST sollten Sie darüber hinaus SSLv3 und TLSv1 deaktivieren.

 

Schritt 10: Systemkonfiguration

Regelmäßige Updates sind der Schlüssel zu nachhaltiger Sicherheit. Entwickler sollten daher sicherstellen, dass ihre JavaScript-Frameworks, ihre externen Pakete und die Frameworks der Web-Anwendungen durchgehend auf dem neuesten Stand sind. Tools wie die Node-Security-Platform (nsp) helfen, bekannte Sicherheitslücken zu vermeiden und die Pakete Up-to-Date zu halten. Achten Sie darauf, dass die Directory-Listings stets deaktiviert sind, um Angreifern die Suche nach sensiblen Files nicht unnötig zu erleichtern. In den Frameworks Node.js und Express sind diese Listings standardmäßig deaktiviert. Entfernen Sie in der Produktivumgebung alle unnötigen Funktionalitäten des HTTP-Headers. Überprüfen Sie dabei auch den HTTP-Response-Header, und bereinigen Sie sensible Informationen wie die OS-Version, die Webserver-Version, das Framework und die Programmiersprache.

Nutzen Sie das helmet-module, um geeignete sichere HTTP-Header in Ihrer Web-Anwendungen einzurichten. Definieren Sie dabei am besten unterschiedliche http-Header, um die Sicherheit der Web-Anwendung zu verbessern.

 

Schritt 11: Database Security

Bevor Sie eine Datenbank an Ihre JavaScript-Anwendung anbinden, sollten Sie die folgenden Konfigurationsschritte vornehmen:

  • Sichere Installation des Datenbankservers
  • Vergabe eines sicheren Root-Passworts
  • Beschränkung der Root-Zugriffe auf den Local-Host
  • Entfernung aller anonymen User-Accounts
  • Entfernung eventueller Testdatenbanken
  • Entfernung aller unnötigen Komponenten und Herstellerinhalte
  • Installation des minimalen für JavaScript erforderlichen Feature-Sets
  • Deaktivierung eventueller Default-Accounts

Um Ihre Connection-Strings optimal zu schützen, sollten die Anmeldedaten in einer dedizierten Konfigurationsdatei fernab öffentlicher Zugriffe hinterlegt werden. Definieren Sie abgestufte Rechte für jeden Vertrauenslevel: User, Read-Only-User, Gast und Admin. Zugriffe auf die Datenbank sollten stets mit minimalen Rechten erfolgen. Wenn Ihre Web-Anwendung lediglich Daten auslesen soll, sollten Sie zu diesem Zweck einen Read-Only-User anlegen. Passen Sie die Rechte an, wenn sich die Anforderungen ändern. Verwenden Sie ein starkes Passwort. Verwenden Sie das npm-OWASP-Password-Strength-Testpaket, um die Passwortstärke zu validieren. Entfernen Sie alle Default-Admin-Passwörter – diese stellen ein erhebliches Sicherheitsrisiko dar. Arbeiten Sie mit Prepared-Statements und Parameterized-Queries, um SQL-Injections zu verhindern. Stored-Procedures, also vordefinierte Ansichtsoptionen für die verschiedenen Rollen und Rechte, helfen Ihnen durchgängig zu regeln, wer auf welche Informationen zugreifen kann.

 

Schritt 12: File Management

Lediglich authentisierte User sollten Dateien hochladen können. Regeln Sie im Vorfeld außerdem, welche Dateitypen und Dateigrößen zulässig sind und implementieren Sie geeignete Tools für die Validierung der Parameter. Von Usern hochgeladene Files sollten stets auf einem isolierten Content-Server oder in einer Datenbank ohne Rechte zur Ausführung installiert werden. Wenn die User-Uploads auf einem Nix- Server gehostet werden, sollten Sie zusätzliche Security-Mechanismen wie chroot vorsehen. Bei der Verwendung dynamischer Umleitungen dürfen Anwenderdaten nicht übergeben werden. Wenn die Anwendung dies erfordert, müssen zum Schutz der App zusätzliche Vorkehrungen getroffen werden, etwa das Ablehnen von nicht validierten Daten und URLs mit relativer Pfadangabe. Vergeben Sie für den Server nur Leserechte. Scannen Sie hochgeladene Files auf Malware.

 

Fazit

JavaScript hat sich in vielen Bereichen als flexibler und unkomplizierter de facto Standard etabliert. Allerdings bietet JavaScript eine Vielzahl von Angriffspunkten mit enormem Schadenspotenzial. Unternehmen sind daher gut beraten, sich bei der Entwicklung an etablierte Secure-Coding-Practices zu halten und für eine optimale Softwarequalität gegebenenfalls eine leistungsfähige Softwareanalyseplattform zu implementieren.

 

Tom Zahov Zaubermann ist seit Mai 2019 bei Checkmarx und zeichnet in seiner aktuellen Position als Sales Engineer für die DACH-Region verantwortlich. Er ist spezialisiert auf die Bereiche Application Security und Software Exposure. Er verfügt über langjährige Erfahrung in der IT-Security-Beratung von Unternehmen und Regierungsstellen in Europa, Afrika, Vietnam und Singapur. Sein besonderes Interesse gilt außerdem dem sich schnell entwickelnden eAuto-Sektor und den damit verbundenen Sicherheitsrisiken. Nach seiner Ausbildung in Israel war Tom Zahov Zaubermann für mehrere führende IT-Security-Unternehmen wie CYMOTIVE Technologies und CIPHRON in Deutschland tätig.

Redaktion


Leave a Reply