feat(help): security topic - 2FA access paths + extension note

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat/v1-foundation
boban 2026-06-19 22:16:37 +02:00
parent d0275db308
commit d60f97413f
3 changed files with 75 additions and 0 deletions

View File

@ -0,0 +1,33 @@
@php
$h = 'font-display text-base font-semibold text-ink';
$p = 'text-sm leading-relaxed text-ink-2';
$li = 'text-sm leading-relaxed text-ink-2';
$code = 'rounded bg-inset px-1.5 py-0.5 font-mono text-[12px] text-accent-text';
@endphp
<div class="space-y-3">
<h3 class="{{ $h }}">Zwei-Faktor-Authentifizierung</h3>
<p class="{{ $p }}">2FA ist optional, aber empfohlen. Du kannst unter <span class="text-ink">Einstellungen Sicherheit</span> einrichten:</p>
<ul class="ml-4 list-disc space-y-1.5">
<li class="{{ $li }}"><span class="text-ink">TOTP</span> (Authenticator-App, z. B. „Google Authenticator") — ein zeitbasierter 6-stelliger Code.</li>
<li class="{{ $li }}"><span class="text-ink">Security-Key</span> (Hardware, z. B. YubiKey) einstecken und einmal tippen.</li>
<li class="{{ $li }}"><span class="text-ink">Backup-Codes</span> einmalige Codes als Notfall-Zugang.</li>
</ul>
</div>
<div class="space-y-3">
<h3 class="{{ $h }}">Wichtig: Zugangswege &amp; welcher Faktor wo funktioniert</h3>
<p class="{{ $p }}">Ein <span class="text-ink">Security-Key (YubiKey) funktioniert nur über die HTTPS-Domain</span> WebAuthn braucht einen sicheren Kontext und die Domain als Kennung (rpId). Über die Domain wird die Security-Key-Anmeldung angeboten und funktioniert.</p>
<p class="{{ $p }}">Über den <span class="text-ink">Bare-IP-/HTTP-Recovery-Weg</span> (<code class="{{ $code }}">http://&lt;Server-IP&gt;</code>) lässt sich <span class="text-ink">nicht</span> per Security-Key anmelden. Dort musst du einen <span class="text-ink">Backup-Code</span> verwenden.</p>
<p class="{{ $p }}"><span class="text-ink">TOTP funktioniert überall</span> auch über Bare-IP/HTTP. Wer TOTP nutzt, braucht für den Bare-IP-Weg <span class="text-ink">keinen</span> Backup-Code.</p>
<ul class="ml-4 list-disc space-y-1.5">
<li class="{{ $li }}">Nutzt du <span class="text-ink">nur</span> einen Security-Key: bewahre die <span class="text-ink">Backup-Codes</span> auf sie sind dein einziger Weg über den Bare-IP-Recovery-Pfad.</li>
<li class="{{ $li }}">Nutzt du (auch) TOTP: du bist auf allen Wegen abgedeckt, ohne Backup-Codes nötig zu haben.</li>
</ul>
</div>
<div class="space-y-3">
<h3 class="{{ $h }}">Passwort-Manager-Erweiterungen (Bitwarden, Kaspersky )</h3>
<p class="{{ $p }}">Browser-Erweiterungen können die Security-Key-Registrierung abfangen und stattdessen „Passkey speichern" anbieten. Clusev fordert korrekt einen Hardware-Schlüssel an (cross-platform, nicht-auffindbar, mit dem Hinweis <code class="{{ $code }}">security-key</code>), aber eine Webseite kann Erweiterungen nicht abschalten.</p>
<p class="{{ $p }}">Lösung: in der Erweiterung die Passkey-Übernahme für diese Seite deaktivieren (z. B. Bitwarden „Nach Passkeys fragen" aus), oder den Schlüssel in einem Browser/Fenster <span class="text-ink">ohne</span> diese Erweiterung registrieren (z. B. ein privates Fenster). Der Login mit dem Schlüssel funktioniert danach auch mit aktiver Erweiterung.</p>
</div>

View File

@ -0,0 +1,33 @@
@php
$h = 'font-display text-base font-semibold text-ink';
$p = 'text-sm leading-relaxed text-ink-2';
$li = 'text-sm leading-relaxed text-ink-2';
$code = 'rounded bg-inset px-1.5 py-0.5 font-mono text-[12px] text-accent-text';
@endphp
<div class="space-y-3">
<h3 class="{{ $h }}">Two-factor authentication</h3>
<p class="{{ $p }}">2FA is optional but recommended. Under <span class="text-ink">Settings Security</span> you can set up:</p>
<ul class="ml-4 list-disc space-y-1.5">
<li class="{{ $li }}"><span class="text-ink">TOTP</span> (authenticator app, e.g. "Google Authenticator") a time-based 6-digit code.</li>
<li class="{{ $li }}"><span class="text-ink">Security key</span> (hardware, e.g. YubiKey) plug in and tap once.</li>
<li class="{{ $li }}"><span class="text-ink">Backup codes</span> (Backup-Code) one-time codes for emergency access.</li>
</ul>
</div>
<div class="space-y-3">
<h3 class="{{ $h }}">Important: access paths &amp; which factor works where</h3>
<p class="{{ $p }}">A <span class="text-ink">security key (YubiKey) only works over the HTTPS domain</span> WebAuthn needs a secure context and the domain as its identifier (rpId). Over the domain, security-key sign-in is offered and works.</p>
<p class="{{ $p }}">Over the <span class="text-ink">bare-IP / HTTP recovery path</span> (<code class="{{ $code }}">http://&lt;server-ip&gt;</code>) you <span class="text-ink">cannot</span> sign in with a security key. There you must use a <span class="text-ink">backup code (Backup-Code)</span>.</p>
<p class="{{ $p }}"><span class="text-ink">TOTP works everywhere</span> including bare-IP/HTTP. If you use TOTP you do <span class="text-ink">not</span> need a backup code for the bare-IP path.</p>
<ul class="ml-4 list-disc space-y-1.5">
<li class="{{ $li }}">If you use <span class="text-ink">only</span> a security key: keep your <span class="text-ink">backup codes</span> they are your only way in over the bare-IP recovery path.</li>
<li class="{{ $li }}">If you (also) use TOTP: you are covered on every path without needing backup codes.</li>
</ul>
</div>
<div class="space-y-3">
<h3 class="{{ $h }}">Password-manager extensions (Bitwarden, Kaspersky )</h3>
<p class="{{ $p }}">Browser extensions can intercept security-key registration and offer to "save a passkey" instead. Clusev correctly requests a hardware key (cross-platform, non-resident, with the <code class="{{ $code }}">security-key</code> hint), but a website cannot disable extensions.</p>
<p class="{{ $p }}">Fix: turn off the extension's passkey handling for this site (e.g. Bitwarden "Ask to save and use passkeys" off), or register the key in a browser/window <span class="text-ink">without</span> that extension (e.g. a private window). Signing in with the key works afterwards even with the extension active.</p>
</div>

View File

@ -46,4 +46,13 @@ class HelpPageTest extends TestCase
->assertSee('TRUSTED_PROXY_CIDR')
->assertDontSee('Zoraxy'); // generic — no product names
}
public function test_security_topic_explains_the_2fa_access_paths(): void
{
$this->actAsAdmin();
Livewire::test(Index::class)
->set('topic', 'security')
->assertSee('Backup-Code')
->assertSee('TOTP');
}
}