# Screenshot-Schwärzer & EXIF-Wäsche – Sensible Bildbereiche unumkehrbar entfernen und Metadaten löschen

> **Autor:** Lukas Kopischke (Lead Software-Engineer, Düsseldorf)
> **Kanonische URL:** https://lukiluki.me/garden/image-redactor
> **Markdown-Endpunkt:** https://lukiluki.me/garden/image-redactor.md
> **Kategorie:** Web Standards & a11y | **Tags:** Canvas-2D, EXIF-Binäranalyse, WebP, Datenschutz, Offline-PWA
> **Veröffentlicht:** 2026-10-27 | **Aktualisiert:** 2026-10-27
> **Zusammenfassung:** Screenshots lokal im Browser schwärzen und bereinigen: Versteckte EXIF- und GPS-Metadaten prüfen, Pixel unumkehrbar überschreiben und als WebP exportieren.

---
Du hängst einen Screenshot aus dem Kundenportal an ein öffentliches GitHub-Issue oder ein Support-Ticket an und ziehst schnell einen Verpixelungs-Filter über deine IBAN oder einen geheimen API-Schlüssel. Oder du teilst ein Smartphone-Foto aus deinem Heimnetzwerk-Schrank, ohne zu ahnen, dass im Datei-Header deine exakte Wohnadresse als GPS-Koordinate samt Seriennummer des Geräts gespeichert ist.

Sicheres Schwärzen überschreibt die betroffenen Bildpunkte in einem frischen `HTMLCanvasElement` komplett durch einfarbige Farbwerte oder Zufallsrauschen und kodiert das Gesamtbild anschließend neu. Durch dieses Re-Encoding fallen sämtliche Container-Metadaten wie JPEG-EXIF-Blöcke oder PNG-Textsegmente restlos weg. Diese Methode schützt Rasterbilder (`PNG`, `JPEG`, `WebP`); für Vektor-PDFs mit markierbarem Text muss die Seite vorab in ein reines Pixelbild umgewandelt werden.

> **Merksatz:**
> Verpixeln und Weichzeichnen verschleiern Text nur optisch, vernichten die Information aber nicht mathematisch. Wirklich gelöscht sind sensible Bilddaten erst, wenn ihre Pixel vollständig überschrieben und alle Datei-Header beim Neu-Kodieren verworfen werden.

## Warum lassen sich verpixelte Passwörter und Kontonummern oft wiederherstellen?

Ein klassischer Mosaik-Filter fasst jeweils einen Block von beispielsweise `10 × 10` Bildpunkten zusammen und ersetzt ihn durch den **arithmetischen Helligkeitsmittelwert** dieser 100 Pixel. Bei Gesichtern reicht das oft aus – bei kurzem Text in bekannten Systemschriften (`Segoe UI`, `San Francisco`, `Inter`, `Consolas`) ist dieses Verfahren jedoch mathematisch angreifbar.

Beim Angriff durch Depixelization (Vorlagen-Abgleich) (Rekonstruktionsverfahren, das mögliche Zeichenketten in derselben Schriftart und Rasterposition probeweise verpixelt und den Treffer mit minimaler Abweichung zum Zielbild ermittelt.) rendert ein Angreifer Kandidaten-Zeichen im exakt gleichen Blockraster und vergleicht die entstehenden Graustufenmuster. Weil Ziffern wie `1`, `4` und `8` sehr unterschiedliche Schwarzanteile und Kantenpositionen besitzen, lässt sich eine verpixelte IBAN oder ein API-Token oft Zeichen für Zeichen rekonstruieren.

Selbst ein pechschwarzer Balken verrät noch ein letztes Detail, wenn er millimetergenau am ersten und letzten Buchstaben einrastet: Über eine Glyph-Breiten-Analyse (Seitenkanal-Angriff auf proportionale Schriften, bei dem aus der exakten Pixelbreite eines Schwärzungsbalkens berechnet wird, welche Namen aus einer Kandidatenliste überhaupt hineinpassen.) schließt man Namen aus, die zu breit oder zu schmal für die Lücke sind. Ein leichter zufälliger Überstand (`±3 bis 6 Pixel`) links und rechts unterbindet auch diesen Rückschluss.

### Wie Datei-Metadaten im Binärstrom stecken und beim Canvas-Export verschwinden

Kameras und Betriebssysteme legen Zusatzinformationen außerhalb der eigentlichen Bildpunkte in speziellen Container-Abschnitten ab:

* **JPEG (`0xFF 0xD8`):** Direkt hinter der Startkennung liegen APP1-Segmente (0xFFE1) (Anwendungs-Datenblock im JPEG-Binärstrom, der EXIF-Kameradaten (inkl. GPS-Breiten-/Längengraden und Vorschaubild!) sowie Adobe-XMP-Historien speichert.). Besonders tückisch: Manche älteren Bildprogramme schneiden zwar das Hauptbild zu, lassen aber das winzige, unbeschnittene Original-Vorschaubild (`EXIF Thumbnail`) im `APP1`-Block unangetastet!
* **PNG (`89 50 4E 47`):** Speichert Erstellungssoftware, Zeitstempel (`tIME`), Kommentare (`tEXt`, `iTXt`) und seit neueren Standards auch `eXIf`-Blöcke als eigenständige Chunks.

Zeichnest du ein geladenes Bild per `ctx.drawImage()` auf ein neues `<canvas>`-Element, überträgt der Browser ausschließlich das rohe `RGBA`-Pixelraster und verwirft sämtliche ursprünglichen Datei-Segmente:

```typescript
// Prüft binäre JPEG-APP1-Segmente vorab und erzeugt eine bereinigte WebP-Datei
export function hasJpegExifSegment(fileBytes: Uint8Array): boolean {
  if (fileBytes.length < 4 || fileBytes[0] !== 0xff || fileBytes[1] !== 0xd8) {
    return false;
  }
  let offset = 2;
  while (offset + 4 <= fileBytes.length) {
    if (fileBytes[offset] !== 0xff) break;
    const marker = fileBytes[offset + 1];
    if (marker === 0xda || marker === 0xd9) break; // Bilddaten-Beginn (SOS) erreicht
    const segmentLength = (fileBytes[offset + 2] << 8) | fileBytes[offset + 3];
    if (marker === 0xe1) return true; // APP1 (EXIF / GPS / XMP) gefunden!
    offset += 2 + segmentLength;
  }
  return false;
}

export async function redactAndStripMetadata(
  img: HTMLImageElement,
  boxes: Array<{ x: number; y: number; width: number; height: number }>
): Promise<Blob> {
  const canvas = document.createElement("canvas");
  canvas.width = img.naturalWidth;
  canvas.height = img.naturalHeight;
  const ctx = canvas.getContext("2d");
  if (!ctx) throw new Error("Canvas-2D-Kontext nicht verfügbar");

  ctx.drawImage(img, 0, 0);
  ctx.fillStyle = "#09090b";

  for (const box of boxes) {
    // Überschreibt die Originalpixel im Zielpuffer unwiderruflich
    ctx.fillRect(box.x, box.y, box.width, box.height);
  }

  return new Promise<Blob>((resolve, reject) => {
    canvas.toBlob(
      (blob) => (blob ? resolve(blob) : reject(new Error("WebP-Export fehlgeschlagen"))),
      "image/webp",
      0.86
    );
  });
}
```

## Welches Schwärzungs-Verfahren ist wirklich sicher?

| Methode | Originalpixel gelöscht? | Metadaten & EXIF-Thumbnail weg? | Bewertung & typische Falle |
| :--- | :--- | :--- | :--- |
| **Mosaik-Verpixelung / Gaußscher Weichzeichner** | **Nein** (nur örtlich gemittelt) | Oft nein | **Unsicher für Text & Zahlen:** Über Vorlagen-Abgleich (`Unredacter`) häufig im Klartext lesbar |
| **Halbtransparenter Textmarker-Pinsel (iOS/macOS Markup)** | **Nein** (`Alpha < 100 %`) | Nein | **Hochgradig unsicher:** Wer Kontrast und Tonwertkurve hochzieht, liest den Text darunter sofort mit bloßem Auge |
| **Schwarzes Rechteck in PDF-Kommentar-Werkzeugen** | **Nein** (liegt nur als Ebene darüber) | Nein | **Klassische Datenpanne:** Jeder Empfänger kann den Text unter dem Rechteck mit `Strg+A` → `Strg+C` herauskopieren |
| **Vollblock / Zufallsrauschen + Canvas-Re-Encoding** | **Ja (100 % überschrieben)** | **Ja (0 Header-Segmente)** | **Sicherer Standard für Bilder:** Weder Originalpixel noch EXIF-Vorschaubild oder GPS-Tags überleben den Export |

  #### Empfohlen (Do): Sichere Routine vor dem Teilen
* Immer deckende Vollblöcke (`100 % Deckkraft`) oder Zufallsrauschen wählen und links/rechts einige Pixel großzügiger über den Textrand hinausziehen
    * Auf iOS/Android niemals den *Textmarker-Stift* zum Schwärzen verwenden – selbst nach fünfmaligem Übermalen bleibt ein Restkontrast in den Farbkanälen messbar
    * Für gestochen scharfe Software-Screenshots ohne Kompressionsränder **PNG** oder **WebP** statt stark komprimiertem JPEG wählen
  #### Vermeiden (Don't): Vermeidbare Datenlecks
* Keine ungeschwärzten Ausweise, Verträge oder privaten API-Schlüssel zum Bearbeiten auf fremde Online-Bildportale hochladen
    * Nicht nur den unteren Teil eines Screenshots abschneiden, falls das Werkzeug alte `EXIF`-Vorschaubilder im Datei-Header belässt
    * Keine sensiblen Zugangsdaten nur schwärzen, wenn sie bereits kurz öffentlich sichtbar waren – kompromittierte API-Keys immer zusätzlich im Backend widerrufen

> **Vorsicht bei Browser-Tabs, Fensterleisten und Spiegelungen**
> Prüfe vor dem Absenden nicht nur die eigentliche Tabelle in der Bildmitte: Häufig verraten die **Adresszeile des Browsers** (Kunden-IDs oder Suchparameter in der URL), offene Nachbar-Tabs oder Benachrichtigungs-Banner am oberen Bildschirmrand genau die Information, die unten sorgfältig geschwärzt wurde.

## Prüfpunkte vor dem Veröffentlichen eines geschwärzten Bildes

- [ ] **Deckkraft 100 % sicherstellen:** Nutze ein Werkzeug, das Pixel hart überschreibt und neu kodiert, statt halbtransparenter Zeichenstifte.
- [ ] **Rand-Überstand einplanen:** Ziehe den Balken etwas breiter als das Wort selbst, damit niemand aus der exakten Pixelbreite auf kurze Namen oder Postleitzahlen schließen kann.
- [ ] **Adressleiste & Fenstertitel mitprüfen:** Kontrolliere URL-Parameter, E-Mail-Adressen im Profil-Menü oben rechts und sichtbare Lesezeichenleisten.
- [ ] **Bereinigten Export versenden:** Lade wirklich die neu exportierte `-geschwaerzt`-Datei hoch statt versehentlich die gleichnamige Originaldatei aus dem Download-Ordner zu erwischen.

## Quellen und nächste Schritte

* **Bishop Fox Security Research (Dan Petro)** – *Never Use Text Pixelation To Redact Sensitive Information (`Unredacter` Proof-of-Concept)*: [bishopfox.com/blog/unredacter-tool-never-pixelation](https://bishopfox.com/blog/unredacter-tool-never-pixelation)
* **CIPA DC-008-2023** – *Exchangeable image file format for digital still cameras: Exif Version 3.0*: [www.cipa.jp/std/documents/download_e.html?DC-008-Translation-2023-E](https://www.cipa.jp/std/documents/download_e.html?DC-008-Translation-2023-E)
* **W3C Recommendation** – *Portable Network Graphics (PNG) Specification (Third Edition) — Ancillary Metadata Chunks (`tEXt`, `iTXt`, `eXIf`)*: [www.w3.org/TR/png-3/](https://www.w3.org/TR/png-3/)
* **Weiterführend im Digital Garden:** Willst du ein bereinigtes Bild komplett ohne Cloud oder WLAN an ein isoliertes Zweitgerät übergeben, nutze den optischen Bild-Stream im [QR-Code-Generator & Webcam-Transfer](/garden/qr-code-generator) oder lies in [Offline-KI in Web-Apps](/garden/offline-ai), wie lokale Browser-Werkzeuge dauerhaft ohne Server auskommen.

---
*Quelle: [Lukas Kopischke – Digital Garden](https://lukiluki.me/garden/image-redactor) | Vollständiger Index: [llms.txt](https://lukiluki.me/llms.txt)*
