Brute-Force-Angriffe zum Erraten von Passwörtern sind eine reale Bedrohung für die Websicherheit. Diese Anleitung zeigt Schritt für Schritt, wie Sie das Login-Formular im Yii2-Framework schützen, indem nach mehreren fehlgeschlagenen Anmeldeversuchen automatisch eine CAPTCHA-Validierung aktiviert wird.
Warum CAPTCHA für das Login entscheidend ist
Brute-Force-Angriffe sind eine alte, aber effektive Methode. Angreifer nutzen Bots, um automatisch tausende Kombinationen aus Benutzername und Passwort zu testen. Ein ungeschütztes Formular kann zu kompromittierten Admin-Konten führen.
- Blockiert Bots: CAPTCHA („Completely Automated Public Turing test to tell Computers and Humans Apart“) unterscheidet Menschen von Robotern.
- Erhöht den Aufwand: Ein ausgelöstes CAPTCHA nach mehreren Fehlversuchen erhöht den Aufwand für Angreifer erheblich.
- Verteidigungsstrategie: CAPTCHA ist eine wichtige zusätzliche Sicherheitsebene.
Die bedingte Implementierung von CAPTCHA (nur bei Bedarf) erhält die Benutzerfreundlichkeit und stellt gleichzeitig eine Barriere für Bots dar.
Schritt 1: Das LoginForm-Modell anpassen
Fügen Sie zunächst eine Eigenschaft für das CAPTCHA und seine Validierungslogik zum `LoginForm`-Modell hinzu. Der Schlüssel ist, das CAPTCHA erst nach einer bestimmten Anzahl von Fehlversuchen obligatorisch zu machen.
<?php
namespace app\models;
use Yii;
use yii\base\Model;
class LoginForm extends Model
{
public $username;
public $password;
public $rememberMe = true;
public $verifyCode; // Neue Eigenschaft für CAPTCHA
// ... bestehender Code ...
public function rules()
{
return [
// Regeln für Benutzername und Passwort
[['username', 'password'], 'required'],
['rememberMe', 'boolean'],
['password', 'validatePassword'],
// CAPTCHA-REGELN: Nur erforderlich, wenn loginFailed true ist
['verifyCode', 'required', 'when' => function($model) {
return $model->loginFailed;
}, 'message' => 'Der CAPTCHA-Code ist nach mehreren Fehlversuchen erforderlich.'],
['verifyCode', 'captcha', 'when' => function($model) {
return $model->loginFailed;
}],
];
}
public function validatePassword($attribute, $params)
{
if (!$this->hasErrors()) {
$user = $this->getUser();
if (!$user || !$user->validatePassword($this->password)) {
// KERNLOGIK: Fehlversuchs-Zähler erhöhen
$attempts = Yii::$app->session->get('_loginAttempts', 0) + 1;
Yii::$app->session->set('_loginAttempts', $attempts);
$this->addError($attribute, 'Falscher Benutzername oder Passwort.');
} else {
// Zähler bei erfolgreicher Anmeldung zurücksetzen
Yii::$app->session->remove('_loginAttempts');
}
}
}
// Getter zur Überprüfung des Fehlerstatus
public function getLoginFailed()
{
// CAPTCHA wird nach 3 oder mehr Fehlversuchen ausgelöst
return Yii::$app->session->get('_loginAttempts', 0) >= 3;
}
// ... getUser()-Methode und andere ...
}Schlüsselerklärung zum Code:
- Die Eigenschaft
$verifyCodespeichert die CAPTCHA-Eingabe des Benutzers. - Die Methode
getLoginFailed()prüft die Session-Variable_loginAttempts. Sie gibttruezurück, wenn Fehlversuche ≥ 3 sind. - Der Parameter
'when'stellt sicher, dass die Regeln fürverifyCodenur gelten, wennloginFailedtrueist.
Schritt 2: CAPTCHA in der Login-View anzeigen
Passen Sie als Nächstes die Login-View-Datei an, damit das CAPTCHA-Widget nur angezeigt wird, wenn die Bedingung $model->loginFailed erfüllt ist.
<?php
use yii\helpers\Html;
use yii\bootstrap5\ActiveForm; // oder yii\widgets\ActiveForm
/* @var $this yii\web\View */
/* @var $form yii\widgets\ActiveForm */
/* @var $model app\models\LoginForm */
$this->title = 'Anmeldung';
?>
<div class="site-login">
<h1><?= Html::encode($this->title) ?></h1>
<div class="row">
<div class="col-lg-5">
<?php $form = ActiveForm::begin(['id' => 'login-form']); ?>
<?= $form->field($model, 'username')->textInput(['autofocus' => true]) ?>
<?= $form->field($model, 'password')->passwordInput() ?>
<?= $form->field($model, 'rememberMe')->checkbox() ?>
<!-- BEDINGTER CAPTCHA-BEREICH -->
<?php if ($model->loginFailed): ?>
<div class="alert alert-warning">
Zu viele fehlgeschlagene Anmeldeversuche. Bitte bestätigen Sie, dass Sie ein Mensch sind.
</div>
<?= $form->field($model, 'verifyCode')->widget(\yii\captcha\Captcha::className()) ?>
<?php endif; ?>
<div class="form-group">
<?= Html::submitButton('Anmelden', ['class' => 'btn btn-primary', 'name' => 'login-button']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
</div>
</div>Schritt 3: CAPTCHA-Action im Controller konfigurieren
Das CAPTCHA-Widget benötigt eine dedizierte Action im Controller. Stellen Sie sicher, dass die ‚captcha‘-Action in `SiteController` konfiguriert ist.
<?php
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
// ... andere actions() ...
public function actions()
{
return [
'error' => ['class' => 'yii\web\ErrorAction'],
// DIE CAPTCHA-ACTION MUSS VORHANDEN SEIN
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
'minLength' => 4,
'maxLength' => 5,
'offset' => 2,
'testLimit' => 1,
],
// ... andere Actions ...
];
}
// ... actionLogin() und andere Methoden ...
}Wichtige Hinweise & zusätzliche Sicherheit
- Session-basiert: Diese Implementierung nutzt PHP-Sessions. Stellen Sie eine sichere Konfiguration sicher.
- Nicht die einzige Lösung: CAPTCHA sollte mit anderen Maßnahmen kombiniert werden:
- Ratenbegrenzung (Rate Limiting): Nutzen Sie Komponenten wie `yiifiltersRateLimiter`.
- Starke Passwörter: Erzwingen Sie komplexe Passwörter.
- Protokollierung: Protokollieren Sie alle Anmeldeversuche.
- Zähler zurücksetzen: Der Zähler wird bei erfolgreicher Anmeldung zurückgesetzt. Eine zeitbasierte Zurücksetzung ist ebenfalls möglich.
Durch die Implementierung dieses bedingten CAPTCHAs fügen Sie eine wichtige Sicherheitsebene hinzu, die den automatisierten Ablauf von Brute-Force-Angriffen intelligent unterbricht, bei gleichbleibender Benutzerfreundlichkeit.
