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
|
|
@ -3,23 +3,19 @@
|
|||
namespace App\Http\Controllers\Web;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Register\RegisterUserRequest;
|
||||
use App\Mail\MailVerifyAccount;
|
||||
use App\Models\UserLevel;
|
||||
use App\Repositories\UserRepository;
|
||||
use App\Services\FormSpamGuard;
|
||||
use App\Services\UserService;
|
||||
use App\Services\Util;
|
||||
use App\User;
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Request;
|
||||
use Validator;
|
||||
|
||||
class RegisterController extends Controller
|
||||
{
|
||||
private $GOOGLE_ReCAPTCHA_KEY = '6LeeZosUAAAAAG907fMMqO4BFgsiR4ANDodd8FlU';
|
||||
|
||||
private $GOOGLE_ReCAPTCHA_SECRET = '6LeeZosUAAAAADIy2fyR4RG3EuM-Zdz7Pa2Qmb1J';
|
||||
|
||||
protected $userRepo;
|
||||
|
||||
/**
|
||||
|
|
@ -27,7 +23,7 @@ class RegisterController extends Controller
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(UserRepository $userRepo)
|
||||
public function __construct(UserRepository $userRepo, private FormSpamGuard $spamGuard)
|
||||
{
|
||||
$this->userRepo = $userRepo;
|
||||
}
|
||||
|
|
@ -35,7 +31,7 @@ class RegisterController extends Controller
|
|||
public function index()
|
||||
{
|
||||
if (config('app.debug')) {
|
||||
\Log::channel('doamin')->debug('RegisterController: index - Session user_shop', [
|
||||
\Log::channel('domain')->debug('RegisterController: index - Session user_shop', [
|
||||
'session_user_shop_id' => \Session::get('user_shop')?->id,
|
||||
'session_user_shop_name' => \Session::get('user_shop')?->name,
|
||||
'session_user_shop_user_id' => \Session::get('user_shop')?->user_id,
|
||||
|
|
@ -47,7 +43,8 @@ class RegisterController extends Controller
|
|||
}
|
||||
|
||||
$data = [
|
||||
'GOOGLE_ReCAPTCHA_KEY' => $this->GOOGLE_ReCAPTCHA_KEY,
|
||||
'turnstile_site_key' => config('services.turnstile.site_key'),
|
||||
'form_token' => old(FormSpamGuard::TIMESTAMP_FIELD, $this->spamGuard->makeFormToken()),
|
||||
'user_shop' => Util::getUserShop(),
|
||||
'yard_instance' => 'webshop',
|
||||
];
|
||||
|
|
@ -60,13 +57,12 @@ class RegisterController extends Controller
|
|||
if (! $member_id) {
|
||||
return redirect('/registrierung');
|
||||
}
|
||||
$user_id = (int) str_replace('m', '', $member_id) - config('mivita.add_number_id');
|
||||
$user = User::find($user_id);
|
||||
if (! $user || ! $user->isActive() || ! $user->isActiveAccount()) {
|
||||
if (! $this->findActiveSponsor($member_id)) {
|
||||
return redirect('/registrierung');
|
||||
}
|
||||
$data = [
|
||||
'GOOGLE_ReCAPTCHA_KEY' => $this->GOOGLE_ReCAPTCHA_KEY,
|
||||
'turnstile_site_key' => config('services.turnstile.site_key'),
|
||||
'form_token' => old(FormSpamGuard::TIMESTAMP_FIELD, $this->spamGuard->makeFormToken()),
|
||||
'user_shop' => Util::getUserShop(),
|
||||
'from_member_id' => $member_id,
|
||||
'yard_instance' => 'webshop',
|
||||
|
|
@ -75,32 +71,17 @@ class RegisterController extends Controller
|
|||
return view('web.templates.registrierung', $data);
|
||||
}
|
||||
|
||||
public function register()
|
||||
public function register(RegisterUserRequest $request): RedirectResponse
|
||||
{
|
||||
if ($blockReason = $this->spamGuard->blockReason($request)) {
|
||||
FormSpamGuard::log($request, 'register', $blockReason);
|
||||
|
||||
$rules = [
|
||||
'salutation' => 'required',
|
||||
'first_name' => 'required',
|
||||
'last_name' => 'required',
|
||||
'email' => 'required|string|email:filter|max:255|unique:users',
|
||||
'email-confirm' => 'required|same:email',
|
||||
'password' => 'required|string|min:6|confirmed',
|
||||
'password_confirmation' => 'required|string|min:6',
|
||||
'g-recaptcha-response' => 'required|recaptcha',
|
||||
'accepted_data_protection' => 'required',
|
||||
];
|
||||
|
||||
Validator::extend('recaptcha', function ($attribute, $value, $parameters, $validator) {
|
||||
return $this->reCaptcha_validate($attribute, $value, $parameters, $validator);
|
||||
});
|
||||
|
||||
$validator = Validator::make(Request::all(), $rules);
|
||||
if ($validator->fails()) {
|
||||
return back()->withErrors($validator)->withInput(Request::all());
|
||||
return redirect('/registrierung/finish');
|
||||
}
|
||||
|
||||
$user_shop = Util::getUserShop();
|
||||
$data = Request::all();
|
||||
$data = $request->validated();
|
||||
$data['lang'] = ! empty(\App::getLocale()) ? \App::getLocale() : 'de';
|
||||
$user = $this->userRepo->create($data);
|
||||
|
||||
$confirmation_code = UserService::createConfirmationCode();
|
||||
|
|
@ -108,10 +89,9 @@ class RegisterController extends Controller
|
|||
if ($user_shop) {
|
||||
$m_sponsor_id = $user_shop->user->id;
|
||||
}
|
||||
if (isset($data['from_member_id'])) {
|
||||
$m_sponsor_id = (int) str_replace('m', '', $data['from_member_id']) - config('mivita.add_number_id');
|
||||
if (filled($data['from_member_id'] ?? null) && $sponsor = $this->findActiveSponsor($data['from_member_id'])) {
|
||||
$m_sponsor_id = $sponsor->id;
|
||||
}
|
||||
$user->lang = ! empty(\App::getLocale()) ? \App::getLocale() : 'de';
|
||||
$user->confirmation_code = $confirmation_code;
|
||||
$user->confirmation_code_to = date('Y-m-d H:i:s', strtotime('+1 week'));
|
||||
$user->confirmation_code_remider = 0;
|
||||
|
|
@ -144,23 +124,18 @@ class RegisterController extends Controller
|
|||
return view('web.templates.registrierung_finish', $data);
|
||||
}
|
||||
|
||||
private function reCaptcha_validate($attribute, $value, $parameters, $validator)
|
||||
/**
|
||||
* Löst eine Partner-Nummer (z. B. "m1234") zu einem aktiven Berater auf.
|
||||
*/
|
||||
private function findActiveSponsor(string $memberId): ?User
|
||||
{
|
||||
$userId = (int) str_replace('m', '', $memberId) - config('mivita.add_number_id');
|
||||
$user = User::find($userId);
|
||||
|
||||
$client = new Client;
|
||||
if (! $user || ! $user->isActive() || ! $user->isActiveAccount()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$response = $client->post(
|
||||
'https://www.google.com/recaptcha/api/siteverify',
|
||||
[
|
||||
'form_params' => [
|
||||
'secret' => $this->GOOGLE_ReCAPTCHA_SECRET,
|
||||
'response' => $value,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$body = json_decode((string) $response->getBody());
|
||||
|
||||
return $body->success;
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue