6.6 KiB
Authentication and security design
Threat posture
The service is private and self-hosted but must assume:
- the reverse-proxy endpoint may become internet reachable;
- an authenticated low-privilege account can be malicious;
- imported Markdown and files are untrusted;
- database or backup theft is possible;
- API tokens can leak;
- container compromise must not automatically expose the host.
The complete threat register is in docs/26-threat-model.md.
First-run owner setup
First-run setup is intentionally available without a separate installation code. The endpoint remains a tightly bounded one-time operation:
- Expose only that setup is required.
- Require the new workspace and owner credentials over the setup form.
- Protect the mutation with CSRF validation and a setup-specific rate limit.
- Atomically create installation, workspace, owner and settings.
- Permanently disable first-run registration after successful completion.
- Audit successful completion without recording passwords or tokens.
The setup endpoint must not be exposed through an internet-facing reverse proxy before owner setup is complete. Complete setup over the trusted LAN or HTTPS endpoint, then configure the reverse proxy and create the first backup.
Password authentication
Use ASP.NET Core Identity or an equivalent reviewed implementation.
Policy:
- minimum 12 characters by default;
- allow password-manager generated long passphrases;
- maximum input bound high enough for passphrases;
- no arbitrary composition rules;
- check against a small bundled common-password denylist where feasible without an outbound service;
- adaptive, versioned password hashing;
- transparent rehash on successful login when policy changes;
- generic authentication failure;
- exponential/threshold lockout;
- session/security stamp invalidation after password reset or account disable.
Operator-issued recovery
No email provider is required.
- Administrator or local operator issues a single-use recovery token.
- Token has at least 256 bits of entropy, a short expiry and one-use state.
- Store only a verifier.
- Deliver through an operator-visible channel.
- Prefer a URL fragment so the raw token never enters access logs:
https://knowledge.example/#/recover/<token>. - Client posts the token body to the API.
- Successful reset consumes the token and invalidates sessions.
- Record safe audit metadata.
For the final administrator, provide a documented container operator command that creates a recovery token without database surgery.
Browser sessions
- Secure cookie in HTTPS production.
- HttpOnly.
- SameSite=Lax or stricter based on tested flows.
- Bounded idle and absolute lifetime.
- Session rotation after authentication/privilege change.
- Anti-forgery token on all cookie-authenticated mutations.
- No auth tokens in localStorage.
- Logout invalidates server-side session/security state where implemented.
- Concurrent session view/revocation is desirable in M1.
Authorization
Authorization is workspace- and resource-aware.
- Reader: view/search permitted content.
- Editor: reader plus content/project creation and editing.
- Administrator: editor plus users, imports, backup, retention, audit and service accounts.
- Service account: scopes plus explicitly assigned workspace/content access; no role inheritance.
Rules are enforced in Application use cases and query specifications. Endpoint attributes alone are insufficient.
Tests cover:
- unauthenticated access;
- role escalation;
- object-ID substitution;
- cross-workspace access even though UI exposes one workspace;
- trashed/private content;
- attachment and revision access;
- project context aggregation;
- disabled users and revoked tokens.
Service-account tokens
Format contains a non-secret public ID/prefix and a random secret. Store only a verifier.
- Show once.
- Optional expiry.
- Multiple independently revocable tokens per account.
- Named purpose and last-used time.
- Explicit scopes.
- Immediate revocation.
- Constant-time verification.
- Rate limit failed token authentication.
- Never accept token in query string.
- Never log the authorization header.
A database compromise should not make offline token recovery feasible because secrets are uniform random 256-bit values.
CSRF, CORS and origins
- Browser API is same-origin in production.
- CORS disabled unless a specific trusted integration requires it.
- Anti-forgery for cookie mutation.
- Bearer-token calls do not use cookies.
- Validate configured public/base URL.
- Proxy headers accepted only from configured trusted proxy networks.
- Host filtering enabled.
Content security
Recommended production headers:
- Content-Security-Policy with no unsafe inline script;
frame-ancestors 'none'unless explicitly required;object-src 'none';base-uri 'self';form-action 'self';- HSTS at reverse proxy after HTTPS validation;
- X-Content-Type-Options;
- Referrer-Policy;
- Permissions-Policy.
Rendered Markdown disallows raw HTML and unsafe URLs. Mermaid uses strict mode. Uploads are not served as executable same-origin content.
Secrets and encryption
- Secrets enter through mounted secret files or environment variables.
- ASP.NET data-protection keys persist outside the read-only root filesystem.
- Production data-protection keys should be protected with an operator-managed secret where supported.
- Backup encryption is operator-configurable and must not rely on a key stored only inside the backup.
- API tokens, passwords and bootstrap/recovery secrets are never recoverable from the DB.
- Do not pretend application-level encryption protects against a fully compromised running application; document the threat boundary.
Logging and privacy
Never log:
- passwords;
- raw tokens;
- cookies/session IDs;
- CSRF tokens;
- page bodies by default;
- attachment content;
- full recovery/bootstrap links;
- database connection strings.
Use safe IDs, correlation IDs and redacted structured properties. Audit retention and diagnostic-log retention are separate.
Rate limits and abuse controls
At minimum isolate policies for:
- setup/login/recovery;
- failed bearer authentication;
- global search;
- upload;
- import/export/backup;
- expensive project-context requests.
Return a generic response that does not confirm account/content existence.
Security verification
Release requires:
- dependency vulnerability scan;
- secret scan;
- container scan;
- authorization matrix tests;
- CSRF tests;
- XSS corpus;
- malicious upload/path corpus;
- session/token lifecycle tests;
- security header test;
- non-root/read-only container evidence;
- independent security review.