Skip to main content

Security best practices

These rules come from real incidents or from checks made on the Bemba servers. They complement JWT authentication, the password policy and rate limiting.

Accounts​

  • One account per person; never shared credentials, not for an enumerator nor for a contractor.
  • Deactivate an account on the day the person leaves; review every quarter the accounts without a recent sign-in.
  • Minimal role and minimal scope (institution and projects). National registry access is an exception, granted by name.
  • Limit ROLE_ADMIN to two or three people: it bypasses partitioning and holds every permission.
  • Encourage two-factor authentication (TOTP app), available to every user under My profile → Security, and require it for administrators.
  • Never send a password by messaging; prefer the "forgot password" link or the magic link.

Personal data​

The registry holds named data on vulnerable households.

  • Sensitive grievances (sexual exploitation and abuse, sexual harassment) are only visible with plaintes.sensibles_view; grant it to a very small circle.
  • Photos and attachments are only served through signed links valid for 12 hours: do not copy them into shared documents.
  • Excel or CSV exports take data out of partitioning: store them in a protected space and delete them after use.
  • For a test or a demo, use pre-production, never production data copied to a workstation.

Secrets​

  • No secret in the Git repository, in this documentation, in a ticket or in a chat. A secret committed and then "removed" by a new commit remains readable in the history: it must be changed.
  • Secrets live in the environment file read by Compose on each server (~/pch-sig/.env.prod in production) and in backend/.env, all in mode 600. JWT keys are in backend/config/jwt/, private key in mode 600.
  • After a suspected leak, or when someone who had access leaves: apply the rotation procedure docs/ROTATION_SECRETS.md in the repository (database, JWT, SMTP, Anthropic and Cohere API keys, Kobo tokens).

Servers​

RuleStatus
Only 22 (SSH), 80 and 443 published on the Internet, plus 2222 (GitLab SSH, pre-production) and 2525 (SMTP relay, open to the 220 server only)applied; exporters and Loki bound to 127.0.0.1
SSH by key only, fail2ban activeapplied
Always docker compose -f <file>without -f, Compose starts the Symfony skeleton, with a default-password database
Console commands as www-dataa command run as root breaks the cache (500 errors)
Security headers and CSPset by the frontend Nginx, see HTTPS

Logs and audit​

  • User actions (sign-ins, changes, deletions, exports) are under Administration → Audits.
  • Technical logs are kept for one year in Loki, errors go to Sentry. See Logs.
  • Never log a password, a token or a full payment account number; do not paste them into a report.

Backups​

The database is backed up daily and replicated to the recovery host; see Backup for the exact list and the points still open. A backup is only worth something if its restore has been tested: run a restore drill at least once a quarter.

In case of incident​

  1. Contain: deactivate the accounts involved; if a secret leaked, change it immediately.
  2. Cut sessions: emptying the refresh_tokens table signs everyone out within an hour.
  3. Understand: application audit, Loki logs, Traefik logs.
  4. Fix and document: cause, period, data exposed.
  5. Inform UCP-PCH, and the World Bank if beneficiary data may have been exposed.

Regular checks​

FrequencyCheck
DailyAPI health, empty failed e-mail queue, errors in Sentry
Weeklydisk space, backups present, abnormal failed sign-ins in the audit
MonthlyUbuntu and Docker image security updates
Quarterlyaccount and role review, restore drill
Yearlysecrets rotation, review of this page