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.
Befunde
| Schweregrad | Befund | Nachweis |
|---|---|---|
| HOCH | Super-Admin-Konten in der öffentlichen Benutzerliste identifiziert | Lese-Schnittstelle markiert Administrationskonten |
| HOCH | Shop-Lese-Schnittstelle exponiert Katalog- und Warenkorbkennungen | Produkt-, Lager- und Warenkorbkeys ohne Sitzung lesbar |
| HOCH | Keine Sicherheits-Header, auch nicht auf Warenkorb- und Bezahlpfaden | Schutz auf den wertvollsten Routen fehlt |
| MITTEL | Subresource Integrity vom Skript-Verzögerer entfernt | Integrität konfiguriert und gleichzeitig entfernt |
| MITTEL | Remote-Procedure-Call-Endpunkt auf dem Origin offen | Login-Amplifikation und interne Portscans möglich |
| MITTEL | Externe Skripte ohne Integrität geladen | Sechs Drittanbieter-Origins ohne Verifikation |
Der Angriffspfad
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
# 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
$ 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
# 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
// 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:
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.