Introduzione
Composer è lo strumento più usato nell’ecosistema PHP per installare librerie e gestire le dipendenze di un progetto. Ogni pacchetto esterno, però, può contenere vulnerabilità di sicurezza. Una libreria non aggiornata, una dipendenza indiretta dimenticata o un requisito installato soltanto per lo sviluppo possono aumentare la superficie di attacco dell’applicazione.
In questo tutorial vedremo come integrare controlli di sicurezza nel flusso di lavoro con Composer. Impareremo a usare il comando composer audit, a distinguere le dipendenze di produzione da quelle di sviluppo e a configurare controlli automatici nella pipeline CI. L’obiettivo non è aggiornare tutto indiscriminatamente, ma conoscere il rischio e prendere decisioni consapevoli.
Gli esempi utilizzano un progetto PHP chiamato catalogo, che dipende da un framework e da alcuni strumenti utili durante lo sviluppo.
Codice completo
Questo è un esempio di file composer.json. La sezione require contiene le dipendenze necessarie all’applicazione in produzione, mentre require-dev contiene strumenti utilizzati solo da sviluppatori e test automatici.
{
"name": "esempio/catalogo",
"description": "Applicazione PHP per la gestione di un catalogo",
"type": "project",
"require": {
"php": "^8.2",
"monolog/monolog": "^3.6",
"guzzlehttp/guzzle": "^7.8"
},
"require-dev": {
"phpunit/phpunit": "^11.0",
"phpstan/phpstan": "^1.11"
},
"autoload": {
"psr-4": {
"Catalogo": "src/"
}
},
"scripts": {
"test": "phpunit",
"analisi": "phpstan analyse src",
"sicurezza": "composer audit --locked"
}
} Dopo aver creato o aggiornato il progetto, è possibile installare tutte le dipendenze con:
composer install Per controllare le vulnerabilità note presenti nelle dipendenze bloccate dal progetto, si può eseguire:
composer audit --locked In alternativa, grazie allo script definito nel file JSON:
composer run sicurezza In un ambiente di produzione è generalmente preferibile installare soltanto ciò che serve all’applicazione:
composer install --no-dev --prefer-dist --no-interaction --optimize-autoloader Per aggiornare le dipendenze secondo i vincoli indicati in composer.json e verificare subito il risultato:
composer update
composer audit È anche possibile analizzare una specifica dipendenza prima di introdurla nel progetto:
composer require vendor/pacchetto
composer audit Spiegazione
Il comando composer audit
composer audit confronta le dipendenze del progetto con un archivio di vulnerabilità conosciute. L’analisi considera sia i pacchetti dichiarati direttamente sia le dipendenze indirette, cioè quelle installate da altre librerie.
Il parametro --locked indica di analizzare esattamente le versioni presenti nel file composer.lock. Questo è utile perché il controllo deve rappresentare ciò che verrà realmente installato, non soltanto ciò che sarebbe consentito dai vincoli del file composer.json.
Se Composer trova una vulnerabilità, normalmente mostra il pacchetto interessato, la versione coinvolta e il riferimento all’avviso di sicurezza. A quel punto occorre capire se esiste una versione corretta compatibile con il progetto.
Dipendenze di produzione e di sviluppo
Le dipendenze inserite con composer require finiscono nella sezione require:
composer require monolog/monolog Quelle necessarie soltanto per test, analisi statica o formattazione del codice devono essere installate con --dev:
composer require --dev phpunit/phpunit
composer require --dev phpstan/phpstan La distinzione è importante. In produzione, il comando composer install --no-dev evita di installare strumenti che non servono all’utente finale. Questo riduce lo spazio occupato, accelera il deploy e limita il numero di componenti disponibili sul server.
Analisi automatica nella CI
Un controllo manuale è utile, ma può essere dimenticato. È preferibile eseguire l’audit automaticamente a ogni modifica del progetto. Per esempio, in una pipeline GitHub Actions si può usare questo file:
name: Controlli PHP
on:
push:
pull_request:
jobs:
sicurezza:
runs-on: ubuntu-latest
steps:
- name: Scarica il codice
uses: actions/checkout@v4
- name: Configura PHP
uses: shivammathur/setup-php@v2
with:
php-version: ´8.2´
tools: composer
- name: Installa le dipendenze bloccate
run: composer install --no-interaction --prefer-dist
- name: Controlla le vulnerabilità
run: composer audit --locked Se il comando rileva un problema e restituisce un codice di errore, la pipeline si interrompe. In questo modo una dipendenza vulnerabile non arriva automaticamente nell’ambiente di produzione.
Best practice
- Controlla le dipendenze con regolarità: esegui composer audit almeno a ogni modifica delle dipendenze e nella pipeline di integrazione continua.
- Usa composer.lock: il file deve essere versionato per le applicazioni. In questo modo sviluppo, test e produzione analizzano e installano le stesse versioni.
- Limita le dipendenze: aggiungi una libreria soltanto quando offre un vantaggio concreto. Ogni pacchetto introduce codice da mantenere e controllare.
- Separa produzione e sviluppo: PHPUnit, PHPStan e strumenti simili devono normalmente stare in require-dev.
- Non ignorare gli avvisi senza analisi: un advisory può riguardare una funzionalità non utilizzata, ma questa valutazione deve essere documentata e verificata.
- Aggiorna in modo controllato: esegui gli aggiornamenti in un ramo separato, lancia test e analisi statica, poi revisiona il diff prima del merge.
- Proteggi l’ambiente di produzione: usa --no-dev, --no-interaction e --optimize-autoloader durante il deploy.
Riepilogo
Composer non serve soltanto a scaricare pacchetti: può diventare una parte importante del processo di sicurezza di un progetto PHP. Il comando composer audit consente di individuare vulnerabilità note nelle dipendenze, mentre la corretta separazione tra require e require-dev evita di portare strumenti non necessari in produzione.
Una configurazione efficace combina quattro elementi: dipendenze dichiarate in modo chiaro, file composer.lock versionato, installazioni di produzione con --no-dev e audit automatici nella CI. In questo modo gli aggiornamenti diventano più prevedibili e i problemi di sicurezza vengono individuati prima del rilascio.
