notiziephp.it

Laravel Scalpel analizza il filesystem alla ricerca di prove di intrusione

Traduzione da Laravel News
18 Settembre 2026 Tempo di lettura: 7 minuti
Laravel Scalpel analizza il filesystem alla ricerca di prove di intrusione

Laravel Scalpel è uno scanner di prove di intrusione realizzato da Harry Agustiana. Viene eseguito all'interno di un'applicazione Laravel e controlla il filesystem alla ricerca di segnali come file PHP malevoli, codice offuscato, direttive del server alterate e modifiche rispetto a uno snapshot considerato attendibile.

Strumenti come Ward e Checkpoint ispezionano codice sorgente, configurazione e dipendenze per individuare problemi di sicurezza. Scalpel ha un compito diverso: trovare le prove che i file di un'applicazione in produzione siano già stati aggiunti, modificati o rimossi.

Scanner per il filesystem

Il comando scalpel:scan esegue sei scanner per impostazione predefinita. Cinque ispezionano i file attuali. Lo scanner Baseline Diff li confronta con uno snapshot salvato.

Lo scanner strutturale cerca file PHP eseguibili nelle directory in cui PHP non dovrebbe comparire. Per impostazione predefinita, queste directory sono public/ e storage/. Rileva i file .php e estensioni meno comuni come .phtml, .pht e .phar, insieme a doppie estensioni come shell.php.jpg. Lo scanner permette public/index.php, public/vendor/ e le view compilate e la cache di Laravel per impostazione predefinita. Puoi cambiare le directory analizzate e aggiungere i tuoi file e le tue directory alle allow list.

Lo scanner del codice offuscato controlla i file PHP alla ricerca di pattern comuni da backdoor. Tra questi ci sono eval(base64_decode(...)), l'esecuzione di payload compressi, le chiamate dinamiche a funzioni, la valutazione diretta dell'input della richiesta e lunghe stringhe codificate. Se del codice legittimo genera un risultato, puoi disattivare quel pattern in config/scalpel.php.

Lo scanner .htaccess segnala le mappature di handler e MIME type che consentono al web server di eseguire Python, Perl, CGI o altri script. Segnala inoltre Options +ExecCGI, regole di rewrite che reindirizzano verso URL esterni e direttive PHP come auto_prepend_file. Lo scanner .user.ini segnala direttive PHP per singola directory, tra cui auto_prepend_file, auto_append_file, include_path e disable_functions. Un attaccante può usare auto_prepend_file per eseguire un file nascosto a ogni richiesta.

Lo scanner dell'ambiente segnala un file .env mancante, vuoto o non leggibile, e qualsiasi file .env posizionato sotto public/. Su sistemi Unix-like controlla anche se il file è leggibile da tutti. Segnala un APP_KEY vuoto, poi confronta le chiavi in .env con quelle in .env.example. Questo si sovrappone agli strumenti che controllano le chiavi dell'ambiente su più file, ma Scalpel considera le chiavi inattese o mancanti come possibili prove di intrusione. Quando APP_ENV è production, lo scanner segnala APP_DEBUG=true. L'opzione --production applica questo controllo indipendentemente da ciò che dice APP_ENV e segnala anche APP_ENV=local.

Puoi eseguire tutti gli scanner o selezionarne un sottoinsieme:

php artisan scalpel:scan
php artisan scalpel:scan --only=structural,obfuscated
php artisan scalpel:scan --only=userini

Confronti con la baseline

Il comando scalpel:baseline registra l'hash SHA-256, la dimensione e l'ora di modifica di ogni file incluso. Il comando scalpel:diff confronta poi i file attuali con quel record e segnala i file aggiunti, modificati ed eliminati:

php artisan scalpel:baseline
php artisan scalpel:diff

Crea la baseline solo dopo che l'applicazione si trova in uno stato di cui ti fidi. Finché non esiste una baseline, scalpel:scan e scalpel:diff segnalano un risultato MEDIUM che ti dice di crearne una. Dopo ogni deploy, il progetto suggerisce di eseguire php artisan optimize e poi scalpel:baseline --force per sostituire la vecchia baseline.

Le esclusioni predefinite lasciano fuori percorsi che cambiano di frequente, come log, sessioni, view compilate e storage/app. La directory vendor/ viene saltata dalle scansioni dei contenuti ma resta parte dei confronti con la baseline, quindi un file aggiunto a un pacchetto installato compare comunque nel diff.

Per impostazione predefinita, Scalpel viene eseguito in modalità strict e calcola l'hash di ogni file durante ciascun confronto. L'opzione --fast confronta prima dimensione e ora di modifica del file, poi riutilizza il vecchio hash quando entrambe coincidono. Questo riduce il lavoro di hashing, ma il confronto con la baseline può non rilevare un file modificato quando un attaccante ne preserva dimensione e ora di modifica. Un altro scanner potrebbe comunque segnalare il file in base al suo contenuto o alla sua posizione.

Scalpel può firmare con HMAC le baseline e i report JSON quando SCALPEL_SIGNING_ENABLED è true e SCALPEL_SIGNING_KEY contiene una chiave dedicata che non è la tua APP_KEY. Il comando diff verifica una baseline firmata prima di usarla e segnala una firma non valida o mancante come CRITICAL. Questo rileva una baseline rigenerata senza la chiave di firma, ma non può proteggere la baseline quando un attaccante può leggere quella chiave o modificare lo scanner stesso. Attiva la firma prima di creare la prima baseline. Il comando scalpel:verify controlla la firma di un report JSON salvato.

Una scansione di prova

Ho testato Scalpel 1.9.0 in un'applicazione Laravel 13.31 appena creata. Con i permessi di .env impostati a 0600 e una baseline in essere, la scansione predefinita non ha prodotto risultati.

Ho poi aggiunto quattro fixture innocue: una chiamata eval(base64_decode(...)) dentro un blocco if (false), un file chiamato avatar.php.jpg, una mappatura di handler in .htaccess e un file .user.ini con auto_prepend_file.

Eseguendo i quattro scanner dei contenuti, l'output è rimasto breve:

php artisan scalpel:scan \
--only=structural,obfuscated,htaccess,userini \
--no-banner

Una scansione completa ha restituito nove risultati perché lo scanner della baseline ha segnalato anche i quattro nuovi file e un file routes/web.php modificato.

Lo stesso test ha evidenziato un problema con le impostazioni predefinite da tenere presente in CI. L'esecuzione di php artisan optimize ha compilato le view del framework sotto storage/framework/views. La scansione successiva ha segnalato 100 risultati MEDIUM di variable-variable e due risultati HIGH di backtick in quei file generati. Dopo php artisan optimize:clear e la ricreazione della baseline, la scansione si è completata senza risultati.

Lo scanner strutturale permette la directory delle view compilate di Laravel, ma lo scanner del codice offuscato ne legge comunque il contenuto. Un'applicazione che mette in cache le view in produzione dovrebbe testare questo percorso prima di aggiungere Scalpel a un gate di deployment. Aggiungere storage/framework/views a content_scan_excluded_paths evita quei risultati, al costo di saltare i controlli sui contenuti per ogni view compilata.

Output per la CI ed eventi Laravel

Sia scalpel:scan sia scalpel:diff supportano l'output table, JSON, annotazione GitHub Actions e SARIF. L'opzione --fail-on imposta la severità minima che fa fallire un job CI. Il valore predefinito è HIGH.

php artisan scalpel:scan --format=sarif --fail-on=MEDIUM

Il codice di uscita 0 significa che la scansione è stata completata e non ha trovato nulla. Il codice 1 significa che almeno un risultato è pari o superiore alla severità di --fail-on. Il codice 2 copre i risultati al di sotto di quella severità o una scansione incompleta, così una directory non leggibile non produce uno stato pulito.

Dopo scalpel:scan o scalpel:diff, il pacchetto invia un evento ScanFinished. L'evento contiene i risultati, il comando eseguito (scan o diff) e la durata in millisecondi. Un'applicazione può ascoltare quell'evento e inviare il proprio avviso via mail, Slack o webhook senza analizzare l'output del comando.

Installazione

Laravel Scalpel richiede PHP 8.2 o versione successiva e supporta Laravel dalla 10 alla 13. Installalo con Composer, poi pubblica la sua configurazione:

composer require hryagstn/laravel-scalpel

php artisan vendor:publish --tag=scalpel-config

Lo scanner viene eseguito nello stesso processo e con gli stessi permessi sul filesystem dell'applicazione Laravel. Un attaccante in grado di modificare il codice dell'applicazione potrebbe anche alterare lo scanner o la sua configurazione. Il progetto raccomanda trigger di scansione esterni, directory di codice in sola lettura e l'invio dei risultati a uno storage esterno al server compromesso. Scalpel rileva le prove di un'intrusione; non fornisce protezione firewall o di contenimento.

Puoi consultare il codice sorgente e il riferimento completo dei comandi su GitHub, oppure provare il simulatore di comandi sul sito di Laravel Scalpel.

Condividi su: LinkedIn

Altri articoli recenti