Sicherheit und Audit: absichern und nachvollziehen, wer was getan hat
Diese Anleitung richtet sich an Administratoren und Betreiber, die für die Sicherheit einer Site verantwortlich sind. In etwa 30 Minuten prüfen Sie, ob eine frische Exponential-Installation gehärtet ist, vergeben Zugriffe über Rollen und Richtlinien, lesen das Audit-Protokoll, schalten die Debug-Ausgabe nur für Ihre eigene Adresse ein und fügen (optional) eine Zwei-Faktor-Anmeldung hinzu. Jeder Schritt ist ein Befehl oder ein Klickpfad, den es in 6.0.15 gibt. Befehle werden im Wurzelverzeichnis des Projekts ausgeführt; die Beispiele verwenden https://example.com für Ihre Site.
Warnung
.htaccessbremst jede Anfrage. Sind.htaccess-Dateien erlaubt (AllowOverridealles außerNone), geschweige denn genutzt, sucht Apache sie bei jeder Anfrage in jedem Verzeichnis des Pfads und liest und wertet sie aus, und die Ladezeiten der Seiten steigen drastisch (gemessen). Die einzige wirkliche Abhilfe ist, die Funktion für den virtuellen Host abzuschalten:AllowOverride Noneim virtuellen HTTPS-Host, und die Regeln in der Konfiguration des virtuellen Hosts selbst als mod_rewrite-Regeln. Das ist in Geschwindigkeitstests im Produktivbetrieb weit schneller und die Zeit für die Optimierung einer Produktivkonfiguration unbedingt wert. Stellen Sie sofort um: Übernehmen Sie die Regeln des Beispiels für einen virtuellen HTTPS-Host in Ihren virtuellen Host (mit dem statischen Cache auchstaticcache_offload.conf), setzen SieAllowOverride None, führen Sieapachectl configtestaus, laden Sie Apache neu und testen Sie die Website. Dieselben Regeln für andere Server: nginx, LiteSpeed, Caddy, IIS, Velocity (eingebaut); wohin Regeln für virtuelle Hosts in einem Control Panel gehören: Plesk, cPanel, DirectAdmin, ISPConfig. Unter LiteSpeed oder OpenLiteSpeed kann zusätzlich der Seiten-Cache des Servers anonyme Besucher und Crawler ohne PHP bedienen: Seiten-Caching mit LiteSpeed und OpenLiteSpeed.
Sie benötigen: Shell-Zugang zur Installation, eine Administrator-Anmeldung und curl.
1. Die bereits aktive Härtung prüfen (5 Minuten)
Seit September 2026 ist eine Standardinstallation ohne zusätzlichen Aufwand sicher. Prüfen Sie das, statt sich darauf zu verlassen.
Sicherheits-Header. Jede Seite, die Administration eingeschlossen, muss fünf Header tragen:
curl -sI https://example.com/ | grep -i -E 'x-content-type|x-frame|referrer|permissions|content-security'Erwartete Ausgabe (die Reihenfolge kann abweichen):
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
content-security-policy: frame-ancestors 'self'
referrer-policy: strict-origin-when-cross-origin
permissions-policy: camera=(), microphone=(), payment=(), usb=()Ändern Sie einen davon mit ./console exp:ini set (Scope override), zum Beispiel, um einem vertrauenswürdigen Editor-Host zu erlauben, die Administration in einen Frame einzubetten. Die Einstellung ist site.ini [HTTPHeaderSettings] SecurityHeaders[Content-Security-Policy]; lesen Sie zuerst ihren Wert:
./console exp:ini get 'site.ini/HTTPHeaderSettings/SecurityHeaders[Content-Security-Policy]' --allow-root-userSchalten Sie HSTS nur ein, wenn die gesamte Site ausschließlich über HTTPS läuft: SecurityHeaders[Strict-Transport-Security]=max-age=31536000.
Dateien, die nicht ausgeliefert werden dürfen. Punktdateien und PHP-Dateien unterhalb des Document Root müssen mit 404 antworten:
for p in .env .git/config extension/expservices/ezinfo.php; do
curl -s -o /dev/null -w "$p %{http_code}\n" https://example.com/$p
doneErwartet: dreimal 404. Wenn Sie eine eigene Kopie von .htaccess pflegen, übernehmen Sie die Regeln aus .htaccess_root und .htaccess_root_static. ./console exp:setup:htaccess (oder --static) zeigt den Unterschied Ihrer Kopie zu den mitgelieferten Regeln und endet mit Exit-Code 1, solange es einen gibt; steht nichts Eigenes darin, übernimmt --force --apply die mitgelieferten Regeln, nachdem Ihre gesichert wurden (.htaccess und config.php von der Konsole einrichten).
Das Sitzungs-Cookie. Melden Sie sich in der Administration an und öffnen Sie in den Entwicklerwerkzeugen des Browsers Anwendung (oder Speicher), Cookies: Das Sitzungs-Cookie muss HttpOnly, SameSite=Lax und, unter HTTPS, Secure zeigen. Das sind die Voreinstellungen im Code (die Schlüssel CookieSecure=auto, CookieHttponly=true, CookieSameSite=Lax in site.ini [Session]; die Datei führt sie nur als Kommentare auf). Das Cookie is_logged_in für HTTP-Caches trägt denselben Pfad, dieselbe Domain, dieselbe Lebensdauer, Secure und SameSite, nicht aber HttpOnly. Hinter einem Load Balancer, der einen Benutzer anhand des Sitzungs-Cookies auf einem Server hält, sendet CookieAlwaysAddToHttpResponse=enabled das Sitzungs-Cookie mit jeder Antwort einer laufenden Sitzung (nie an einen Besucher ohne Sitzung), und eine solche Antwort meldet Cache-Control: private, sodass kein gemeinsamer Cache sie speichert: Prüfen Sie mit curl -sI -b <session cookie> <page>, dass sie Set-Cookie zusammen mit private zeigt.
Einstellungen, die es SameSite nennen. Eine Installation, deren Einstellungen für LoveStack (mugoweb/ezpublish-legacy) geschrieben wurden, setzt das Attribut möglicherweise als site.ini [Session] SameSite. Exponential liest auch diesen Namen, solange CookieSameSite nicht gesetzt ist (sind beide gesetzt, wird CookieSameSite verwendet), und vermerkt einmal pro Anfrage, dass der Name veraltet ist (in var/log/deprecated.log, gezählt in der Debug-Ausgabe). Für Besucher ändert sich nichts; um den Hinweis abzustellen, benennen Sie die Einstellung in settings/override und den Siteaccesses in CookieSameSite um.
Abmelden. Das Abmelden beendet die Sitzung endgültig: Was die Sitzung enthielt, wird gelöscht, der Browser wird angewiesen, das Sitzungs-Cookie zu verwerfen (es wird abgelaufen gesendet, mit demselben Pfad, derselben Domain, Secure, HttpOnly und SameSite, mit denen es gesetzt wurde, sodass der Browser genau dieses Cookie entfernt), und die Sitzungs-ID, die der Browser hatte, meldet niemanden mehr an, auch wenn sie vorher kopiert wurde. Eine Sitzung, die die Site später in derselben Anfrage startet, erhält eine neue ID. Das gilt für jeden Session-Handler (den eigenen von PHP, ezpSessionHandlerDB, einen eigenen Handler, den von Symfony) und unter Velocity. Frühere Versionen gaben der Sitzung eine neue ID und behielten ihren Inhalt. Es muss nichts eingeschaltet werden. Zur Prüfung: Melden Sie sich in der Administration an und notieren Sie den Wert des Sitzungs-Cookies, melden Sie sich ab und senden Sie dann eine Anfrage mit dem alten Wert, z. B. curl -s -b '<cookie name>=<old value>' https://<site>/admin/content/dashboard: Die Antwort ist das Anmeldeformular, nicht das Dashboard. Mit [UserSettings] RedirectOnLogoutWithLastAccessURI=enabled führt das Abmelden weiterhin zurück zur zuletzt besuchten Seite.
Dateien und Verzeichnisse, die die Site schreibt. Logs, Caches und Speicher werden so offen angelegt, wie es site.ini [FileSettings] und der Code verlangen (standardmäßig 0777/0666). Setzen Sie auf einem Live-Server die Grenzen in config.php, define( 'EZP_DIR_MODE_MAX', 0750 ); und define( 'EZP_FILE_MODE_MAX', 0640 );, damit nichts Neues für andere Konten lesbar oder schreibbar ist, und schränken Sie das Bestehende einmalig ein: Grenzen für die Modi neuer Dateien und Verzeichnisse. Von der Konsole: ./console exp:config:set EZP_DIR_MODE_MAX 0750 --apply und ./console exp:config:set EZP_FILE_MODE_MAX 0640 --apply.
config.php selbst. Sie kann das Passwort der Cluster-Datenbank enthalten. Halten Sie sie aus der Versionsverwaltung heraus (tragen Sie /config.php in die .gitignore Ihres Projekts ein; das Repository von Exponential enthält nur config.php-RECOMMENDED) und geben Sie ihr den Modus 0640 mit der Gruppe des Webservers. ./console exp:config:list und exp:config:get zeigen die Werte von Namen mit PASS, SECRET, KEY, TOKEN, CREDENTIAL oder PWD als ********, außer Sie geben --show-secrets an; exp:config:set warnt, wenn es ein Geheimnis in eine für alle Benutzer lesbare Datei schreibt. Jede Änderung hinterlässt eine Kopie der alten Datei in var/backup/config/<zeit>/ (Verzeichnisse mit Modus 0700): Schützen Sie var/backup/ wie config.php und löschen Sie alte Kopien (.htaccess und config.php von der Konsole einrichten).
Hochgeladene Bilder. Ein Bild wird anhand dessen akzeptiert, was die Datei enthält, nicht anhand ihres Namens: fileinfo von PHP liest den Typ, und er muss in image.ini [ImageUploadSettings] AllowedMIMETypes[] stehen (im Auslieferungszustand JPEG, PNG, GIF, WebP, AVIF, TIFF, BMP und SVG; ein SVG wird nur bereinigt gespeichert, siehe SVG-Bilder). Das gilt für das Bearbeitungsformular, die Upload-Dialoge, den AJAX-Uploader und die Vorschaubilder des Paket-Assistenten, und eine abgelehnte Datei wird nicht gespeichert. Prüfen Sie, ob fileinfo im PHP des Webservers wie auch auf der Kommandozeile geladen ist (php -m | grep fileinfo); ohne fileinfo gilt die ältere Prüfung mit getimagesize(), und das Log weist einmal darauf hin. Lesen Sie die Liste mit:
./console exp:ini get 'image.ini/ImageUploadSettings/AllowedMIMETypes' --allow-root-userDas erste Administrator-Passwort. Wenn eine Kickstart-Datei kein Passwort setzt, ein allgemein bekanntes wie publish (oder eine einfache Variante davon) oder eines, das kürzer als MinPasswordLength ist, erzeugt der Installer ein zufälliges Passwort aus 20 Zeichen, gibt es einmal aus und schreibt es nach var/log/initial-admin-password (nur für den Eigentümer lesbar). exp:install --random-password erzeugt eines aus 24 Zeichen und zeigt es einmal an. Melden Sie sich an, ändern Sie es und löschen Sie diese Datei. Falls Sie es später vergessen haben:
php bin/php/resetuserpassword.php --allow-root-user -u admin -g-g erzeugt ein zufälliges Passwort und gibt es aus. Details: ein Benutzerpasswort zurücksetzen.
Request Shield vor der Site. Seit 6.0.15 entscheidet request-shield (die Erweiterung exp_request_shield) über jede Anfrage, bevor der Kernel startet: Scanner, Fluten, verirrte Formular-POSTs und System-URLs werden abgewiesen, und die Anmeldung und die Formulare der Administration verlangen eine Browserprüfung. Er ist wie installiert eingeschaltet, im Durchsetzungsmodus, über die Hook-Zeile in config.php; eine Installation, die von einer früheren Version aktualisiert wurde, fügt diese Zeile selbst ein (Request Shield (BC)). Prüfen Sie, dass er läuft: Setup > Request Shield sagt, ob der Schutzschild für diese Seite lief, in welchem Modus und aus welcher Regeldatei, und was er in den letzten 24 Stunden entschieden hat. Von außen:
curl -sI https://<site>/settings/site.ini # 404, vom Schutzschild im DurchsetzungsmodusLesen Sie in den ersten Tagen sein Log und ergänzen Sie eine Ausnahme für alles, was ein echter Besucher oder Redakteur getan hat. Zum sofortigen Ausschalten legen Sie var/request-shield/PAUSED an. Schritt für Schritt: Request Shield.
Vertiefung: Sicherheitsvoreinstellungen vom September 2026, Härtung von Datentypen und Eingaben, Härtung in 6.0.13.
2. Nur den Zugriff vergeben, den Personen brauchen (10 Minuten)
Über den Zugriff entscheiden Rollen aus Richtlinien (Modul, Funktion, Beschränkungen), die Benutzern oder Gruppen zugewiesen werden. Niemand erhält etwas, das ihm keine Rolle gibt.
- Melden Sie sich in der Administrationsoberfläche an und öffnen Sie den Reiter Benutzer, Rollen und Richtlinien (
/role/list). - Klicken Sie auf Neue Rolle und nennen Sie sie im sich öffnenden Editor
Editor of News. - Klicken Sie auf Neue Richtlinie, wählen Sie das Modul content, die Funktion edit, dann Eingeschränkten Zugriff gewähren, und wählen Sie die Sektion oder den Teilbaum, den die Person bearbeiten darf. Speichern Sie die Rolle mit der Schaltfläche unten.
- Öffnen Sie die Rolle, klicken Sie auf Zuweisen und wählen Sie den Benutzer oder die Gruppe.
- Melden Sie sich in einem privaten Fenster als dieser Benutzer an: Nur die erlaubten Inhalte lassen sich bearbeiten.
Rollen können Dutzende von Richtlinien enthalten; jede Richtlinie zeigt ihre ID, die Spaltenköpfe sortieren die Liste, und der Editor hat Schaltflächen zum Hoch- und Herunterschieben (sie ordnen nur die Liste, die Reihenfolge ändert nie, wer was darf): Reihenfolge der Richtlinien einer Rolle. Eine Rolle, die vielen Benutzern zugewiesen ist, listet sie seitenweise auf, nach Namen sortiert, mit einem Namensfilter, und zeigt Zuweisungen, deren Benutzer oder Gruppe nicht mehr existiert: seitenweise Anzeige der Rollenzuweisungen. Links in der Administration richten sich bereits nach den Berechtigungen, sodass ein Benutzer nie einen Link auf etwas sieht, das abgelehnt würde: Links in der Administration folgen den Berechtigungen.
Eine Bearbeitungsrichtlinie öffnet mehr als den Editor: Wer ein Objekt bearbeiten darf, darf auch dessen Versionen öffnen
(content/history), ohne eine Leserichtlinie dafür zu haben, und sieht dort Nummer, Status, Übersetzung, Ersteller und
Daten jeder Version und kann deren veröffentlichte, archivierte und abgelehnte Versionen vergleichen und kopieren. Der
Entwurf oder die ausstehende Version einer anderen Person bleibt ohne content/versionread verschlossen. Beschränken Sie eine
Bearbeitungsrichtlinie daher so, wie Sie die Leserichtlinie derselben Rolle beschränken: die Versionen
eines Entwurfs.
Verwenden Sie dieselben Regeln in Templates:
if $current_user|has_role( 'Editor' ) ... /if
if $current_user|has_policy( 'content', 'edit' ) ... /ifAlle sieben Operatoren finden Sie unter Rollen- und Richtlinienprüfungen in Templates.
Zwei Faustregeln: Bearbeiten Sie nie die Rolle Administrator, um einem Kollegen etwas mehr zu geben; legen Sie eine neue Rolle an. Und halten Sie die Zahl der Administratoren klein, denn die Vergabe dieser Rolle löst einen Alarm aus (Schritt 3).
3. Das Audit-Protokoll lesen (5 Minuten)
Das Audit ist standardmäßig eingeschaltet. Es zeichnet Anmeldungen und Ablehnungen, Inhaltsänderungen, Schreibvorgänge in Einstellungen, das Leeren von Caches, Bereitstellungen und Bestellungen in einem manipulationssicheren Protokoll auf (jeder Eintrag trägt den Hash des vorherigen).
./console exp:audit status --allow-root-userErwartet: Audit: enabled, dann eine Zeile je Kanal (content, access, system, commerce, read) mit Dateien, Bytes, Einträgen von heute und Chain intact.
Sehen Sie sich die neuesten Anmeldungen an und prüfen Sie, dass nichts verändert wurde:
./console exp:audit tail --channel=access --name='access.session.*' --lines=3 --allow-root-user
./console exp:audit verify --allow-root-userverify gibt je Kanal INTACT aus und endet mit 1, wenn eine Kette unterbrochen ist.
Im Browser: Melden Sie sich als Administrator an, öffnen Sie den Reiter Audit (/audit/dashboard), melden Sie sich ab und wieder an und öffnen Sie Konsole: Ihre Anmeldung ist das neueste access.session.login. Suchen Sie nach Benutzer, IP-Netz oder Text:
./console exp:audit search --name='content.*' --result=refused --limit=10 --allow-root-user
./console exp:audit search --query=login --limit=5 --allow-root-userErledigen Sie Folgendes einmal bei einer neuen Installation:
- Führen Sie die Cronjob-Gruppe
frequentalle paar Minuten aus (php runcronjobs.php frequent); ihr Teilauditindiziert Ereignisse, beliefert Senken, wertet Alarme aus und rotiert, prüft und archiviert einmal täglich. - Prüfen Sie, wer Alarm-Mails erhält:
./console exp:audit alerts recipients --allow-root-user(Voreinstellung: dieAdminEmailder Site). - Listen Sie die Alarmregeln auf:
./console exp:audit alerts list --allow-root-user. Ab Werk überwachen sie Brute-Force-Anmeldungen, die Vergabe einer Administratorrolle, Schreibvorgänge in Einstellungen außerhalb der Arbeitszeit, Massenlöschungen, das Abschalten des Audits und eine unterbrochene Kette. - Sichern Sie
settings/override/audit.ini.append.php: Die Datei enthält die Signatur- und Pseudonym-Schlüssel. - Legen Sie
OnWriteFailurefest (settings/audit.ini [AuditSettings], Voreinstellungcontinue): Mitrefusewerden sicherheitsrelevante Aktionen abgelehnt, solange das Protokoll nicht geschrieben werden kann, sodass nichts ohne Aufzeichnung geschieht.
Wer Einblick hat: Nur die Rolle Administrator hat die Richtlinien audit/read und audit/manage; vergeben Sie audit/read auf die Art von Schritt 2 an eine Auditor-Rolle (optional auf Kanäle beschränkt). Ein Benutzer ohne diese Richtlinie sieht keinen Reiter, und eine eingetippte URL wird abgelehnt und als access.permission.refused aufgezeichnet.
Um Einträge an einen Auditor zu übergeben, öffnen Sie Export mit dem Filter der Konsole: Jetzt herunterladen streamt die Datei
sofort, Im Hintergrund exportieren schreibt einen großen Filter in eine Datei, die Sie später auf derselben Seite herunterladen. Eine Extension
mit einem eigenen Kanal (Exponential Intelligence: der Kanal ai, jede Anfrage an ein Modell und jeder Entwurf, den es
geschrieben hat, nie ein Prompt oder eine Antwort) fügt dem Dashboard ihr Panel und der CSV-Datei ihre Spalten hinzu.
Änderungen an Orten: Das Entfernen eines Orts wird standardmäßig aufgezeichnet (Ort entfernt). Um zu sehen, wer einen Ort
hinzugefügt oder einen anderen Hauptort gewählt hat (Ort hinzugefügt, Hauptort geändert), schalten Sie diese beiden in
settings/override/audit.ini.append.php ein:
[AuditEventSettings]
Enabled[]=content.node.add
Enabled[]=content.node.mainSie erscheinen dann in der Konsole wie jedes Inhaltsereignis, mit dem Objekt, dem Knoten und seinem Elternknoten; beim
Entfernen des Hauptorts wird außerdem aufgezeichnet, welcher Ort zum Hauptort wurde. Die Idee stammt aus LoveStack
(mugoweb/ezpublish-legacy, Commit 9c931192e0), mit Dank an Mugo Web; siehe die
Audit-Referenz, „Location changes“.
Vertiefung: das Audit-Protokoll, Ereignismodell des Audits, Audit-Referenz (bc).
4. Debug-Ausgabe nur für Ihre Adresse (5 Minuten)
Die Debug-Ausgabe zeigt Dateipfade, SQL und Einstellungen; sie darf daher nie für jeden Besucher eingeschaltet sein. Zwei Einstellungen entscheiden, wer sie sieht: DebugOutput ist der Hauptschalter, und mit DebugByIP=enabled erhalten nur die Adressen in DebugIPList[] den Bericht.
Ermitteln Sie Ihre Adresse so, wie der Server sie sieht: Melden Sie sich in der Administration an, öffnen Sie die Exp-Debug-Leiste (sie erscheint, sobald Sie Debug-Ausgaben sehen dürfen), den Reiter Einstellungen, und führen Sie den IP-Test aus. Der Test benötigt die Richtlinie
setup/setup; er nenntREMOTE_ADDR, den passenden Eintrag und Warnungen wielockout,openoderexpired.Sehen Sie nach, woher die Einstellung kommt und was gilt:
./console exp:ini where site.ini/DebugSettings/DebugByIP --allow-root-userSchreiben Sie Ihre Adresse mit einem Ablaufdatum, damit sie sich selbst aufräumt, in
settings/override/site.ini.append.php:[DebugSettings] DebugOutput=enabled DebugByIP=enabled DebugIPList[] DebugIPList[]=203.0.113.7/32 ; My laptop ; expires=2026-12-31T18:00(Verwenden Sie Ihre Adresse; Bezeichnung und Ablaufdatum können entfallen.) Einträge akzeptieren IPv4- und IPv6-Netze (
10.0.0.0/8,2001:db8::/32) sowiecommandlinefür die Shell.Leeren Sie den INI-Cache und laden Sie die Seite neu:
php bin/php/ezcache.php --clear-tag=ini --allow-root-user.
Die Leiste verweigert Schreibvorgänge, die Sie aussperren würden (die Liste enthielte Ihre Adresse nicht) oder Debug für alle öffnen würden (/0, oder DebugByIP aus bei eingeschaltetem DebugOutput), und sie protokolliert jede Änderung und kann sie rückgängig machen; Voreinstellungen (Template-Arbeit, SQL-Tuning, Alles, Aus) schalten ein ganzes Bündel von Einstellungen auf einmal. Schalten Sie auf Aus, wenn Sie fertig sind.
Vertiefung: die Exp-Debug-Leiste, Debug-Leiste (bc), lesbare Debug-Ausgabe.
5. Zwei-Faktor-Anmeldung (optional, 10 Minuten)
Die Extension sevenx_authentication_2fa ergänzt die Anmeldung um TOTP (Google Authenticator, Authy und jede App nach RFC 6238) und Einmalcodes per E-Mail.
Installieren und aktivieren Sie sie:
composer require se7enxweb/sevenx_authentication_2fa# settings/override/site.ini.append.php [ExtensionSettings] ActiveExtensions[]=sevenx_authentication_2fa [UserSettings] ExtensionDirectory[]=sevenx_authentication_2fa LoginHandler[user2fa]=sevenxUser2fa LoginHandler[]=standardDer Standard-Handler muss nach
sevenxUser2fakommen; kommentieren Sie eine ZeileLoginHandler[]=standardinsettings/site.iniaus, wenn die Reihenfolge nicht greift.Aktualisieren Sie:
php bin/php/ezpgenerateautoloads.php -eundphp bin/php/ezcache.php --clear-all --allow-root-user.Vergeben Sie die Richtlinien unter Rollen und Richtlinien (Schritt 2):
user2fa/verifyan die Rolle Anonymous und an jede Rolle, die 2FA verwendet, unduser2fa/setupan die Rollen, die ihre eigene 2FA verwalten.Melden Sie sich an und öffnen Sie
/user2fa/setup: Wählen Sie TOTP, scannen Sie den Code mit Ihrer App (oder tippen Sie das Geheimnis ein) und geben Sie die sechs Ziffern ein. Melden Sie sich ab und wieder an: Nach dem Passwort werden Sie nach dem Code gefragt.Um sie verpflichtend zu machen, setzen Sie
[General] Enforce2FA=enabledinsettings/override/sevenxauthentication2fa.ini.append.php; Benutzer ohne eingerichtete Methode werden auf die Einrichtungsseite geleitet.
Erwartet: Mit einem falschen Code wird die Anmeldung abgelehnt, und das Audit zeigt den fehlgeschlagenen Versuch. Telefon verloren: Der Benutzer kann den E-Mail-Code verwenden, solange AllowEmailFallback auf enabled steht (die Voreinstellung); die Extension hat außerdem eine Oberfläche zum Zurücksetzen der 2FA, die auf ihrer Funktionsseite beschrieben ist. Entfernen Sie abgelaufene Challenges mit php extension/sevenx_authentication_2fa/bin/php/sevenx2facleanup.php (auch ein Cronjob-Skript).
Vertiefung: Zwei-Faktor- und Social-Login (jede Einstellung, Social Login, einen Anbieter hinzufügen).
6. Ein Konto auf seiner Kontoseite prüfen (2 Minuten)
Mein Konto (/user/edit) ist Ihre eigene Kontoseite; /user/edit/<id> ist die eines anderen Benutzers, für einen Administrator,
der diesen Benutzer bearbeiten darf.
- Öffnen Sie
/user/edit. Die obere Karte zeigt Namen, Login, E-Mail-Adresse, Gruppen, Rollen (verlinkt mit den Rollenseiten, sofern Sie diese lesen dürfen), die letzte Anmeldung mit der Zahl der Anmeldungen und wann das Passwort zuletzt geändert wurde (aus dem Audit-Index; „Nicht erfasst“, wenn das Audit kein solches Ereignis hat). Eine Plakette zeigt, ob das Konto Aktiv, Deaktiviert oder Gesperrt ist (zu viele fehlgeschlagene Anmeldungen). - Lesen Sie die Hinweise darüber, die dringendsten zuerst: Das Konto ist deaktiviert oder gesperrt, es gab fehlgeschlagene Anmeldungen seit der letzten erfolgreichen, die zweistufige Anmeldung ist aus, das Passwort ist mit einem alten Verfahren gespeichert (eine Änderung speichert es mit dem aktuellen), das Passwort wurde vor mehr als einem Jahr geändert, das Konto hat sich nie angemeldet.
- Machen Sie von einer Karte aus weiter: Profil (Inhaltsbearbeitung des Benutzers), Passwort, Kontoeinstellungen (aktivieren,
deaktivieren, fehlgeschlagene Anmeldungen zurücksetzen), Zweistufige Anmeldung (
/user2fa/setup, wenn die Extension aktiv ist und die Benutzerklasse ihr Feld hat), API-Schlüssel, Lesezeichen, Benachrichtigungen und E-Mail-Einstellungen. Es werden nur die Karten angezeigt, die Sie öffnen dürfen: Lesezeichen, Benachrichtigungen und die Einrichtung der zweistufigen Anmeldung gehören immer Ihnen selbst, sie stehen daher nicht auf der Seite eines anderen Benutzers; dort öffnet API-Schlüssel/oauthadmin/keys/(user)/<id>und E-Mail-Einstellungen die Administrationsseite dieses Benutzers. - Abbrechen führt zurück zu der Seite, von der Sie kamen.
Erwartet: Ein Administrator sieht auf seiner eigenen Seite jede Karte; ein Redakteur ohne die Richtlinie user/password oder
user/preferences sieht keine Karte Passwort oder Kontoeinstellungen. Für Entwickler: Die Seite ist
design/admin4/templates/user/edit.tpl (dieselbe Datei in design/admin), ihr Stil user/exp_style.tpl und die
Übersicht expUserAccountOverview (getestet in tests/tests/kernel/classes/user/expUserAccountOverviewTest.php).
Für alle Konten auf einmal listet Benutzer > Benutzerkonten prüfen (user/hygiene) diejenigen auf, die sich nie angemeldet haben, seit
N Tagen nicht gesehen wurden, deaktiviert, gesperrt oder verwaist sind oder eine E-Mail-Adresse teilen, deaktiviert, aktiviert oder entsperrt die angehakten
und exportiert die Liste als CSV: Benutzerkonten prüfen.
7. Ein Konto pro Login (2 Minuten)
Bei der Anmeldung wird ein Konto anhand seines Logins ohne Rücksicht auf Groß- und Kleinschreibung gesucht; zwei Konten mit demselben Login (oder mit
Logins, die sich nur in der Schreibweise unterscheiden) können daher nicht beide verwendet werden, und welches antwortet, ist Zufall. Eine neue
Installation hat einen eindeutigen Index auf ezuser.login, sodass die Datenbank selbst die Logins auseinanderhält. Eine aktualisierte Site behält
den einfachen Index, den sie hatte, bis ein Administrator den eindeutigen hinzufügt; das Datenbank-Update tut das nicht, weil es auf einer Site mit
Duplikaten fehlschlagen würde.
Listen Sie die Duplikate auf (ändert nichts):
./console exp:user-login-check --allow-root-userDer Befehl zeigt die Datenbank-Engine, den Index auf
ezuser.loginund je Login, das mehr als ein Konto hat, eine Zeile mit den Inhaltsobjekt-IDs dieser Konten. Logins werden auf ihren ersten Buchstaben und ihre Länge gekürzt;--show-loginszeigt sie vollständig,--jsonliefert dasselbe als JSON. Eine Zeile, die auf „differ only in case“ endet, wird vom Index von PostgreSQL, SQLite, Oracle und MongoDB akzeptiert, die Bytes vergleichen, ist für Exponential aber dennoch dasselbe Login. Auf MySQL und MariaDB entscheidet die Kollation der Spalte; im Auslieferungszustand ignoriert sie Groß- und Kleinschreibung und Leerzeichen am Ende.Lösen Sie jede Zeile von Hand auf: Öffnen Sie die Konten über ihre IDs (
/content/view/full/<node>oder Benutzer), geben Sie einem davon auf seiner Bearbeitungsseite ein neues Login oder entfernen Sie ein Konto, das niemand verwendet.Fügen Sie den eindeutigen Index hinzu, sobald der Bericht sauber ist:
./console exp:user-login-check --fix-index --allow-root-userDer Befehl verweigert das und ändert nichts, solange ein Duplikat aufgeführt wird. Exit-Codes: 0 sauber (oder Index hinzugefügt), 1 Duplikate gefunden (oder Index verweigert), 2 Fehler.
Erwartet: „PASS: every login belongs to one account“ und, nach --fix-index, „Login index ezuser_login (unique)“.
Was Redakteure und Integrationen bemerken: Das Bearbeitungsformular hat ein Login, das ein anderes Konto bereits hat, schon bisher abgelehnt; nun
lehnen es auch ein Kontoentwurf, ein Paketimport, die Zeichenkette login|email|hash|type|enabled der Content-API und eine erste LDAP-Anmeldung ab,
und zwei Anfragen, die gleichzeitig dasselbe Konto anlegen, enden mit einem Konto. Eine erste LDAP-Anmeldung, die dieses Rennen verliert, meldet
sich mit dem Konto an, das die andere Anfrage angelegt hat. Für Entwickler:
expUserLoginIntegrity::duplicates(), indexStatus(), addUniqueIndex(), loginTakenBy() und storeUser()
(kernel/classes/expuserloginintegrity.php, getestet in tests/tests/kernel/classes/expUserLoginIntegrityTest.php).
Die Idee und die Behandlung der Entwürfe stammen aus LoveStack (Mugo Web, Commit 826e1d4647), mit Dank.
Checkliste
- To do: Fünf Sicherheits-Header vorhanden, Punktdateien und PHP-Dateien antworten mit 404
- To do: Setup > Request Shield zeigt, dass der Schutzschild lief, im Durchsetzungsmodus; sein Log in den ersten Tagen gelesen
- To do:
config.phpmit Modus0640, nicht committet; alte Sicherungen invar/backup/entfernt - To do: Erstes Administrator-Passwort geändert
- To do: Rollen enthalten nur, was Personen brauchen; wenige Administratoren
- To do:
exp:audit statuszeigt jede Kette intakt, der Cronjobfrequentläuft, die Alarmempfänger stimmen - To do: Debug-Ausgabe nur für Ihre eigene Adresse, mit Ablaufdatum
- To do: Zwei-Faktor-Anmeldung für Administratoren eingeschaltet
- To do:
exp:user-login-checkmeldet, dass jedes Login zu einem Konto gehört, und der Login-Index ist eindeutig
Demo-Modus im Audit und in den Logs. Solange die Umgebungsvariable EXP_DEMO_MODE=1 gesetzt ist, zeichnet jeder Prozess einmal das Audit-Ereignis system.demo.mode (Warnung, immer eingeschaltet) und eine Zeile demo/mode in var/log/security.log auf, und jede abgelehnte Änderung oder Zurücksetzung eines Administrator-Passworts ist access.user.password.change.failed bzw. access.user.password.reset.failed mit dem Grund demo_mode. Auf einer Site im Produktivbetrieb bedeutet jedes davon, dass die Variable dorthin gelangt ist. Demo-Modus.
Siehe auch
- Die Bedrohungen einzeln, und request-shield davor: Sicherheitshärtung, Request Shield; das Administratorkonto: Das Administrator-Passwort ändern, Das Standard-Administrator-Passwort.
- Eine Site mit Tokens aus Skripten und Apps steuern: Remote-Dienste und Apps.
.htaccessundconfig.phpvon der Konsole, mit maskierten Geheimnissen und Sicherungen: .htaccess und config.php von der Konsole einrichten.- Auswirkungen der Sicherheitsänderungen auf ein Upgrade: Verhaltensänderungen vom 1. und 2. Oktober 2026, Sicherheitshärtung vom August 2026, Changelog 6.0.15.
- Wie es dazu kam: Chronik Oktober 2026, September 2026, zweite Hälfte.
- Weitere Anleitungen: Betrieb einer Site (Logs, Sicherungen, Reparaturen), Extensions (Zwei-Faktor-Anmeldung und andere Extensions), Glossar.
Werden Sie Exponential-Partner
Partner teilen ihre Informationen, stellen Mittel bereit, geben Beiträge zurück und entwickeln die Produkte mit uns, und so wächst Exponential. Eine Partner-Website und ein Dashboard sind für Mitte 2027 geplant: Werden Sie noch heute Partner, damit wir schneller wachsen und neue Funktionen früher liefern.