Fix the findings of a full second security audit
Some checks are pending
CI / PHP lint (7.4) (pull_request) Waiting to run
CI / PHP lint (8.0) (pull_request) Waiting to run
CI / PHP lint (8.1) (pull_request) Waiting to run
CI / PHP lint (8.2) (pull_request) Waiting to run
CI / PHP lint (8.3) (pull_request) Waiting to run
CI / PHP lint (8.4) (pull_request) Waiting to run
CI / WordPress Coding Standards (pull_request) Waiting to run
CI / WordPress.org Plugin Check (pull_request) Waiting to run
Some checks are pending
CI / PHP lint (7.4) (pull_request) Waiting to run
CI / PHP lint (8.0) (pull_request) Waiting to run
CI / PHP lint (8.1) (pull_request) Waiting to run
CI / PHP lint (8.2) (pull_request) Waiting to run
CI / PHP lint (8.3) (pull_request) Waiting to run
CI / PHP lint (8.4) (pull_request) Waiting to run
CI / WordPress Coding Standards (pull_request) Waiting to run
CI / WordPress.org Plugin Check (pull_request) Waiting to run
Four-part audit (OIDC/JWT/crypto, user sync, admin UI, login bypasses) with dynamic PoCs against a real WordPress install; every fix is covered by a regression test. Report: docs/security-audit.md, section 6. Critical/High - Multisite: settings, AJAX actions and certificate download require manage_network_options (site admins could sign in as super admin). - Privileged accounts are only linked (sync and first sign-in) via a matching UPN of a member account, never via the settable mail attribute; the sync never changes their e-mail address; e-mail change notifications stay on. - Button-only mode exempts by credential (application passwords, WP-CLI) instead of request context, closing bypasses through xmlrpc.php and REST login handlers; API requests never receive login cookies. - Multi-tenant mode refuses guest/external identities. Medium/Low - Same message for right and wrong passwords; button-only no longer switches off when the connection breaks; server-side fallback cookie expiry; correct fallback key beats IP lockouts; right-most proxy hop; higher start limit; one object ID per account. - Deactivation sets a random password, revokes application passwords and removes the role (restored on reactivation); disabled people are deactivated even when their mail vanished; duplicate bindings handled. - Sync: abort on empty directory answer, no deprovisioning right after a tenant change, atomic run lock, strict photo path validation. - Certificates: key bundles refused, clean re-exported certificate. - Array-safe sanitising, encoded redirect_to, per-action nonces, escaped role lists, no Graph sleeps during sign-in, warnings for public groups, multi-tenant group rules and missing salts, uninstall clears the token. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
791f43a80b
commit
850f0dcd54
18 changed files with 1908 additions and 1270 deletions
29
README.md
29
README.md
|
|
@ -259,8 +259,14 @@ Im Tab *Sicherheit* → **Button-only mode**:
|
|||
|
||||
- Blendet Benutzername/Passwort-Felder und den „Passwort vergessen?“-Link aus.
|
||||
- **Sperrt Passwort-Logins serverseitig**, nicht nur per CSS – auf `wp-login.php` und in jedem eigenen Login-Formular (`authenticate`-Filter).
|
||||
- Application Passwords, REST API, XML-RPC, WP-CLI und Cron sind nicht betroffen. Einzelne Ausnahmen per Filter `m365_login_block_password_login`.
|
||||
- Wird erst aktiv, wenn die Verbindung vollständig konfiguriert ist.
|
||||
- Unterschieden wird nach **Zugangsdaten, nicht nach Anfrage-Typ**: Das normale Passwort wird überall abgelehnt – auch über
|
||||
XML-RPC und in Login-Handlern anderer Plugins, die in `xmlrpc.php` oder einer REST-Anfrage laufen. Application Passwords
|
||||
(REST, XML-RPC) und WP-CLI funktionieren weiter; API-Anfragen bekommen aber nie ein Login-Cookie.
|
||||
- Falsches und richtiges Passwort erhalten dieselbe Meldung (kein Passwort-Orakel).
|
||||
- Einzelne Ausnahmen per Filter `m365_login_block_password_login`.
|
||||
- Bleibt aktiv, auch wenn die Verbindung zu Microsoft kaputtgeht (abgelaufenes Zertifikat, rotierte Salts) – dann gibt es
|
||||
einen roten Hinweis im Backend, und nur der Fallback-Link oder die Konstante helfen. Passwort-Logins schalten sich nie
|
||||
stillschweigend wieder ein.
|
||||
|
||||
**Fallback (Notausgang):** Beim Speichern erzeugt das Plugin einen geheimen Schlüssel und zeigt den Fallback-Link an:
|
||||
|
||||
|
|
@ -298,6 +304,13 @@ Plugins, die `wp-login.php` umbenennen (z. B. WPS Hide Login), sind kompatibel,
|
|||
|
||||
### Benutzer-Sync
|
||||
|
||||
> **Administrator-Konten** (alle mit `manage_options`, `promote_users`, `edit_users` oder Super-Admin) werden nie über das
|
||||
> `mail`-Attribut verknüpft, sondern nur, wenn der **User Principal Name** eines Mitglieds (kein Gast) exakt ihrer
|
||||
> WordPress-E-Mail entspricht – das `mail`-Attribut kann jeder Benutzer- oder Exchange-Admin des Tenants frei setzen, der
|
||||
> UPN nur auf verifizierten Domains. Dieselbe Regel gilt für die erste Microsoft-Anmeldung eines Administrators. Ihre
|
||||
> E-Mail-Adresse ändert der Sync nie automatisch. Bei allen anderen Konten informiert WordPress die alte Adresse über eine
|
||||
> Änderung.
|
||||
|
||||
Tab *Benutzer-Sync*. Legt WordPress-Konten für Microsoft-365-Benutzer an und hält sie aktuell – manuell per Knopfdruck,
|
||||
automatisch per WP-Cron (stündlich, zweimal täglich, täglich) oder per WP-CLI.
|
||||
|
||||
|
|
@ -346,7 +359,9 @@ höchstens 500 pro Lauf, der Rest folgt im nächsten (Filter `m365_login_sync_ph
|
|||
wenn Microsoft ausdrücklich „kein Foto“ meldet. **Abgewählte** Felder und Bilder werden beim nächsten Lauf aus den Profilen
|
||||
entfernt (Vor-, Nach- und Anzeigename bleiben stehen); wird ein Benutzer in WordPress gelöscht, wird auch sein Bild gelöscht.
|
||||
|
||||
**Deaktivierte Konten** können sich überhaupt nicht mehr anmelden – weder per Microsoft noch per Passwort,
|
||||
**Deaktivierte Konten** bekommen ein Zufallspasswort, verlieren ihre Rolle auf der Site (sie wird gemerkt und bei der
|
||||
Reaktivierung zurückgegeben) und alle Application Passwords – so bleiben sie auch gesperrt, wenn das Plugin einmal
|
||||
deaktiviert wird. Sie können sich überhaupt nicht mehr anmelden – weder per Microsoft noch per Passwort,
|
||||
Anwendungspasswort oder bestehender Session (alle Sessions werden beendet). In der Benutzerliste zeigt die Spalte
|
||||
*Microsoft 365* den Status; per Zeilenaktion lassen sich Konten auch von Hand deaktivieren und reaktivieren.
|
||||
|
||||
|
|
@ -474,7 +489,7 @@ add_filter( 'm365_login_sync_protect_user', function ( $protected, WP_User $user
|
|||
// Sicherheitsstopp anheben (Standard: 20 % der verknüpften Konten, mindestens 5)
|
||||
add_filter( 'm365_login_sync_deprovision_limit', fn( $limit, $linked ) => max( 10, $linked * 0.5 ), 10, 2 );
|
||||
|
||||
// Weitere: m365_login_sync_email, m365_login_sync_photo_limit, m365_login_sync_photo_interval
|
||||
// Weitere: m365_login_sync_email, m365_login_sync_photo_limit, m365_login_sync_photo_interval, m365_login_is_privileged_user
|
||||
// Actions: m365_login_sync_user_created, m365_login_sync_finished, m365_login_user_disabled, m365_login_user_enabled
|
||||
```
|
||||
|
||||
|
|
@ -565,12 +580,14 @@ Ja, Tenant auf <code>consumers</code> oder <code>common</code> stellen. Microsof
|
|||
|
||||
<details>
|
||||
<summary><strong>Multisite?</strong></summary>
|
||||
Ja. Einstellungen gelten pro Site; der Benutzer muss Mitglied der Site (oder Super-Admin) sein.
|
||||
Ja. Einstellungen gelten pro Site, dürfen aber **nur von Super-Admins** geändert werden: Sie entscheiden, welche
|
||||
Microsoft-Identität sich als welcher (netzwerkweite) WordPress-Benutzer anmelden darf. Ein Site-Admin könnte sonst einen
|
||||
eigenen Tenant eintragen und sich als Super-Admin anmelden. Der Benutzer muss Mitglied der Site (oder Super-Admin) sein.
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Was passiert beim Deinstallieren?</strong></summary>
|
||||
Einstellungen, Caches (Transients), Sync-Protokoll, Cron-Termin, gespeicherte Profilbilder und die pro Benutzer gespeicherten Plugin-Daten (Objekt-ID, Deaktivierungs-Status) werden entfernt – auch in Multisite. Importierte Konten und übernommene Profilfelder (<code>m365_*</code>) bleiben erhalten. Deaktivierte Konten sind danach wieder aktiv; wer sie sperren will, sollte sie vorher löschen.
|
||||
Einstellungen, Caches (Transients), Sync-Protokoll, Cron-Termin, gespeicherte Profilbilder und die pro Benutzer gespeicherten Plugin-Daten (Objekt-ID, Deaktivierungs-Status) werden entfernt – auch in Multisite. Importierte Konten und übernommene Profilfelder (<code>m365_*</code>) bleiben erhalten. Deaktivierte Konten bleiben ohne Rolle, mit Zufallspasswort und ohne Application Passwords – der Deaktivierungs-Vermerk selbst wird entfernt.
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue