You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/web/routes/active/security/+page.svelte

141 lines
5.0 KiB

<script lang="ts">
import Callout from '../_components/Callout.svelte';
import CodeBlock from '../_components/CodeBlock.svelte';
import PageNav from '../_components/PageNav.svelte';
const securityRules = `$auth -> proves identity and binds successful authentication to session
$session -> owns session continuity, refresh, revocation and browser sync
$perm -> decides authorization for an authenticated actor
$cache -> must scope private data by actor, tenant, permissions and locale
$prefs -> owns user preference intent and effective environment-derived values
$storage -> persists non-secret local state and can back the prefs storage bridge
$logger -> receives security diagnostics with redacted payloads`;
const noSecrets = `// Good: store a theme preference
App.storage.entry('theme', 'base').set('forest');
// Bad: never persist secrets in client storage
App.storage.entry('access-token', token).set(token);
App.storage.entry('csrf-token', token).set(token);`;
const csrfFlow = `1. Client asks auth for a CSRF token.
2. Auth returns a short-lived token and helper cookie.
3. Client sends the token in the configured CSRF header.
4. Server validates token, cookie, origin/fetch metadata and expiry.
5. State-changing auth action continues only if validation passes.`;
</script>
<svelte:head>
<title>Security — Active</title>
</svelte:head>
<article class="article">
<header class="breadcrumbs">
<a href="/active">Get Started</a>
<span aria-hidden="true">/</span>
<span>Security</span>
</header>
<h1>Security model</h1>
<p class="lead">
Active treats identity, sessions, permissions, storage and cache as separate security surfaces.
The active client improves UX, but the server layer remains authoritative.
</p>
<Callout variant="warn" title="1.0 security gate">
<p>
Active should not be tagged as <code>1.0</code> until the security release checklist is
closed and documented in <code>docs/SECURITY.md</code>. MFA and production
WebAuthn/passkeys are intentionally outside the stable surface unless the release notes
explicitly include them.
</p>
</Callout>
<h2>Report privately</h2>
<p>
Do not open public issues for suspected vulnerabilities. Use the private advisory flow described
in <code>docs/SECURITY.md</code>. Include the affected module, commit hash, reproduction steps and
whether cookies, tokens, permissions or cross-tenant data are involved.
</p>
<h2>Module boundaries</h2>
<p>
Security-sensitive work starts by choosing the correct owner. Avoid moving authority to the
client just because it is convenient for a page.
</p>
<CodeBlock code={securityRules} lang="text" />
<table>
<thead>
<tr>
<th>Surface</th>
<th>Rule</th>
<th>Failure mode</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>auth</code></td>
<td>Flows are server-side and short-lived.</td>
<td>Login CSRF, stale flow replay, OAuth state confusion.</td>
</tr>
<tr>
<td><code>$session</code></td>
<td>The session cookie is the continuity source.</td>
<td>Session fixation or logout that resurrects state.</td>
</tr>
<tr>
<td><code>perm</code></td>
<td>Authorization decisions are actor and tenant scoped.</td>
<td>Actor A decisions leak into actor B after hydrate.</td>
</tr>
<tr>
<td><code>$cache</code></td>
<td>Private cache entries require explicit scope.</td>
<td>Cross-user, cross-tenant or stale-permission data leaks.</td>
</tr>
<tr>
<td><code>$storage</code></td>
<td>Client storage is not a secret vault.</td>
<td>Tokens readable by script or browser extensions.</td>
</tr>
</tbody>
</table>
<h2>Cookies and CSRF</h2>
<p>
The session cookie belongs to <code>$session</code>. <code>auth</code> owns helper cookies and CSRF validation
for auth actions. Defaults are intentionally strict for the browser case.
</p>
<CodeBlock code={csrfFlow} lang="text" />
<h2>OAuth and PKCE</h2>
<p>
OAuth state and the PKCE verifier are created by <code>startOAuth</code> and persisted in the
server flow. <code>completeOAuth</code> reads the stored verifier, verifies that it still matches
the flow hash and passes it to the provider adapter. The callback does not trust a browser-supplied
verifier.
</p>
<h2>Storage rule</h2>
<p>
Use <code>$storage</code> for drafts and non-secret local state. Use <code>$prefs</code> for
user preference intent. Do not persist access tokens,
refresh tokens, passwords, OTPs or CSRF tokens in client storage.
</p>
<CodeBlock code={noSecrets} lang="ts" />
<h2>Regression requirements</h2>
<ul>
<li>Every security bug fix needs a regression test.</li>
<li>Every exported stable method must work or be removed from the stable surface.</li>
<li>Every memory adapter must warn in production mode.</li>
<li>
Every private cache or permission decision must include an actor, tenant or explicit scope.
</li>
<li>Every public route, cookie, header, event and logger message must come from constants.</li>
</ul>
<PageNav />
</article>

Powered by TurnKey Linux.