JustFlows

డాక్యుమెంటేషన్ ప్రస్తుతానికి ఇంగ్లీష్-మాత్రమే. మిగిలిన సైట్ మీ భాషను అనుసరిస్తుంది.

Security

The Security Center, passkeys, signed security advisories, security events, managed headers, CSRF, sessions, the admin URL, file integrity, and signed packages.

14 నిమి చదవబడింది

Admin → Security opens on the Security Center. Passkeys, Header grade, Headers, Advanced, Admin URL, Audit log, File integrity, and Web server are the other pages. Header APIs: GET/PUT /api/security/headers, reset, and POST /api/security/audit (grades a draft). Config is cached briefly (security-headers:config).

Security Center

The Security Center lists the checks this installation can answer, each as Pass, Warning, Fail, Not verified, or Not applicable, and says whether it is a configuration or a deployment check. A passing row is that one check, not a grade for the site.

  • Runtime: the Node.js version, whether a core update is available, debug mode, and whether the install wizard is still open.
  • Accounts: administrators without an authenticator app or a passkey, device sessions, and API keys without an expiry date.
  • Transport: the session cookie policy, the public URL, trusted proxies, and the response-header policy (the result stays on Header grade).
  • Files: file integrity and the web-server setup for uploads.","Advisories: installed core, plugin, and theme versions checked against the signed advisory feed.","Backups: whether automatic backups on the installation root last succeeded and are still running.

Backup readiness warns when the last automatic backup failed or the schedule has stopped running. It never passes, because a finished backup does not prove a restore works, and subsites show it as unknown because schedules live on the root. An update check that has not finished is not reported as up to date. On a multisite installation, a hosted site's Security Center shows only its own checks; installation-wide checks such as the Node.js version, core updates, the install wizard, the session cookie, the public URL, trusted proxies, file integrity, and the web-server setup stay on the main site.

Passkeys

From Justflows 0.4.2, staff and members can sign in with passkeys: a synced passkey (iCloud Keychain, Google Password Manager, a password manager), a device-bound one (Windows Hello, Touch ID), or a hardware security key. Staff add them under Security → Your account, members on their account page. Adding or removing a passkey asks for the current password, and each passkey can be renamed or revoked. Revoking one signs out every other device by default. How people use them is described in Users and roles.

Security → Passkeys sets the policy for each site:

SettingEffect
Allow (default)The role may add passkeys and sign in with them.
RequireThe role must add a passkey. An account without one is sent to add it straight after signing in. Once it has one, a password and an authenticator code are no longer enough; a recovery code still works. The last passkey cannot be removed.
DisallowThe role cannot add passkeys, and existing ones are not accepted.
User verificationPreferred (default) or Required. Passwordless sign-in always requires a PIN or biometric.
AttestationNone (default) does not ask which device made the passkey. Direct verifies packed and fido-u2f statements and enables an AAGUID allow-list. Certificates are not checked against the FIDO Metadata Service, so the list filters by model but does not prove it. Synced passkeys carry no attestation and cannot pass the list.
RP ID and extra originsBy default the RP ID is the hostname the site is served on, and only that origin is accepted. A parent domain lets passkeys work across its subdomains. A passkey only works for the RP ID it was created for, so changing it orphans existing passkeys.

Passkeys are verified on the server with Node's built-in crypto (ES256, EdDSA, and RS256), with no extra dependency. Each challenge is stored, accepted once, and expires after five minutes, and a signature counter that goes backwards is refused. Registration, sign-in, rename, removal, recovery-code regeneration, and policy changes are rate limited and written to the audit log. Migration 0056_webauthn adds the credential and challenge tables. APIs: /api/auth/passkeys for your own passkeys and sign-in, GET/PUT /api/security/passkeys for the policy (administrator).

Behind a reverse proxy

The RP ID and origin come from X-Forwarded-Host and X-Forwarded-Proto, which are trusted only from addresses in TRUST_PROXY. If these are wrong, passkey ceremonies fail with an origin or RP error. The recommended Permissions-Policy now sends publickey-credentials-get=(self); a policy saved with the old shipped value is upgraded when read, but an edited policy that still blocks it stops passkey sign-in.

Security advisories

The Security Center checks installed core, plugin, and theme versions against a signed advisory feed from api.justflows.com. This is separate from update availability: an update notice says a newer version exists, an advisory says your version is affected. The feed is refreshed shortly after boot and then every six hours; opening the page never calls the network.

ResultMeaning
PassA verified, current feed lists nothing that affects this installation. It covers published advisories only.
Warning or failAn advisory applies. High, critical, and withdrawn versions show as a failure.
UnknownNo verified feed is available, or it has expired, so nothing was checked.

The feed is signed with the core release key and checked against the key pinned in core on every read, so the stored copy cannot be edited in place. A feed with a bad signature, one older than the stored feed, and an expired feed are all refused. A withdrawn version is reported with a recovery path, and nothing is changed for you: update to a fixed version, or deactivate the extension until one exists. Deactivating keeps the site's data.

File integrity

Security → File integrity compares each installed plugin and theme with the baseline recorded when it was installed from a trusted package. A changed, removed, or added file is reported, and that extension is not loaded. Reinstall it from a trusted package to restore it. An extension installed before baselines existed stays Not verified and still runs.

Core files are compared with the signed file manifest in the release archive. Uploads, storage, themes, plugins, and installed extensions are left out of that manifest. A development checkout without the manifest stays Not verified.

Web server

Justflows checks every request for an upload in the application: the host, the site, and whether the file is private. A web server that serves /uploads/ straight from disk, or a CDN that caches private files as public, skips that check. Security → Web server on the main site shows the file to copy for Apache, LiteSpeed, nginx, an Apache reverse proxy, Passenger, and Docker, filled in with this installation's port and uploads folder. Justflows refreshes the site-root .htaccess itself while its first line is intact; it never rewrites nginx, a reverse proxy, Passenger, or Docker configuration.

Managed headers

Thirteen headers, each scoped to all / public / admin: CSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, COEP, COOP, CORP, X-Permitted-Cross-Domain-Policies, X-DNS-Prefetch-Control, Origin-Agent-Cluster, X-XSS-Protection. Advanced adds custom headers, removing Server, and JSON export. Plugins can still adjust via http.responseHeaders.

Public CSP is enforced by default

New installs enforce the shipped public Content Security Policy. Themes that need inline scripts or third-party hosts must allow them in Admin → Security. A deliberately saved disabled setting is respected; JF_SECURITY_HEADERS_DISABLED=1 is the recovery override when database access is unavailable.

Request hardening

  • CSRF — double-submit cookie jf_csrf + header x-csrf-token on mutating /api/* except login and install. Tokens rotate with token_version.
  • Sessions — jf_session, HMAC-SHA256, 14 days. Password change, reset, 2FA changes, and logout bump token_version and reject old cookies.
  • Passwords — PBKDF2-SHA256, 310k iterations, minimum 12 characters.
  • 2FA — optional TOTP with encrypted recovery codes. See Users and roles.
  • Login rate limit — 20/IP and 10/email per 15 minutes; exhausted windows lengthen up to 8× and send Retry-After.
  • Express — default x-powered-by off; Justflows sets X-Powered-By: Justflows.
  • Password reset — optional self-service reset by email: single-use SHA-256-hashed tokens, identical responses whether or not the address exists, and per-address and per-IP rate limits. See Users and roles.
  • Correlation IDs — every HTTP response carries one, and sanitized errors are retained in a bounded buffer for Diagnostics.

Multisite and outbound hardening

  • User management stays within your own access. Someone who manages users can assign roles, permissions, and scopes only within what they hold, and cannot change or remove an administrator. Changing, rotating, revoking, or deleting an API key requires that key's access, including its scope, to sit within the caller's own.
  • Unpublished content stays editorial. A read-only role receives published content only. Drafts, archived items, scheduled items, and working revisions are visible to people who can edit that content or who wrote it. Deleting media needs the media delete capability, and site-wide preview needs permission to edit content on that site.
  • Sign-in and recovery fail closed. An authenticator record that cannot be read is not treated as turned off. Each authenticator code and recovery code works once, even when two requests overlap. A password reset changes the password and revokes sessions together, or neither. In production the installation token is required even from a loopback address.
  • Private files stay private. Private storage, update backups, rollback data, and trashed uploads are never served. Uploads have no public filesystem alias, and public upload reads are limited to 600 a minute per address.
  • Outbound requests check the address they connect to. Webhooks, AI providers, and downloads refuse private addresses in every IPv6 form at connection time, and webhook responses are read only up to a small limit.
  • Uploads are bounded. Each site has a limit on uploads in progress, oversized uploads are refused before and while they are read, and image processing runs a few at a time.
  • Sites stay separate. A site that cannot be looked up gets a temporary error instead of another site's content, plugin routes answer only on sites where the plugin is on, and a sign-in only counts on the site it was made for.
  • Packages must be pinned or Marketplace-signed. A signature carried inside a package's own manifest is not trusted.

Admin Content Security Policy

The public site already enforces CSP by default. The admin now has its own enforcing policy as well, graded from the Security screen, because an admin session can install extensions and replace the core. Pre-session pages served by root server.js (/login, /install) also send security headers.

Admin URL

Admin → Security → Admin URL moves the administration entry path off /admin. Reserved paths are rejected, a reachability check with automatic rollback runs before the change sticks, and the old path's behaviour (404 or redirect) is configurable. Staff sign in, request a reset, and reset their password only at <admin path>/login, /forgot-password, and /reset-password, and once the path is moved, /admin/* answers 404. A staff account on the member sign-in page gets exactly the answer a wrong password gets, before any two-factor prompt, so the member pages never confirm a staff account or reveal the admin path. Each site keeps its own admin path. The redirect from a renamed admin address back to the login page is not cached. JF_ADMIN_PATH_RECOVERY is the environment override for proxy or cache recovery, and its instructions show only on the platform site.

Audit log

Admin → Security → Audit log reads the audit_log table (migrations 0008 / 0009). It records sign-ins and failed sign-ins, password changes and resets, 2FA enrolment, account creation, role changes and deletions, plugin/theme/CSS-provider installs and activations, core updates, security-header changes, and public-API toggles. Later releases also record custom-role and per-user access-policy changes, trash / restore / purge, password-reset requests and completions, admin-URL changes, and automatic-update runs. Every change an AI agent or the admin assistant makes is recorded as ai.tool_called (never the arguments), and saving or removing an AI provider key as ai.provider_saved / ai.provider_removed. Passkey registration, sign-in, and policy changes, plugin permission approvals, and backup and restore runs are recorded too. Writes never throw into the action they describe.

Security events

The Security Center opens a focused view of site-scoped security events: authentication, MFA, sessions, API keys, privileges, extensions, updates, integrity, and security configuration, without unrelated content activity. The full audit trail stays available separately. The Settings button on the audit log opens a page for email alerts and retention:

  • Email alerts are opt-in per site. High-value events are sent, redacted, to the site's administration address, at most ten per site per hour. Attempts and failures show in the email delivery log, and events stay in the admin when mail is off.
  • Export downloads up to 5,000 redacted events at a time, without free-form detail, targets, user agents, raw email addresses, or full IP addresses.
  • Retention defaults to 365 days (JF_AUDIT_RETENTION_DAYS) and can be applied from the page. Each site is also capped at 100,000 rows (JF_AUDIT_MAX_ROWS_PER_SITE, 1,000 to 1,000,000); the oldest rows go first.
  • Delete removes a site's security events after you type the exact confirmation phrase, and leaves a marker with the number removed.

Note

Local audit records are not tamper-proof against someone who controls the host or the database. Export important evidence before you clean up after an incident, and store it elsewhere. There is no external security-event sink yet.

Packages and updates

Package authenticity is required by default. A .jfpkg needs a valid Marketplace signature or a digest in JUSTFLOWS_TRUSTED_PACKAGE_DIGESTS; JUSTFLOWS_ALLOW_UNSIGNED_PACKAGES=1 is the explicit legacy escape hatch. Core update digest pinning and HMAC signing are also available — see Configuration. Package and core archives are checked before anything is written: a plugin package is unpacked and parsed in a separate worker that can be stopped, a malformed archive is rejected, and absolute paths, links, special files, duplicate names, and incomplete listings are refused. A core update checks the signature before it extracts."},{"type":"list","items":["New permissions need approval. When a plugin update asks for permissions the installed version does not have, upload, Marketplace install, and manual update show them and stop before the installed version is replaced. Approvals are written to the audit log, and automatic updates wait for a manual update instead of adding permissions themselves.","No downgrades. Manual and automatic Marketplace updates refuse an equal or older version before downloading the archive.","`TRUST_PROXY` names proxies. It accepts false, named ranges such as loopback, and explicit addresses or subnets. true and hop counts are ignored because they can be spoofed; a site still set to one boots on loopback, logs a warning, and the Security Center notes the value is ignored. A proxy on another machine needs its address set, or every visitor appears as that proxy."]