Modul: Mopedkennzeichen-Bestellung¶
Stand
Code-Analyse vom 2026-04-22 gegen sachpool.de, WebEdition 9.2.3, PHP 8.3.
Zweck¶
Vermittler können über das Portal Versicherungskennzeichen für Kleinkrafträder bestellen (Mopeds, Leichtkraftfahrzeuge, E-Bikes >25 km/h, Krankenfahrstühle, Elektrokleinstfahrzeuge). Das Modul:
- Zeigt verfügbare Kennzeichen-Nummern aus dem Lager
- Nimmt Kundendaten + Fahrzeugdaten entgegen
- Versendet Bestätigungs-Mails (Kunde + Sachpool-Backoffice)
- Reserviert das Kennzeichen im System
Template-Struktur¶
sachpool-portal/kennzeichen/
├── frontend/
│ ├── uebersicht-verfuegbare-kennzeichen.tmpl (224) Liste: verfügbare Kennzeichen
│ ├── kennzeichen-abwicklung.tmpl (225) Bestellformular + Abwicklung
│ └── inc/ Include-Bausteine
├── backend/
│ └── kennzeichen-uebersicht.tmpl (238) Admin-Lagerverwaltung
└── mails/
├── kunden-email.tmpl (247) Bestätigung an Kunde
└── interne-email.tmpl (248) Benachrichtigung an Sachpool
Einstiegspunkte¶
| Doc-ID | Pfad | Template |
|---|---|---|
| 39515 | /_login/service/kennzeichen/bestellen-mopedkennzeichnen.php |
224 + 225 |
| 39516 | /_login/service/kennzeichen/abwicklung.php |
225 |
Datenmodell¶
Tabelle Mopedschilder¶
Alle Kennzeichen aus dem Lager. Aus Queries ableitbare Felder:
| Feld | Typ | Rolle |
|---|---|---|
id |
int PK | Laufende Nummer |
bezeichnung |
varchar(30) | Kennzeichentext (z. B. SHI 450, Upper-Case) |
bestellstatus |
int | 0 frei / 1 reserviert / 2 bezahlt |
kunden_id |
int | FK auf WebEdition-Kunde (User-Makler-ID), 0 = frei |
bestell_id |
int | FK auf Moped_bestellungen.id, 0 = keine Bestellung |
bestell_datum |
datetime | Zeitstempel der Reservierung |
haftpflicht_kasko |
varchar | Deckungstyp (z. B. „Haftpflicht", „Haftpflicht + Teilkasko") |
notiz |
text | Admin-Notiz (Freitext) |
eingepflegt_am |
datetime | Erfassungs-Zeitpunkt |
eingepflegt_von_userid |
int | Backend-User der Erfassung |
Tabelle Moped_bestellungen¶
Kundendaten pro Bestellung. Aus Queries ableitbare Felder:
| Feld | Inhalt |
|---|---|
id, schild_id, besteller_id, makler_kennung, besteller_email |
Referenzen |
anrede, vorname, nachname |
Kunde |
strasse, plz, ort, geburtsdatum |
Kundenadresse |
erstzulassung, fahrzeug_hersteller, hersteller_schluessel_nr, fahrzeug_idz_nr |
Fahrzeugdaten (FIN) |
deckung, beginn, beitrag |
Versicherungsdetails |
moped_art, gewicht, staerke |
Fahrzeugtyp |
bestelldatum |
Zeitstempel |
Frontend-Workflow¶
1. Verfügbare Kennzeichen (uebersicht-verfuegbare-kennzeichen.tmpl, 224)¶
Auswahl Blechschild vs Plakette (Radio-Button, filtert per bezeichnung LIKE '%PLAKETTE%'):
SELECT * FROM Mopedschilder
WHERE bestellstatus=0 AND kunden_id=0
AND bezeichnung LIKE '%PLAKETTE%' -- oder NOT LIKE
Darstellung als tablesorter-Tabelle (Filter nach Versicherer möglich —
„Zum Filtern R+V oder Zurich eingeben"). Jede Zeile hat „Bestellen"-Button,
führt per POST mit kennzeichenid=<id> zum Abwicklungsformular.
2. Bestellabwicklung (kennzeichen-abwicklung.tmpl, 225)¶
~600 Zeilen großes Formular mit:
- Hidden-Felder für WebEdition-FormMail (
crkpfpg=1,sec_eingabe=1) - Deckungs-Radios: Haftpflicht / Haftpflicht + Teilkasko 0 € SB / Haftpflicht + TK 150 € SB
- Beginn (Tag/Monat/Jahr Dropdowns, Jahr
date('Y')bis +4) - Beitrag (Pattern
\d+(,\d{2})?) - 18 Fahrzeugtyp-Radios (Moped/Mokick/Roller 45/50/60 km/h, Microcar, Quad, Krankenfahrstuhl diverse, Leichtmofa, Mofa, Kleinkraftrad, Elektrokleinstfahrzeug)
- Gewicht (kg), Stärke (kW)
- Personendaten (Anrede, Vor-/Nachname, Adresse, Geburtsdatum)
- Fahrer unter/ab 23 (Tarifierung)
- Fahrzeugdaten: Hersteller, HSN (Herstellerschlüsselnummer), FIN (Fahrzeug-Identifikationsnummer), Erstzulassung
- 3 Pflicht-Checkboxen: Elterneinverständnis (<18), Betriebserlaubnis (ABE), VVG-Informationspflichten
Verarbeitung durch WebEdition-FormMail-Engine
Das Template ist kein Verarbeitungs-Endpoint. Die Mail-Versand- und
DB-Update-Logik übernimmt die WebEdition-eigene FormMail-Pipeline (getriggert
durch crkpfpg=1 + sec_eingabe=1). Die eigentliche Speicherung erfolgt
im eingebundenen Template 245 (abwicklung-formulardaten.tmpl).
2a. Speicherung und Reservierung (abwicklung-formulardaten.tmpl, 245)¶
Template 245 wird von 225 eingebunden und übernimmt die eigentliche DB-Mutation nach erfolgreicher Formular-Validierung. Wesentliche Schritte in Reihenfolge:
1. Bestellung in Moped_bestellungen speichern:
$sql_bestellunginsert = "INSERT INTO Moped_bestellungen
(Anrede, Vorname, Nachname, Strasse, Plz, Ort, Geburtsdatum,
Erstzulassung, Fahrzeug_Hersteller, Hersteller_Schluessel_Nr, Fahrzeug_Identfiz_Nr,
Deckung, Beginn, Beitrag, Moped_Art, Gewicht, Staerke, ...)
VALUES ('".$_POST["Anrede"]."','".$_POST["Vorname"]."', ...)";
$wedb->query($sql_bestellunginsert);
$bestell_id = $wedb->insert_id;
→ SQL-Konkatenation aller POST-Werte ohne Escape. Auch die Gesellschaftsauswahl (R+V vs Zurich), die Beitragsberechnung und der Deckungs-Radio-Wert fließen hier roh in das Statement.
2. Reservierung in Mopedschilder:
$sql_kennzeichenupdate = "UPDATE Mopedschilder SET
bestellstatus = 1,
kunden_id = '$sach_userid',
bestell_id = '$bestell_id',
bestell_datum = NOW()
WHERE id = '".$_POST["kennzeichenid"]."'";
3. Mail-Versand — doppelt per <we:sendMail>:
<we:sendMail from="webmail@der-sachpool.de"
recipient="$internalrecipients"
id="40153" <!-- interne-email.tmpl (248) -->
subject="Mopedkennzeichen-Bestellung VM $sach_user" />
<we:sendMail from="webmail@der-sachpool.de"
recipient="$sach_mail"
id="40152" <!-- kunden-email.tmpl (247) -->
subject="Ihre Mopedkennzeichen-Bestellung" />
SQL-Injection am Bestell-Endpoint
Das Template konkateniert ~30 POST-Felder direkt in SQL-Statements. Ein
Angreifer kann über beliebige Form-Felder SQL einschleusen (Stored SQLi,
Datenexfiltration). Priorität kritisch — siehe HANDLUNGSEMPFEHLUNGEN.md.
3. E-Mail-Versand¶
Nach erfolgreichem Submit werden zwei Mails generiert (Templates 247 + 248):
kunden-email.tmplan den Kunden: Bestellbestätigung mit allen Daten + hartkodierte Sachpool-Bankverbindung (IBAN DE15 1203 0000 0011 4155 02 DKB Chemnitz). 14-Tage-Zahlungsfrist, sonst Freigabe.interne-email.tmplan Sachpool-Backoffice: VM-Bestätigungsformel (VVG §7)- alle Daten inkl. VM-Nummer.
Beide Templates geben $_POST-Werte ungeescaped ins HTML aus — siehe
HANDLUNGSEMPFEHLUNGEN.md.
Backend-Lagerverwaltung (kennzeichen-uebersicht.tmpl, 238)¶
Vier Ansichten (Toolbar-Buttons, currentview 1–4):
- Alle (
ORDER BY id DESC) - Sortiert nach Bestelldatum (
ORDER BY bestell_datum DESC) - Reserviert (
bestellstatus=1) - Frei (
bestellstatus=0)
Admin-Operationen:
- Neues Kennzeichen erfassen (
erfassen=1) — INSERT inMopedschilder - Kennzeichen bearbeiten (
bearbeitet=1) — UPDATE Status + Notiz - Kennzeichen löschen (
loeschen=1) — DELETE nach Bestätigung (OK eingeben) - Freigabe (Status → 0) — Zuordnung aufheben (
kunden_id='0', bestell_id='0')
Zusammenhang mit WebEdition-Kundenverwaltung¶
Mopedschilder.kunden_id→ WebEdition-Customer (tblWebUser.id)- Klick auf Kunden-ID im Backend öffnet
we_cmd('we_customer_edit', ...): direkter Sprung ins WebEdition-Kundenmanagement.
Status-Lebenszyklus¶
┌─────┐ Bestellung
│ 0 │ ──────────────────▶ ┌─────┐ Zahlung eingegangen ┌─────┐
│ frei│ │ 1 │ ──────────────────▶ │ 2 │
└─────┘ ◀─────────────── reserviert bezahlt
Freigabe (Admin) └─────┘ └─────┘
Es gibt keinen expliziten Storno- oder Rückabwicklungs-Status.
Bekannte Altlasten¶
→ interne Datei HANDLUNGSEMPFEHLUNGEN.md im Repo-Root
- 🔴 Template 245 SQL-Konkatenation: ~30 POST-Felder direkt in
INSERT/UPDATEohne Escape - 🟡
kunden-email.tmpl+interne-email.tmpl: POST-Werte ungeescaped (HTML-Injection) - 🟡 Bankverbindung hartkodiert in
kunden-email.tmpl - 🟡 Tippfehler-Feldname
Fahrzeug_Identfiz_Nr(stattIdentifiz) - 🟡 18 Radio-Inputs mit identischer ID
id="Typenbezeichnung"— HTML-invalid - 🟡 Datums-Format-Bug
date('Y-m-j h:i:s')im Backend — 12h statt 24h - 🟡 4× Code-Duplizierung im Backend (Ansichten 1–4)
- 🟡 String-Nullen als „leer" statt NULL (
kunden_id='0', bestell_id='0') - 🟢 VVG-Tippfehler
VVG-Informationspflichetenverordnung
Siehe auch¶
- Nutzer: Service-Tools (Kennzeichen bestellen)
- Link-Modul —
$sach_*-Variablen werden ins Formular eingesetzt