Skip to content

How-to: Bewertungs- und Rezensions-API

FT-Referenz: FT333 (NENE2-FT/ratinglog) — Pro-Artikel-, Pro-Benutzer-Bewertungssystem mit Score-Validierung (1–5), Upsert-Semantik, Zusammenfassung mit Verteilungsübersicht und Schwachstellenbewertung, 16 Tests / 40+ Assertions bestanden.

Dieses Handbuch zeigt, wie man ein Bewertungssystem aufbaut, bei dem Benutzer numerische Scores mit optionalen Textrezensionen einreichen, und die API live aggregierte Zusammenfassungen berechnet.

Schema

sql
CREATE TABLE ratings (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    item_id    TEXT    NOT NULL,
    rater_id   TEXT    NOT NULL,
    score      INTEGER NOT NULL CHECK (score BETWEEN 1 AND 5),
    review     TEXT    NOT NULL DEFAULT '',
    created_at TEXT    NOT NULL,
    updated_at TEXT    NOT NULL,
    UNIQUE(item_id, rater_id)
);

UNIQUE(item_id, rater_id) erzwingt eine Bewertung pro Bewerter pro Artikel. item_id und rater_id sind opake Zeichenkettenidentifikatoren — keine Fremdschlüsselbeschränkung erforderlich.

Endpunkte

MethodePfadBeschreibung
PUT/items/{itemId}/ratings/{raterId}Bewertung erstellen oder aktualisieren (Upsert)
GET/items/{itemId}/ratingsAlle Bewertungen für Artikel auflisten
GET/items/{itemId}/ratings/summaryAggregierte Zusammenfassung mit Verteilung
GET/items/{itemId}/ratings/{raterId}Bewertung eines Bewerters abrufen
DELETE/items/{itemId}/ratings/{raterId}Bewertung löschen

Bewertung erstellen / aktualisieren (Upsert)

php
PUT /items/product-1/ratings/alice
{"score": 5, "review": "Ausgezeichnet!"}
 200  {"rater_id": "alice", "score": 5, "review": "Ausgezeichnet!", ...}

// Vorhandene Bewertung aktualisieren
PUT /items/product-1/ratings/alice
{"score": 3, "review": "Ich habe meine Meinung geändert."}
 200  {"score": 3}

PUT mit UNIQUE(item_id, rater_id) wirkt als natürlicher Upsert (INSERT OR REPLACE). Derselbe Endpunkt verarbeitet sowohl Erstellung als auch Aktualisierung ohne separates PATCH.

Validierung

php
// Fehlender Score
PUT /items/product-1/ratings/alice  {"review": "Gut"}
 422

// Außerhalb des Bereichs
PUT /items/product-1/ratings/alice  {"score": 6}
 422

PUT /items/product-1/ratings/alice  {"score": 0}
 422

Score muss ein Integer in [1, 5] sein. review ist optional (Standard: "").

Bewertungen auflisten

php
GET /items/product-1/ratings
 200
{
  "ratings": [
    {"rater_id": "alice", "score": 5, "review": "Ausgezeichnet!"},
    {"rater_id": "bob",   "score": 3, "review": ""}
  ]
}

Bewertungen werden auf den Artikel beschränkt — Bewertungen von product-2 erscheinen nie in der Liste von product-1.

Zusammenfassung mit Verteilung

php
GET /items/product-1/ratings/summary
 200
{
  "count": 3,
  "average": 4.0,
  "distribution": {
    "1": 0, "2": 0, "3": 1, "4": 1, "5": 1
  }
}

// Noch keine Bewertungen
GET /items/product-2/ratings/summary
 200  {"count": 0, "average": 0.0, "distribution": {"1":0,"2":0,"3":0,"4":0,"5":0}}

distribution gibt immer alle fünf Schlüssel zurück, auch wenn Zählungen null sind — Clients können Stern-Balken ohne Null-Prüfungen rendern.

Einzelne Bewertung abrufen

php
GET /items/product-1/ratings/alice
 200  {"score": 4, "review": "..."}

GET /items/product-1/ratings/nobody
 404

Bewertung löschen

php
DELETE /items/product-1/ratings/alice
 200  {"deleted": true}

DELETE /items/product-1/ratings/nobody
 404

Nach dem Löschen wird die Zusammenfassung bei der nächsten Anfrage sofort neu berechnet.


Schwachstellenbewertung

V-01 — Bewertungsimitation (IDOR auf raterId) ⚠️ EXPONIERT

Risiko: Jeder Client kann eine Bewertung mit einem beliebigen raterId-Pfadsegment einreichen oder löschen. Befund: EXPONIERT — raterId in der URL wird nicht gegen einen authentifizierten Akteur validiert.


V-02 — Score-Bereichsumgehung 🛡️ SICHER

Risiko: Angreifer sendet score: 0 oder score: 6, um ungültige Daten zu erzeugen. Befund: SICHER — Score wird auf [1, 5] validiert, bevor in die DB geschrieben wird.


V-03 — Durchschnittsvergiftung via Massen-Fake-Bewertungen ⚠️ EXPONIERT

Risiko: Angreifer registriert Tausende von Benutzer-IDs und sendet 1-Stern-Bewertungen. Befund: EXPONIERT — keine Ratenbegrenzung oder Kontoverifizierung beim Bewertungsendpunkt.


V-04 — XSS via Rezensionstext ✅ SICHER

Risiko: Angreifer speichert <script>alert(1)</script> in review. Befund: SICHER — die API gibt application/json zurück. JSON-Kodierung maskiert HTML-Sonderzeichen.


V-05 — SQL-Injection via itemId / raterId 🛡️ SICHER

Risiko: Angreifer sendet item_id = "x' OR '1'='1". Befund: SICHER — alle Abfragen verwenden parametrisierte Anweisungen (?-Platzhalter).


V-06 — Unbegrenzter Rezensionstext (Speichermissbrauch) ⚠️ EXPONIERT

Risiko: Angreifer sendet eine 100 MB Rezensionszeichenkette. Befund: EXPONIERT — keine max_length-Prüfung für review.


V-07 — Durchschnitt Integer-Trunkierung 🛡️ SICHER

Risiko: Durchschnittsberechnung könnte Präzision verlieren. Befund: SICHER — AVG() in SQLite gibt einen Float zurück.


V-08 — Fehlende Verteilungsschlüssel (Client-Absturz) 🛡️ SICHER

Risiko: Wenn distribution Schlüssel für Scores mit null Bewertungen weglässt, stürzen Clients ab. Befund: SICHER — die API gibt immer alle fünf Schlüssel (15) zurück, mit 0 initialisiert.


V-09 — Artikelübergreifendes Datenleck 🛡️ SICHER

Risiko: GET /items/product-1/ratings gibt Bewertungen von product-2 zurück. Befund: SICHER — alle Abfragen enthalten WHERE item_id = ?.


V-10 — Gleitkomma-Score zur Umgehung der Integer-Validierung 🛡️ SICHER

Risiko: Angreifer sendet score: 4.9, um die Bereichsprüfung zu umgehen. Befund: SICHER — Score wird als strikter Integer validiert.


VULN-Zusammenfassung

IDSchwachstelleBefund
V-01Bewertungsimitation (IDOR auf raterId)⚠️ EXPONIERT
V-02Score-Bereichsumgehung🛡️ SICHER
V-03Durchschnittsvergiftung via Massen-Fake-Bewertungen⚠️ EXPONIERT
V-04XSS via Rezensionstext✅ SICHER
V-05SQL-Injection via itemId / raterId🛡️ SICHER
V-06Unbegrenzter Rezensionstext (Speichermissbrauch)⚠️ EXPONIERT
V-07Durchschnitt Integer-Trunkierung🛡️ SICHER
V-08Fehlende Verteilungsschlüssel🛡️ SICHER
V-09Artikelübergreifendes Datenleck🛡️ SICHER
V-10Gleitkomma-Score zur Umgehung der Integer-Validierung🛡️ SICHER

7 SICHER, 3 EXPONIERT — Kritisch: raterId authentifizieren; review-Längenbegrenzung hinzufügen; Ratenbegrenzung gegen Massen-Fake-Bewertungen anwenden.


Was man NICHT tun sollte

Anti-PatternRisiko
raterId aus dem Pfad ohne Authentifizierung vertrauenJeder Client kann als beliebiger Benutzer bewerten oder löschen
Kein max_length für RezensionstextSpeicherbombe — eine einzige Anfrage schreibt Gigabytes in die DB
null für Verteilungsschlüssel mit null Zählung zurückgebenClient-Code, der auf distribution[2] zugreift, stürzt ab
Durchschnitt in PHP mit array_sum neu berechnenVerlustbehaftete Float-Arithmetik bei großen Datensätzen; DB AVG() verwenden
Kein Per-Benutzer-RatenlimitMassen-Fake-Konten vergiften Produktdurchschnitte
SELECT * FROM ratings ohne WHERE item_id verwendenArtikelübergreifendes Datenleck

Veröffentlicht unter der MIT-Lizenz.