Salta ai contenuti

Sicurezza e operatività del pacchetto Laravel di NextPDF

Il pacchetto applica un set fisso di header di risposta, sanifica i nomi dei file scaricati, convalida sul worker i percorsi di output della coda e incapsula le chiamate HTTP all’autorità di marcatura temporale in un client consapevole del rischio di falsificazione delle richieste. Questa pagina illustra il modello delle minacce e la configurazione di distribuzione richiesta per ciascun controllo.

Terminal window
composer require nextpdf/laravel
php artisan vendor:publish --tag=nextpdf-config

Il pacchetto integra un motore PDF in un framework web. Il confine di fiducia è rappresentato dalla richiesta HTTP e dal trasporto della coda. I controlli descritti di seguito riguardano la gestione delle risposte, i payload deserializzati dei job e le chiamate HTTP in uscita verso un’autorità di marcatura temporale.

AssetMinacciaControllo in questo pacchettoConfigurazione di distribuzione richiesta
Risposta HTTP PDFSniffing del content-type, clickjacking, indicizzazioneSet fisso di header impostato da ogni factory PdfResponse generataNessuna; gli header non sono configurabili
Nome del file scaricatoIniezione di header, path traversal in Content-DispositionIl sanificatore dei nomi dei file rimuove separatori, caratteri di controllo e byte nullNessuna; il sanificatore viene sempre eseguito
Percorso di output del job in codaScrittura arbitraria di file tramite payload serializzato manomessoPercorso convalidato in handle() sul workerIndirizzare l’output a un percorso di archiviazione controllato
HTTP TSA in uscitaServer-side request forgery, manomissione del testo in chiaroClient HTTP consapevole del rischio di falsificazione delle richieste; HTTPS imposto a meno che non venga esplicitamente allentatoMantenere tsa.allow_insecure_http = false; applicare il pinning SPKI
Stato condiviso del workerFuga di stato tra richieste nei worker a lunga durataRegistro dei font bloccato; cache delle immagini limitata; documento associato alla factoryImpostare preload_fonts; limitare la memoria a livello di container

Ogni factory PdfResponse imposta un set fisso di header:

  • Cache-Control: private, max-age=0, must-revalidate
  • Pragma: public
  • X-Content-Type-Options: nosniff
  • X-Frame-Options: DENY
  • Content-Security-Policy: default-src 'none'
  • X-Robots-Tag: noindex, nofollow
  • Referrer-Policy: no-referrer

Questi valori sono costanti in PdfResponse. Non sono configurabili. La suite di test del pacchetto verifica ogni header su ciascun metodo factory, incluse le varianti in streaming.

Il nome del file scaricato passa attraverso un sanificatore prima di raggiungere l’header Content-Disposition. Il sanificatore rimuove i separatori di percorso, i caratteri di controllo e i byte null, ed emette un parametro RFC 5987 filename*= per i nomi non ASCII. Un nome di file vuoto diventa document.pdf.

GeneratePdfJob serializza una closure nel trasporto della coda. Il percorso di output viene convalidato all’interno di handle() sul worker, non al momento del dispatch. La convalida rifiuta:

  • i byte null nel percorso,
  • gli schemi degli stream wrapper (ad esempio php://),
  • segmenti di path traversal ..,
  • qualsiasi percorso che non termini con .pdf (senza distinzione tra maiuscole e minuscole).

Ogni rifiuto solleva InvalidArgumentException. La convalida viene eseguita al punto di consumo. Il payload serializzato in un trasporto Redis o database potrebbe essere alterato prima che il worker lo legga. Indirizzare il percorso di output a una directory di archiviazione controllata; non derivarlo da input di richiesta non convalidato.

HTTP in uscita verso un’autorità di marcatura temporale

Sezione intitolata “HTTP in uscita verso un’autorità di marcatura temporale”

Quando è configurata un’autorità di marcatura temporale, il pacchetto associa un Psr\Http\Client\ClientInterface PSR-18. Un client PSR-18 invia una richiesta PSR-7 e restituisce una risposta PSR-7 (PSR-18 §2). Il client associato racchiude un client basato su curl con un livello consapevole del rischio di falsificazione delle richieste che impone HTTPS a meno che tsa.allow_insecure_http non sia esplicitamente impostato su true.

L’autorità di marcatura temporale è una funzionalità del piano Premium. Il pacchetto Core qui documentato associa il client HTTP e il collegamento del client di marcatura temporale; la firma vera e propria richiede nextpdf/premium. Questa pagina non documenta il comportamento dei baseline PAdES oltre il livello B-B; i baseline superiori sono fuori ambito.

Indicazioni operative per l’autorità di marcatura temporale:

  1. Mantenere tsa.allow_insecure_http impostato su false in produzione.
  2. Impostare tsa.pinned_public_keys sugli hash SPKI SHA-256 in base64 del certificato dell’autorità di marcatura temporale (forma RFC 7469).
  3. Mantenere tsa.warn_on_key_rotation impostato su true affinché una modifica dello SPKI venga registrata prima della scadenza del certificato pinnato.
  4. Ricavare tsa.url solo da configurazione attendibile. Se un operatore può impostarlo da un’interfaccia di amministrazione, applicare regole di firewall in uscita o criteri DNS per ridurre l’esposizione al rischio di falsificazione delle richieste.

Usare Psr\Log\LoggerInterface per la diagnostica. Passare un contesto strutturato, non stringhe interpolate. PSR-3 delega l’escaping dei segnaposto all’implementazione del logger e indica ai chiamanti di non eseguire il pre-escaping dei valori di contesto (PSR-3 §1.2). Registrare la classe dell’eccezione, non il messaggio né la traccia, per ridurre i dettagli interni nei log.

resource: config/nextpdf.php (tsa hardening) + src/Laravel/NextPdfServiceProvider.php
<?php
declare(strict_types=1);
// .env — production timestamp-authority hardening
// NEXTPDF_TSA_URL=https://tsa.example.test
// NEXTPDF_TSA_ALLOW_INSECURE_HTTP=false
// NEXTPDF_TSA_WARN_ROTATION=true
return [
'tsa' => [
'url' => env('NEXTPDF_TSA_URL'),
'allow_insecure_http' => env('NEXTPDF_TSA_ALLOW_INSECURE_HTTP', false),
'warn_on_key_rotation' => env('NEXTPDF_TSA_WARN_ROTATION', true),
'pinned_public_keys' => [
// base64 SHA-256 SPKI hashes of the TSA certificate
],
],
];
  • Il set di header di risposta è fisso. Le applicazioni che necessitano di una CSP diversa devono elaborare la risposta a posteriori, dopo che la factory l’ha restituita.
  • La convalida del percorso viene eseguita sul worker. Un percorso errato supera dispatch() e fallisce solo quando il job viene eseguito.
  • tsa.allow_insecure_http = true rimuove l’imposizione di HTTPS e indebolisce l’affidabilità della marcatura temporale. Limitarlo allo sviluppo locale.
  • Il registro dei font viene bloccato dopo il warmup; un tentativo a runtime di registrare un font in un worker di lunga durata viene rifiutato per scelta progettuale.

I controlli di sicurezza sono operazioni su stringhe e array a tempo costante e non aggiungono alcun costo misurabile per richiesta. Il costo operativo predominante è l’analisi dei font al primo utilizzo; precaricare i font all’avvio del worker per evitare la latenza alla prima richiesta.

Questa pagina è il riferimento per il modello delle minacce del pacchetto. I controlli qui descritti sono applicati nel codice sorgente e verificati dalla suite di test. La configurazione di distribuzione a carico dell’operatore è indicata nella tabella del modello delle minacce e nei passaggi relativi all’autorità di marcatura temporale.

DichiarazioneFonteClausolareference_id
Il client PSR-18 invia una richiesta PSR-7, restituisce una risposta PSR-7PSR-18 HTTP Client§2
Il chiamante passa un contesto di log strutturato senza escapingPSR-3 Logger§1.2

Il pinning SPKI RFC 7469 è indicato come forma utilizzata dalla chiave di configurazione tsa.pinned_public_keys; il pacchetto utilizza i valori di pin forniti dall’operatore e non implementa direttamente l’RFC.

La firma PAdES B-B e l’integrazione con l’autorità di marcatura temporale richiedono nextpdf/premium. Si tratta di una funzionalità Enterprise opzionale; il pacchetto Core qui documentato non richiede alcuna modifica al codice per adottarla. Vedere https://nextpdf.dev/get-license/?intent=laravel-signing.

  • /integrations/laravel/configuration/ — ogni chiave TSA, di firma e di coda
  • /integrations/laravel/production-usage/ — pattern di DI e gestione degli errori
  • /integrations/laravel/troubleshooting/ — perché i controlli sul percorso rifiutano l’input
  • /integrations/laravel/boot-and-discovery/ — cicli di vita dei binding nei worker di lunga durata