[FEAT] TLS-DB pre-equip nis2: PDO SSL gated default-OFF + CA (VIGILE 2026-06-10)

database.php: Database::sslOptions() — TLS verso MySQL gated (env DB_SSL=true o
flag-file application/config/.db_ssl_on), DEFAULT OFF. PDO::MYSQL_ATTR_SSL_CA +
VERIFY_SERVER_CERT=false; fail-safe se CA assente (resta in chiaro + log: un
VERIFY=false senza CA connetterebbe in chiaro silenziosamente). Merge con '+'
(preserva chiavi-intere PDO). Default-OFF provato inerte (base + [] === base).

Validato da 2 agenti: runtime app coperto 100% da Database::getInstance (0 raw PDO
in application/); review adversariale = SICURO default-OFF, nessun bug.

.gitignore: flag-file + db-ca.pem. Runbook: docs/TLS_DB_PREEQUIP_NIS2.md.
NB topologia verificata: l'app usa il DB CONTAINER (db->172.21.0.4, 8.0.45), non il
MySQL host -> CA + enforce vanno sul container db (a cura VIGILE).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
DevEnv nis2-agile
2026-06-10 15:36:52 +02:00
co-authored by Claude Opus 4.8
parent 16790d25a4
commit 4d89b1e04b
4 changed files with 211 additions and 0 deletions
+42
View File
@@ -41,6 +41,11 @@ class Database
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci",
];
// TLS-in-transito (VIGILE 2026-06-10) — pre-equip, GATED, DEFAULT OFF.
// Unione con '+' (NON array_merge): preserva le chiavi-intere delle
// opzioni PDO (array_merge le re-indicizzerebbe). Vedi doc VIGILE §14.
$options = $options + self::sslOptions();
try {
self::$instance = new PDO($dsn, DB_USER, DB_PASS, $options);
} catch (PDOException $e) {
@@ -55,6 +60,43 @@ class Database
return self::$instance;
}
/**
* Opzioni PDO per TLS-in-transito verso MySQL (VIGILE 2026-06-10, pre-equip).
*
* GATED, DEFAULT OFF: ritorna [] (nessuna modifica al comportamento attuale)
* a meno che NON sia attivato esplicitamente tramite:
* - env DB_SSL=true (canonico)
* - OPPURE flag-file application/config/.db_ssl_on (robusto anche in
* PHP-FPM dove getenv() puo' non propagare; nessun recreate necessario)
*
* IMPORTANTE (doc VIGILE §11): PHP PDO/mysqlnd NON cifra senza un CA file.
* MYSQL_ATTR_SSL_VERIFY_SERVER_CERT=false DA SOLO connette IN CHIARO. Quindi
* il TLS si attiva solo se il CA e' presente e leggibile; altrimenti si
* resta in chiaro (come oggi) e si logga — MAI una connessione "a meta'".
* CA host self-signed => VERIFY_SERVER_CERT=false (cifra il canale; la
* verifica della CA e' hardening successivo, coordinato con VIGILE).
*
* @return array opzioni PDO SSL (vuoto se disattivato o CA mancante)
*/
private static function sslOptions(): array
{
$enabled = Env::bool('DB_SSL', false) || is_file(__DIR__ . '/.db_ssl_on');
if (!$enabled) {
return [];
}
$ca = Env::get('DB_SSL_CA', __DIR__ . '/db-ca.pem');
if (!$ca || !is_file($ca) || !is_readable($ca)) {
error_log('[Database] DB_SSL attivo ma CA non trovato/leggibile (' . $ca . '): connessione NON cifrata (serve il CA file).');
return [];
}
return [
PDO::MYSQL_ATTR_SSL_CA => $ca,
PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false,
];
}
/**
* Esegue una query con parametri
*/