Spamschutz Kontakt + Registrierung: Turnstile, Rate-Limit, Honeypot; Passwort min. 8
- Kontaktformular: keine Mail mehr an die eingegebene Adresse (wurde als Spam-Versender missbraucht); Anfrage nur an Kontakt-Adresse + Berater (BCC), Reply-To = Absender; Eingaben in der Mail escaped - Kontakt + Registrierung: Cloudflare Turnstile statt reCAPTCHA (Schluessel aus dem Code in die .env), Rate-Limits, Honeypot + Mindest-Ausfuellzeit, Namensregel (lateinische Schrift, max. 50 Zeichen), Form Requests - Registrierung: Partner-Nummer nur fuer aktive Berater (vorher ungeprueft) - CRM: POST /register abgeschaltet (legte ohne Captcha Benutzer an) - Passwort-Mindestlaenge systemweit 8 Zeichen ueber Password::defaults() - Log abgefangener Anfragen: storage/logs/form-spam-*.log - Doku und Protokoll: dev/2026-10-09-spam/README.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
fe1a9478f4
commit
4c944aa15d
44 changed files with 1320 additions and 248 deletions
233
dev/2026-10-09-spam/README.md
Normal file
233
dev/2026-10-09-spam/README.md
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
# Spam über das Kontaktformular – Entwicklungsplan & Protokoll
|
||||
|
||||
Stand: 09.10.2026 · Status: **Kontaktformular + Registrierung umgesetzt, als `v1.6.0` getaggt** (Deploy siehe Abschnitt 7)
|
||||
|
||||
Beispiel-Mail: [spam-mail.md](spam-mail.md)
|
||||
|
||||
---
|
||||
|
||||
## 1. Befund
|
||||
|
||||
Betroffen ist das Kontaktformular `/kontakt`, das auf allen Shops läuft (Hauptseite, `shop.*`, alle Berater-Shops wie `freshzone.mivita.care`).
|
||||
|
||||
- Route: `routes/shared/common.php` (bzw. `routes/domains/main.php`) → `Web\ContactController@store`
|
||||
- Mail: `App\Mail\MailContact`, Vorlage `resources/views/emails/contact.blade.php`
|
||||
- Formular: `resources/views/web/templates/kontakt.blade.php`
|
||||
|
||||
### Was in der Beispiel-Mail passiert
|
||||
|
||||
Die Spam-Mail ist **keine Nachricht an uns**, sondern die **Kopie an den Absender** („Deine Anfrage von freshzone.mivita.care“). Der Controller schickt die Mail so:
|
||||
|
||||
```php
|
||||
Mail::to($contact['email']) // ← Adresse aus dem Formular
|
||||
->bcc([$user_shop->user->email, $contact_mail])
|
||||
->send(new MailContact($contact));
|
||||
```
|
||||
|
||||
Der Spammer trägt also die Adresse eines **fremden Opfers** ein (hier `igor.makhataev@icloud.com`) und seinen Werbetext in Vorname, Nachname und Nachricht. Unser Server verschickt dann eine Mail **im Namen von mivita.care** mit „Hallo <Werbetext>“ und dem Phishing-Link an das Opfer. Wir und der Berater bekommen nur die BCC-Kopie.
|
||||
|
||||
Das heißt:
|
||||
|
||||
1. **Unser Formular wird als Spam-Versender missbraucht.** Das ist der eigentliche Grund, warum das Formular für Spammer interessant ist – nicht, um uns zu erreichen.
|
||||
2. **Ruf der Absender-Domain:** Beschwerden der Empfänger („Als Spam markieren“) landen bei unserer Domain. Das kann dazu führen, dass auch echte Mails (Bestellbestätigungen, Rechnungen, Abo-Mails) im Spam landen.
|
||||
3. Jeder Berater mit Shop bekommt den Spam zusätzlich per BCC.
|
||||
|
||||
### Weitere Schwachstellen
|
||||
|
||||
| # | Schwachstelle | Fundstelle |
|
||||
| - | ------------- | ---------- |
|
||||
| A | Bestätigungsmail geht an beliebige eingegebene Adresse, inklusive aller Eingaben | `ContactController@store` |
|
||||
| B | Kein Rate-Limit (nur globales `throttle:60,1` für die Web-Gruppe) | `routes/shared/common.php` |
|
||||
| C | reCAPTCHA **v2 (Checkbox)** – wird von bezahlten Captcha-Lösediensten zuverlässig geknackt | `kontakt.blade.php` |
|
||||
| D | reCAPTCHA-Schlüssel **inkl. Secret hart im Code** und damit im Git | `ContactController` (und `RegisterController`) |
|
||||
| E | Keine Plausibilitätsprüfung: Vorname/Nachname ohne Längenbegrenzung, Links erlaubt, beliebige Schrift | Validierungsregeln |
|
||||
| F | Eingaben werden **ungefiltert als HTML** in die Mail geschrieben (`{!! nl2br($value) !!}`) – man könnte auch Links/Bilder einschleusen | `emails/contact.blade.php` |
|
||||
| G | Kein Protokoll: Wir sehen nicht, wie viele Versuche kommen und was geblockt wird | – |
|
||||
| H | Validierung inline im Controller statt Form Request | `ContactController` |
|
||||
|
||||
---
|
||||
|
||||
## 2. Vorgeschlagene Maßnahmen
|
||||
|
||||
Reihenfolge nach Wirkung. Stufe 1 allein dürfte den größten Teil erledigen, weil das Formular für Spammer damit wertlos wird.
|
||||
|
||||
### Stufe 1 – sofort, höchste Wirkung
|
||||
|
||||
**1.1 Keine Inhalte mehr an die eingegebene Adresse schicken** (behebt A)
|
||||
- Die Anfrage geht nur noch an `kontakt@mivita.care` bzw. den Berater, mit `Reply-To` = Adresse des Absenders (Antworten funktionieren wie bisher).
|
||||
- Der Absender sieht die Bestätigungsseite. Falls eine Bestätigungsmail gewünscht ist: nur ein **neutraler Text ohne Eingaben** („Wir haben Deine Anfrage erhalten …“), siehe Entscheidung E1.
|
||||
|
||||
**1.2 Rate-Limit** (behebt B)
|
||||
- Eigener Limiter für `POST /kontakt`, z. B. max. 3 Anfragen / 10 Minuten pro IP und max. 3 / Tag pro E-Mail-Adresse.
|
||||
|
||||
**1.3 Honeypot + Mindest-Ausfüllzeit** (unsichtbar für echte Besucher)
|
||||
- Verstecktes Feld, das nur Bots ausfüllen.
|
||||
- Verschlüsselter Zeitstempel beim Laden des Formulars; Absenden schneller als ~3 Sekunden → verwerfen.
|
||||
- Abgefangene Anfragen bekommen trotzdem die normale Erfolgsseite, damit der Bot nichts lernt.
|
||||
|
||||
**1.4 Plausibilitätsregeln** (behebt E)
|
||||
- Vorname/Nachname: max. 50 Zeichen, keine URLs, keine Zeilenumbrüche, nur lateinische Schrift inkl. Umlaute/Akzente (Shops laufen auf de/en/es/fr).
|
||||
- Nachricht: max. ca. 3.000 Zeichen, max. 1–2 Links.
|
||||
- Telefon: nur Ziffern, Leerzeichen, `+ - / ( )`.
|
||||
- Vorname = Nachname = Nachricht (wie im Beispiel) → verwerfen.
|
||||
|
||||
**1.5 Mail-Vorlage absichern** (behebt F)
|
||||
- `{!! nl2br($value) !!}` → `{!! nl2br(e($value)) !!}`.
|
||||
|
||||
### Stufe 2 – Aufräumen & Absichern
|
||||
|
||||
**2.1 Captcha** (behebt C, D) – siehe Entscheidung E2
|
||||
- Schlüssel in `.env` / `config/services.php` verschieben, **Secret bei Google neu erzeugen** (das alte liegt im Git).
|
||||
- Bei der Prüfung zusätzlich `hostname` kontrollieren.
|
||||
- Optional Wechsel auf Cloudflare Turnstile oder reCAPTCHA v3 (unsichtbar, schwerer automatisiert zu lösen).
|
||||
|
||||
**2.2 Form Request** (behebt H)
|
||||
- `ContactStoreRequest` mit Regeln und Fehlermeldungen (de/en/es/fr), Controller verschlanken.
|
||||
|
||||
**2.3 Protokoll geblockter Anfragen** (behebt G) – siehe Entscheidung E4
|
||||
- Eigener Log-Kanal `contact-spam` (Grund, IP, Shop, Zeit – **ohne** Nachrichtentext wegen Datenschutz) oder kleine DB-Tabelle mit Zählern.
|
||||
- Damit sehen wir nach der Umstellung, ob es wirkt, und können Regeln nachschärfen.
|
||||
|
||||
### Stufe 3 – nur falls nötig
|
||||
|
||||
- Wortfilter / Sperrliste für Domains und Linkdienste (z. B. `share.google`, Kurz-URLs).
|
||||
- Gleiche Prüfung auf das Registrierungsformular übertragen (nutzt dieselben reCAPTCHA-Schlüssel).
|
||||
|
||||
---
|
||||
|
||||
## 3. Entscheidungen (abgestimmt am 09.10.2026)
|
||||
|
||||
| # | Frage | Entscheidung |
|
||||
| - | ----- | ------------ |
|
||||
| E1 | Bestätigungsmail an den Absender? | **Nein.** Nur Bestätigungsseite. Die Anfrage geht an `kontakt@mivita.care` (+ Berater per BCC), `Reply-To` = Absender. |
|
||||
| E2 | Captcha | **Wechsel auf Cloudflare Turnstile.** Vorgabe: kostenlos. Turnstile ist dauerhaft kostenlos, ohne Mengenlimit und ohne Zahlungsdaten; die Seite muss nicht über Cloudflare laufen. reCAPTCHA v3 läuft inzwischen über Google Cloud (nur 10.000 Prüfungen/Monat frei, Cloud-Projekt nötig) und ist datenschutzrechtlich ungünstiger. |
|
||||
| E3 | Nicht-lateinische Schrift in Namensfeldern blocken? | **Ja.** |
|
||||
| E4 | Protokoll | **Logdatei** `storage/logs/contact-spam-YYYY-MM-DD.log` (30 Tage). Admin-Übersicht nur bei Bedarf. |
|
||||
| E5 | Berater bekommen weiter eine Kopie? | **Ja**, per BCC. |
|
||||
|
||||
---
|
||||
|
||||
## 4. Umsetzung Kontaktformular (Stand 09.10.2026)
|
||||
|
||||
### Was jetzt passiert, wenn jemand das Formular abschickt
|
||||
|
||||
1. **Rate-Limit** (`throttle:contact-form`, `RouteServiceProvider`): max. 5 Anfragen / 10 Min. pro IP und max. 5 / Tag pro E-Mail-Adresse. Darüber: Fehlermeldung am Formular.
|
||||
2. **Validierung** (`App\Http\Requests\Contact\ContactStoreRequest`):
|
||||
- Vor-/Nachname (`App\Rules\PersonName`): max. 50 Zeichen, nur lateinische Buchstaben inkl. Umlaute/Akzente, Leerzeichen, `- ' .`
|
||||
- Telefon: max. 30 Zeichen, nur `0-9 + - / ( ) .` und Leerzeichen
|
||||
- Nachricht: max. 3.000 Zeichen, max. 2 Links
|
||||
- Turnstile-Token wird bei Cloudflare geprüft (`App\Rules\TurnstileToken` → `App\Services\TurnstileVerifier`). Ist Cloudflare nicht erreichbar oder fehlt das Secret → abgelehnt.
|
||||
3. **Unsichtbare Bot-Erkennung** (`App\Services\FormSpamGuard`): verstecktes Feld `form_extra` (Honeypot) und verschlüsselter Zeitstempel `form_token` (Absenden schneller als 3 Sek. → Bot). Bots bekommen die normale Erfolgsseite, es wird aber nichts verschickt.
|
||||
4. **Versand** (`App\Mail\MailContact`): an `config('app.contact_mail')`, Berater des Shops per BCC, `Reply-To` = Absender. Betreff: „Neue Kontaktanfrage über <shop>.mivita.care“. **Keine Mail mehr an die eingegebene Adresse.**
|
||||
5. Eingaben werden in der Mail HTML-escaped (`resources/views/emails/contact.blade.php`).
|
||||
|
||||
---
|
||||
|
||||
## 5. Umsetzung Registrierung (Stand 09.10.2026)
|
||||
|
||||
Die Registrierung (`/registrierung`, `/reg/{partnernummer}` auf Hauptseite, `shop.*` und Berater-Shops) hatte dieselben Schwächen. Zusätzlich verschickt sie eine Bestätigungsmail an die eingegebene Adresse **mit dem Vornamen in der Anrede** – ohne Namensprüfung hätte sich auch das als Spam-Versender missbrauchen lassen.
|
||||
|
||||
1. **Turnstile statt reCAPTCHA** (`data-action="register"`). Damit ist reCAPTCHA im ganzen System entfernt; die alten Schlüssel stehen nicht mehr im Code.
|
||||
2. **Rate-Limit** (`throttle:register-form`): max. 5 Versuche / 10 Min. und 20 / Tag pro IP (großzügiger, weil Berater auf Veranstaltungen mehrere Partner aus einem WLAN registrieren).
|
||||
3. **Validierung** (`App\Http\Requests\Register\RegisterUserRequest`): Namensregel `PersonName` wie beim Kontaktformular, Anrede nur `mr`/`ms`, Datenschutz muss akzeptiert sein. Passwort min. 8 Zeichen (systemweit, siehe unten).
|
||||
4. **Honeypot + Mindestzeit** (`FormSpamGuard`): Bots werden auf die Erfolgsseite geleitet, es wird kein Benutzer angelegt und keine Mail verschickt.
|
||||
5. **Sponsor-Manipulation verhindert:** Die Partner-Nummer `from_member_id` wurde beim Absenden ungeprüft übernommen – man konnte sich jedem beliebigen (auch gesperrten) Berater unterhängen. Jetzt gilt sie nur, wenn der Berater aktiv ist und einen gültigen Account hat; sonst greift wie bisher Shop-Inhaber bzw. Firma.
|
||||
6. Nur noch geprüfte Felder werden an `UserRepository::create()` übergeben; die Sprache wird direkt beim Anlegen gesetzt.
|
||||
|
||||
### Passwort-Mindestlänge systemweit 8 Zeichen
|
||||
|
||||
Zentral in `AppServiceProvider::boot()`: `Password::defaults(fn () => Password::min(8))`. Alle Stellen, an denen ein neues Passwort gesetzt wird, nutzen `Password::defaults()`: Registrierung, Wizard (Schritt 11), erstes Passwort nach Freischaltung, Passwort ändern, Passwort zurücksetzen (Laravel-Standard). Vorher galten teils 6, teils 8 Zeichen. Bestehende kürzere Passwörter funktionieren beim Login weiter – die Regel greift nur beim Setzen. Texte in `resources/lang/*/passwords.php` angepasst. Tests: `tests/Feature/PasswordPolicyTest.php`.
|
||||
|
||||
### Sicherheitslücke im CRM geschlossen
|
||||
|
||||
`Auth::routes()` in `routes/domains/crm.php` hat neben Login auch `POST /register` auf `my.mivita.care` registriert. Das Formular dazu leitete zwar zum Login um, **der POST selbst legte aber ohne Captcha einen Benutzer an und meldete ihn direkt an** (auf dem Dev-System geprüft: Antwort 419 = Route aktiv, nur CSRF fehlte). Jetzt `Auth::routes(['register' => false])`; der Link „Register“ in `layouts/app.blade.php` ist entfernt.
|
||||
|
||||
Empfehlung: Auf Live einmal prüfen, ob es Benutzer **ohne `account_id`** gibt – das wären Konten, die über diesen Weg angelegt wurden:
|
||||
|
||||
```sql
|
||||
SELECT id, email, created_at FROM users WHERE account_id IS NULL OR account_id = 0 ORDER BY created_at DESC;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Gemeinsames Protokoll & Stellschrauben
|
||||
|
||||
### Protokoll abgefangener Anfragen
|
||||
|
||||
`storage/logs/form-spam-*.log` (30 Tage), eine Zeile pro Vorfall mit `form` (`contact` / `register`), `reason`, IP, Host, Shop-ID, Domain der E-Mail-Adresse – kein Freitext, keine Passwörter.
|
||||
|
||||
| reason | Bedeutung |
|
||||
| ------ | --------- |
|
||||
| `validation` | Validierung fehlgeschlagen, `fields` nennt die Felder (betrifft auch echte Tippfehler) |
|
||||
| `rate_limit` | zu viele Anfragen |
|
||||
| `honeypot` | verstecktes Feld ausgefüllt |
|
||||
| `too_fast` | schneller als 3 Sek. abgeschickt |
|
||||
| `invalid_form_token` | Zeitstempel fehlt/manipuliert (Formular nicht über die Seite geladen) |
|
||||
|
||||
Auswertung auf dem Server (Bash):
|
||||
|
||||
```bash
|
||||
grep -ho '"form":"[a-z]*","reason":"[a-z_]*"' storage/logs/form-spam-*.log | sort | uniq -c
|
||||
```
|
||||
|
||||
### Stellschrauben für spätere Anpassungen
|
||||
|
||||
| Was | Wo |
|
||||
| --- | -- |
|
||||
| Rate-Limits | `RouteServiceProvider::configureRateLimiting()` → `contact-form`, `register-form` |
|
||||
| Namensregel | `App\Rules\PersonName` (Muster, max. Länge) |
|
||||
| Telefon-Muster, max. Links (Kontakt) | Konstanten in `ContactStoreRequest` |
|
||||
| Mindest-Ausfüllzeit, Feldnamen | `FormSpamGuard` |
|
||||
| Fehlermeldungen | `resources/lang/*/form_protection.php` (gemeinsam), `resources/lang/*/contact.php` (Kontakt + Mailtexte) |
|
||||
|
||||
Hinweis Routing: Auf der Hauptdomain überschreibt `routes/domains/main.php` die Kontakt-Route aus `routes/shared/common.php`. Änderungen an der Route deshalb **an beiden Stellen** machen. Die Registrierungs-Route steht in `main.php`, `shop.php` und `user-shop.php`.
|
||||
|
||||
### Geänderte / neue Dateien
|
||||
|
||||
- Controller: `Web/ContactController.php`, `Web/RegisterController.php`
|
||||
- Requests: `Requests/Contact/ContactStoreRequest.php`, `Requests/Register/RegisterUserRequest.php` (neu)
|
||||
- Regeln/Services: `Rules/PersonName.php`, `Rules/TurnstileToken.php`, `Services/TurnstileVerifier.php`, `Services/FormSpamGuard.php` (neu)
|
||||
- `Mail/MailContact.php`, `Repositories/UserRepository.php` (`create`: Sprache beim Anlegen)
|
||||
- Views: `web/templates/kontakt.blade.php`, `web/templates/registrierung.blade.php`, `emails/contact.blade.php`, `layouts/app.blade.php`
|
||||
- Routen: `RouteServiceProvider.php`, `routes/shared/common.php`, `routes/domains/{main,shop,user-shop,crm}.php`
|
||||
- Config: `config/services.php` (`turnstile`), `config/logging.php` (`form_spam`), `.env.example`
|
||||
- Sprachen: `resources/lang/{de,en,es,fr}/contact.php`, `form_protection.php` (neu)
|
||||
- Passwort: `AppServiceProvider.php`, `UserUpdatePasswordController.php`, `WizardController.php`, `Auth/RegisterController.php`, `resources/lang/*/passwords.php`
|
||||
- Tests: `tests/Feature/ContactFormSpamTest.php` (26), `tests/Feature/RegisterFormSpamTest.php` (16), `tests/Feature/PasswordPolicyTest.php` (5)
|
||||
|
||||
---
|
||||
|
||||
## 7. Deployment – vor dem Go-Live erledigen
|
||||
|
||||
1. **Turnstile-Widget anlegen** (kostenlos): https://dash.cloudflare.com → Turnstile → „Add widget“
|
||||
- Hostnames: `mivita.care`, `mivita.shop` (Subdomains wie `freshzone.mivita.care` sind automatisch abgedeckt)
|
||||
- Widget Mode: **Managed**
|
||||
2. Schlüssel in die Live-`.env` eintragen:
|
||||
```
|
||||
TURNSTILE_SITE_KEY=...
|
||||
TURNSTILE_SECRET_KEY=...
|
||||
```
|
||||
✅ Widget angelegt am 09.10.2026. **Ohne diese Schlüssel lehnen Kontaktformular und Registrierung jede Anfrage ab.** Lokal sind die Cloudflare-Testschlüssel eingetragen, die immer bestehen.
|
||||
3. **Datenschutzerklärung** anpassen: Google reCAPTCHA raus, Cloudflare Turnstile (Kontakt + Registrierung) rein.
|
||||
4. Deploy wie üblich per Tag (`dev/betrieb/README.md`), keine Migration: `bash dev/betrieb/deploy.sh v1.6.0`
|
||||
5. Danach den alten reCAPTCHA-Schlüssel in der Google-Konsole löschen (das Secret liegt in der Git-Historie).
|
||||
6. SQL-Abfrage aus Abschnitt 5 (Benutzer ohne Account) auf Live ausführen.
|
||||
7. Nach ein paar Tagen das Log auswerten (Befehl oben) und hier im Protokoll eintragen.
|
||||
|
||||
### Noch offen (nur bei Bedarf)
|
||||
|
||||
- Wortfilter / Sperrliste für Linkdienste, falls trotzdem Spam durchkommt.
|
||||
|
||||
---
|
||||
|
||||
## 8. Protokoll
|
||||
|
||||
| Datum | Was | Version |
|
||||
| ----- | --- | ------- |
|
||||
| 09.10.2026 | Analyse, Plan erstellt (dieses Dokument) | – |
|
||||
| 09.10.2026 | Entscheidungen E1–E5 abgestimmt (E2: Turnstile statt reCAPTCHA, weil kostenlos) | – |
|
||||
| 09.10.2026 | Stufe 1 + 2 umgesetzt, 26 Tests grün (`tests/Feature/ContactFormSpamTest.php`) | noch nicht deployt |
|
||||
| 09.10.2026 | Registrierung auf Turnstile + gleiche Schutzschichten, Sponsor-Prüfung, offenes `POST /register` im CRM geschlossen; Schutz-Bausteine verallgemeinert (`FormSpamGuard`, `PersonName`, Log `form-spam`), 15 Tests grün (`tests/Feature/RegisterFormSpamTest.php`) | noch nicht deployt |
|
||||
| 09.10.2026 | Passwort-Mindestlänge systemweit auf 8 Zeichen (zentral über `Password::defaults()`), Turnstile-Widget bei Cloudflare angelegt | noch nicht deployt |
|
||||
| 09.10.2026 | Echte Turnstile-Schlüssel lokal geprüft: Secret von Cloudflare akzeptiert, Site-Key auf Hauptseite und Berater-Shop ausgeliefert, gefälschtes Token wird abgelehnt und protokolliert | noch nicht deployt |
|
||||
| 09.10.2026 | Auf dem Testsystem im Browser geprüft (läuft), Commit + Tag für den Deploy | v1.6.0 |
|
||||
24
dev/2026-10-09-spam/spam-mail.md
Normal file
24
dev/2026-10-09-spam/spam-mail.md
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
Hallo Приветствуем! Напоминаем, что на вашем бонусном счёте находится 926USD. Бонус будет аннулирован через 10 дней. Воспользоваться бонусом или вывести средства вы можете по ссылке: https://share.google/O8hzS8W7vPuroPXdL Всего доброго, команда сайта
|
||||
|
||||
Deine Anfrage von freshzone.mivita.care
|
||||
|
||||
Anrede:
|
||||
Frau
|
||||
Vorname:
|
||||
Приветствуем! Напоминаем, что на вашем бонусном счёте находится 926USD. Бонус будет аннулирован через 10 дней. Воспользоваться бонусом или вывести средства вы можете по ссылке: https://share.google/O8hzS8W7vPuroPXdL
|
||||
Всего доброго, команда сайта
|
||||
Nachname:
|
||||
Приветствуем! Напоминаем, что на вашем бонусном счёте находится 926USD. Бонус будет аннулирован через 10 дней. Воспользоваться бонусом или вывести средства вы можете по ссылке: https://share.google/O8hzS8W7vPuroPXdL
|
||||
Всего доброго, команда сайта
|
||||
E-Mail:
|
||||
igor.makhataev@icloud.com
|
||||
Telefon:
|
||||
88538273161
|
||||
Nachricht:
|
||||
Приветствуем! Напоминаем, что на вашем бонусном счёте находится 918USD. Бонус будет аннулирован через 11 дней. Воспользоваться бонусом или вывести средства вы можете по ссылке: https://share.google/SzivlySgl5DxoQgWn
|
||||
Всего доброго, команда сайта
|
||||
|
||||
|
||||
Für weitere Fragen stehen wir Dir gerne zur Verfügung.
|
||||
|
||||
Mit freundlichen Grüßen
|
||||
Loading…
Add table
Add a link
Reference in a new issue