10_SECURITY.md 5.5 KB

Security

Overview

What the client does, who it trusts, and what stays the project's responsibility.

The token

The instance token is a 64-character hexadecimal value from 32 random bytes. It's the only secret between instance and server.

  • It's shown once when the instance is created. The server stores only the SHA-256 hash and cannot display it again.
  • It lives exclusively in manage-client/config.php.
  • This file does not belong in the repository and does not belong in the release package.
  • If compromise is suspected, in the Manage server go to Instances → "Rotate token". The old token becomes invalid immediately.

    manage-client/config.php
    data/manage/
    

A compromised token allows: downloading releases and uploading backups — so, access to the application code and the ability to use up storage. It does not allow downloading backups or changing releases; both require logging into the Manage server.

Transport

Every request runs over HTTPS. The client uses PHP's default certificate verification; it is not disabled. A server with a self-signed certificate therefore doesn't work without a matching CA bundle on the system — that's intentional.

Redirects are not followed (follow_location => 0). A redirected request fails instead of sending credentials to a different destination.

Trust in the release package

An update deploys someone else's code on the server. That's secured by:

  1. TLS to the Manage server.
  2. Token required for manifest and package — neither is publicly retrievable.
  3. SHA-256 check of size and content against the manifest. On mismatch, the file is deleted and nothing is deployed.
  4. Path check on every ZIP entry against escaping the target directory.
  5. Sanity check via MANAGE_UPDATE_SANITY_PATHS.

The limit of this model: the checksum comes from the same server as the package. Whoever takes over the Manage server can publish a package and the matching checksum. A signature backed by a public key held in the client deliberately doesn't exist — the Manage server has to be secured accordingly.

Backups contain operational data

A backup gets transferred to the Manage server, stored there, and can be downloaded by anyone who logs into the Manage server. It follows that:

  • No credentials in the backup. config.php with database passwords or API keys doesn't belong in MANAGE_BACKUP_SOURCES.
  • If the backup contains personal data — the rule for order or customer data — the same requirements apply to the Manage server as to the application itself: access control, transport encryption, deletion deadlines. Retention on the server is configurable.
  • The S3 target stores archives unencrypted in the bucket. The bucket must be private.

Local directories

These directories must not be reachable over the web:

Path Content
data/manage/backups/ complete operational data
data/manage/updates/ copies of the application files an update overwrote
data/manage/work/ extracted packages during an update
manage-client/config.php instance token

The bundled manage-client/.htaccess locks config.php, lib/ and bin/. For data/, the project's own .htaccess is responsible. On nginx, the matching location rules have to be set by hand — .htaccess has no effect there.

This can be checked directly:

curl -s -o /dev/null -w "%{http_code}\n" https://myproject.example.org/manage-client/config.php
curl -s -o /dev/null -w "%{http_code}\n" https://myproject.example.org/data/manage/backups/

Both must return 403 or 404, never 200.

The UI

ui/panel.php allows deploying updates and downloading backups — it's the application's most powerful page. Because of that:

  • The project must check its login before including it.
  • The panel brings an extra check on $_SESSION["admin_logged_in"].
  • MANAGE_PANEL_SKIP_AUTH_GUARD disables only this extra check. Setting it without checking the login yourself publishes update and backup functions on the network.
  • All forms are CSRF-protected.
  • The download strictly validates the filename, so no arbitrary path can be served.

Where possible, the page should be accessible only to administrators, not to every logged-in user.

Command line

bin/manage-client.php refuses to run over HTTP (a PHP_SAPI check) and is additionally locked via .htaccess. On the server, the file should still avoid living in the public directory tree where that can be helped.

Logs

The client log contains filenames, versions, HTTP status and error messages. Credentials are filtered out: from target configurations, the client only picks up an allowlist of non-sensitive keys; access_key, secret_key, password and the instance token never appear in the log.

Response excerpts from failed uploads are truncated to 500 characters.

Checklist before going live

  • manage-client/config.php is in .gitignore
  • config.php and manage-client/config.php are excluded from the release package
  • data/manage/ is not reachable over the web (checked with curl)
  • manage-client/config.php is not reachable over the web (checked with curl)
  • The panel page requires an administrator login
  • MANAGE_SERVER_URL uses https://
  • No credentials are inside the backup
  • A backup has been downloaded once and its content checked

Next