diff --git a/HANDOFF.md b/HANDOFF.md index 3f2203a..962767e 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -4,7 +4,37 @@ Stato del progetto per chi ci mette mano dopo. Per installazione, deploy e uso quotidiano vedi [README.md](README.md); qui c'è il contesto che il README non può dare: perché le cose sono come sono, e cosa resta aperto. -Ultimo aggiornamento: **12 ottobre 2026** — vedi [Lavori in corso](#lavori-in-corso--12-ottobre-2026-riprendere-da-qui). +Ultimo aggiornamento: **21 ottobre 2026** (rilascio di sicurezza di PHP) — vedi [Sicurezza: PHP](#sicurezza-php-cve-2026-109618--cve-2026-109619-21-ottobre-2026). + +> **Questo è l'HANDOFF di `main` (produzione).** Il 21/10/2026 in produzione +> è andata **solo la correzione di PHP**, scelta dell'utente: le funzioni nuove +> di `dev` (gruppi di servizio e lavori del 20 ottobre) restano sulla demo. +> Il quadro completo e aggiornato del progetto è nell'HANDOFF di `dev`, che +> sostituirà questo quando `dev` verrà portato in produzione. + +--- + +## Sicurezza: PHP CVE-2026-109618 / CVE-2026-109619 (21 ottobre 2026) + +Due esecuzioni di codice da remoto nel core di PHP (CVSS v4 9.2), patch alle +14:00 UTC del 21/10/2026; versione corretta per il nostro ramo: **8.3.36**. +La produzione girava su 8.3.35. Rilasciati su `main` solo i due commit di +sicurezza di `dev` (cherry-pick): + +- `docker/php/Dockerfile`: `ARG PHP_VERSION=8.3.36` e `FROM + php:${PHP_VERSION}-fpm`. Prima era `php:8.3-fpm`, un tag che si sposta ma + che Docker tiene in cache: una ricostruzione senza `--pull` (anche su + Dokploy) poteva riusare la base vulnerabile. Ora una build o prende la + 8.3.36 o fallisce. Test `tests/Unit/VersionePhpTest.php` contro il ritorno a + un tag mobile o a una versione inferiore. +- phpredis da GitHub (`ARG PHPREDIS_VERSION=6.3.0`) invece di `pecl install`: + quel giorno pecl.php.net rispondeva 504 e la build falliva. +- `docker/php/php.ini`: `session.upload_progress.enabled = 0` e + `session.use_strict_mode = 1`, la mitigazione indicata da Sansec in attesa + della patch, da tenere anche dopo (l'applicazione usa le sessioni di + Laravel, in Redis). +- Solo per provare in locale prima che l'immagine sia su Docker Hub: + `PHP_VERSION=8.3.35 docker compose ...` (mai per un deploy). --- diff --git a/docker-compose.yml b/docker-compose.yml index 1a91965..6863347 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,6 +18,10 @@ services: build: context: . dockerfile: docker/php/Dockerfile + # Vuota = la versione fissata nel Dockerfile (ARG PHP_VERSION). Si + # imposta solo per provare in locale una versione diversa. + args: + - PHP_VERSION restart: unless-stopped env_file: .env environment: @@ -46,6 +50,10 @@ services: build: context: . dockerfile: docker/php/Dockerfile + # Vuota = la versione fissata nel Dockerfile (ARG PHP_VERSION). Si + # imposta solo per provare in locale una versione diversa. + args: + - PHP_VERSION restart: unless-stopped user: www-data env_file: .env @@ -89,6 +97,10 @@ services: build: context: . dockerfile: docker/php/Dockerfile + # Vuota = la versione fissata nel Dockerfile (ARG PHP_VERSION). Si + # imposta solo per provare in locale una versione diversa. + args: + - PHP_VERSION restart: unless-stopped user: www-data env_file: .env @@ -207,6 +219,10 @@ services: build: context: . dockerfile: docker/php/Dockerfile + # Vuota = la versione fissata nel Dockerfile (ARG PHP_VERSION). Si + # imposta solo per provare in locale una versione diversa. + args: + - PHP_VERSION # Senza questo si costruirebbe l'immagine di produzione, che essendo # installata senza dipendenze di sviluppo non contiene phpunit. target: test diff --git a/docker/php/Dockerfile b/docker/php/Dockerfile index 382ec10..e891894 100644 --- a/docker/php/Dockerfile +++ b/docker/php/Dockerfile @@ -1,5 +1,21 @@ # syntax=docker/dockerfile:1 +# Versione di PHP, fissata alla patch. Va dichiarata prima del primo FROM per +# poterla usare nel FROM dello stage `base`. +# +# Fissata e non "8.3": quel tag si sposta, ma Docker tiene in cache la base già +# scaricata, e una ricostruzione senza --pull (anche su Dokploy) poteva uscire +# con un PHP vecchio senza che nessuno se ne accorgesse. Con la patch scritta +# qui, una build o prende questa versione o fallisce. +# +# 8.3.36: corregge CVE-2026-109618 e CVE-2026-109619 (esecuzione di codice da +# remoto nel core di PHP, CVSS 9.2, rilascio del 21/10/2026). Non scendere +# sotto. Aggiornala a ogni rilascio di sicurezza del ramo 8.3. +# +# Solo per provare in locale prima che l'immagine corretta sia su Docker Hub: +# PHP_VERSION=8.3.35 docker compose ... (mai per un deploy). +ARG PHP_VERSION=8.3.36 + # ============================================================================= # Stage 1 — PHP dependencies (no dev, production autoloader) # ============================================================================= @@ -65,7 +81,7 @@ RUN npm run build # estensioni e sullo stesso php.ini della produzione: un test che passa qui # non puo' passare grazie a un ambiente diverso da quello vero. # ============================================================================= -FROM php:8.3-fpm AS base +FROM php:${PHP_VERSION}-fpm AS base # nginx + supervisor run in-image alongside php-fpm: a separate nginx container # would need its own copy of public/ plus the storage volume just to serve @@ -76,6 +92,11 @@ FROM php:8.3-fpm AS base # are named per Debian release (libicu72 vs libicu76, libzip4 vs libzip5), so # purging means pinning package names that break whenever the php base image # moves to a new Debian. A few tens of MB is worth not having that breakage. +# +# phpredis si scarica da GitHub, versione fissata, e non con `pecl install`: +# il 21/10/2026, giorno della patch di sicurezza di PHP, pecl.php.net +# rispondeva 504 e la build falliva proprio quando bisognava aggiornare. +ARG PHPREDIS_VERSION=6.3.0 RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ netcat-openbsd \ @@ -101,8 +122,13 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ intl \ zip \ opcache \ - && pecl install redis \ - && docker-php-ext-enable redis \ + && mkdir -p /usr/src/php/ext/redis \ + && curl -fsSL --retry 5 --retry-delay 5 \ + "https://github.com/phpredis/phpredis/archive/refs/tags/${PHPREDIS_VERSION}.tar.gz" \ + | tar xz --strip-components=1 -C /usr/src/php/ext/redis \ + && echo redis >> /usr/src/php-available-exts \ + && docker-php-ext-install -j"$(nproc)" redis \ + && docker-php-source delete \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* diff --git a/tests/Unit/VersionePhpTest.php b/tests/Unit/VersionePhpTest.php new file mode 100644 index 0000000..40a157b --- /dev/null +++ b/tests/Unit/VersionePhpTest.php @@ -0,0 +1,44 @@ +assertMatchesRegularExpression('/^ARG PHP_VERSION=(\d+\.\d+\.\d+)\s*$/m', $this->dockerfile()); + + preg_match('/^ARG PHP_VERSION=(\d+\.\d+\.\d+)\s*$/m', $this->dockerfile(), $trovata); + + $this->assertTrue( + version_compare($trovata[1], self::MINIMA, '>='), + "PHP {$trovata[1]} è vulnerabile a CVE-2026-109618/109619: serve almeno " . self::MINIMA . '.', + ); + } + + public function test_l_immagine_usa_la_versione_fissata_e_non_un_tag_mobile(): void + { + preg_match_all('/^FROM php:(\S+)/m', $this->dockerfile(), $basi); + + $this->assertNotEmpty($basi[1]); + foreach ($basi[1] as $tag) { + $this->assertStringStartsWith('${PHP_VERSION}', $tag, "FROM php:{$tag}: usa ARG PHP_VERSION, non un tag che si sposta."); + } + } +}