~/blog/woocommerce-store-api-exposurePOSTED
von Shady Nathan Tawfik · 19. September 2026 · 4 min

Ihr Onlineshop exponiert eine öffentliche API, die Sie nicht geschrieben haben

Eine Lifestyle- und Commerce-Seite auf einer aktuellen Content-Plattform mit angehängtem Shop. Siebzehn Befunde, und die Shop-Schnittstelle war diejenige, die niemand auditierte, weil sie wie ein Feature aussah.

Interaktiv[blog-2.0]

TL;DR: Ein Shop installiert eine zweite Anwendung mit eigener öffentlicher Lese-Schnittstelle. Ich fand Super-Admin-Flags in der Benutzerliste, Warenkorbkennungen ohne Sitzung lesbar und einen Skript-Loader, der Integritätsattribute entfernt.

Ausgangslage

Ich habe das Ziel als Black-Box geprüft: keine Zugangsdaten, nur die öffentlich sichtbare Fläche. Das ist, was ich sah, bevor ich etwas angefasst habe.

Eine Medien- und Lifestyle-Plattform mit monetisiertem Katalog, Veranstaltungskalender, mehreren Formularen und externer Shop-Integration, auf einer aktuellen Content-Plattform mit vollständigem Commerce-Plugin. Geprüft wurden die Content-Oberfläche, die Shop-Schnittstelle, E-Mail-Authentifizierung, Header-Policy, Drittanbieter-Skripte und Benutzer-Enumeration.

Ich habe alle identifizierenden Informationen entfernt. Das Ziel wird ausschließlich nach Branche und Technologieklasse beschrieben, damit das Muster übertragbar bleibt.

Das Muster

Das Muster, das ich erkannt habe — und das ich in ähnlichen Landschaften immer wieder finde:

Ein Shop auf einer Content-Seite installiert eine zweite Anwendung. Sie hat eine eigene Lese-Schnittstelle, ein eigenes Datenmodell, eigene Sitzungsverwaltung und eine eigene Vorstellung davon, wer ein Kunde ist, und sie kommt von einem Plugin, dessen Aufgabe der Vertrieb ist, nicht das Audit.

Dieses Design ist für Katalogdaten vertretbar und für alles daneben nicht. Die Lese-Schnittstelle exponiert Produkte, Lagerstatus, Preise und je nach Konfiguration die Kennungen, die Warenkorb, Kunde, Bestellung und Adresse verbinden. Sie antwortet, bevor das Plugin prüft, ob der Aufrufer das sehen darf.

Das zweite strukturelle Thema ist der Optimierer. Performance-Plugins verzögern Skript-Laden und entfernen dabei die Integritätsattribute. Der Trade-off zwischen Caching und Verifikation ist echt und in einem Plugin-Inventar unsichtbar.

TL;DR: Eine Lifestyle- und Commerce-Seite auf einer aktuellen Content-Plattform mit angehängtem Shop. Siebzehn Befunde, und die Shop-Schnittstelle war diejenige, die niemand auditierte, weil sie wie ein Feature aussah.

Befunde

SchweregradBefundNachweis
HOCHSuper-Admin-Konten in der öffentlichen Benutzerliste identifiziertLese-Schnittstelle markiert Administrationskonten
HOCHShop-Lese-Schnittstelle exponiert Katalog- und WarenkorbkennungenProdukt-, Lager- und Warenkorbkeys ohne Sitzung lesbar
HOCHKeine Sicherheits-Header, auch nicht auf Warenkorb- und BezahlpfadenSchutz auf den wertvollsten Routen fehlt
MITTELSubresource Integrity vom Skript-Verzögerer entferntIntegrität konfiguriert und gleichzeitig entfernt
MITTELRemote-Procedure-Call-Endpunkt auf dem Origin offenLogin-Amplifikation und interne Portscans möglich
MITTELExterne Skripte ohne Integrität geladenSechs Drittanbieter-Origins ohne Verifikation

Der Angriffspfad

Content platformCommerce plugin installedStore read interfaceCatalogue, stock and cart keysNo authorisation on the read pathPerformance pluginStrips integrity attributesThird-party scripts unverifiable

Reproduktion im Labor

Jeder Befehl unten zielt auf einen Lab-Container, den ich selbst kontrolliere. Nichts davon ist auf ein laufendes System gerichtet.

Die Shop-Schnittstelle der eigenen Instanz unauthentifiziert lesen

~/code/bash bash
# Ziel: Ihr eigener Shop auf localhost
# 1. antwortet die Lese-Schnittstelle ohne Sitzung
$ curl -s 'http://localhost:8080/wp-json/wc/store/products?per_page=2' | python3 -m json.tool | head -40

# 2. was exponiert die öffentliche Benutzerliste über Rollen
$ curl -s 'http://localhost:8080/wp-json/wp/v2/users' \
  | python3 -c 'import json,sys
for u in json.load(sys.stdin):
    print(u["id"], u["slug"], u.get("meta", {}))'

# 3. sind die Header auf den wertvollsten Routen vorhanden
$ for p in / /cart/ /checkout/ /product/; do
    printf '%-12s %s\n' "$p" \
      "$(curl -sI "http://localhost:8080$p" | grep -ciE 'content-security-policy|x-frame-options|x-content-type-options')/4"
done

Erkennung in eigener Infrastruktur

Prüfen, ob Ihr eigener Loader Integritätsattribute entfernt

~/code/bash bash
$ for f in $(curl -s https://example.org/ | grep -oE '/assets/[A-Za-z0-9._-]+\.js' | sort -u); do
    curl -s "https://example.org$f"
  done > /tmp/bundle.txt

# ein Loader, der die Verifikation entfernt, sieht so aus
$ grep -oE 'removeAttribute\("integrity"\)|removeAttribute\(\x27integrity\x27\)' /tmp/bundle.txt | head
$ grep -c 'integrity' /tmp/bundle.txt

# und wie viele externe Skripte im ausgelieferten HTML kein Attribut haben
$ curl -s https://example.org/ | grep -oE '<script[^>]*src="https?://[^"]*"[^>]*>' \
  | grep -vc integrity

Behebung

Die wertvollsten Routen explizit schützen

~/code/nginx nginx
# Warenkorb und Bezahl brauchen ihre eigene Regel, nicht den Website-Standard
location ~* ^/(cart|checkout|my-account)/ {
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "DENY" always;
    add_header Referrer-Policy "no-referrer" always;
    add_header Content-Security-Policy "default-src 'self'; frame-ancestors 'none'; script-src 'self' https://cdn.example.com; object-src 'none'" always;
    proxy_pass http://backend;
}

Wenn Sie verzögertes Laden brauchen, lassen Sie es nicht die Verifikation entfernen

~/code/ts ts
// die korrekte Lösung: Attribut behalten und ehrlich deferen
// Build-Zeit-Integrität, pro Release gehasht
import { createHash } from 'node:crypto';
import { readFileSync } from 'node:fs';

const SRI_ALGO = 'sha384';
export function sriFor(file) {
  const hash = createHash(SRI_ALGO).update(readFileSync(file)).digest('base64');
  return `${SRI_ALGO}-${hash}`;
}

// Integrität zur Laufzeit nie entfernen: wer die Antwort kontrolliert,
// kann auch den Loader umschreiben, der verifizieren sollte
document.querySelectorAll('script[defer-src]').forEach((el) => {
  el.setAttribute('src', el.getAttribute('defer-src'));
  el.removeAttribute('defer-src');
});

Sobald ein Angreifer Zugriff hat, kann er folgende Aktionen durchführen:

Super-Admin-Konten in der öffentlichen Benutzerliste identifiziert
Shop-Lese-Schnittstelle exponiert Katalog- und Warenkorbkennungen
Keine Sicherheits-Header, auch nicht auf Warenkorb- und Bezahlpfaden
Subresource Integrity vom Skript-Verzögerer entfernt
Remote-Procedure-Call-Endpunkt auf dem Origin offen
Externe Skripte ohne Integrität geladen

Fazit — was ich daraus mitnehme

  • Ein Shop installiert eine zweite Anwendung. Auditieren Sie sie als eine.
  • Eine Shop-Lese-Schnittstelle ist per Design öffentlich; prüfen Sie, was sie sonst noch exponiert.
  • Ein Performance-Plugin kann Integrität strukturell unmöglich machen. Tauschen Sie den Loader.
  • Schützen Sie Warenkorb und Bezahl explizit; der Website-Standard reicht nicht.

Nur zu Bildungszwecken. Alle reproduzierbaren Befehle zielen auf meine eigene Lab-Umgebung (localhost), nie auf ein laufendes System. © 2026