💡 Esempio completo funzionante disponibile su GitHub:
skip-external-resources-when-signing-dotnet

Introduzione

Un documento Word può contenere un’immagine che non è nel file. Il documento conserva un indirizzo e chiunque lo apra recupera quell’indirizzo. Su un desktop è una funzionalità – l’immagine si aggiorna quando la sorgente lo fa. Su un server che accetta upload, significa che la persona che ti ha inviato il file decide quali URL la tua infrastruttura richiede.

Il caricamento sicuro dei documenti è un comportamento di GroupDocs.Signature per .NET che rifiuta di effettuare tali richieste. Dalla versione 26.9, LoadOptions.SkipExternalResources è impostato di default su true. Questo articolo confronta i tre modi di caricamento sullo stesso documento, mostra come consentire un host senza permettere tutti gli altri e spiega perché la firma di un file non attendibile non richiede alcun accesso alla rete.

Perché è più importante di quanto sembri

L’attacco ha un nome – server‑side request forgery – e tre forme concrete.

Un indirizzo interno non raggiungibile da Internet è raggiungibile dal tuo server, quindi un documento manipolato può far richiedere al tuo servizio http://169.254.169.254/ o un endpoint amministrativo su localhost e, a seconda di cosa fai con il risultato, farlo trapelare. Un percorso UNC in un documento può indurre un host Windows a autenticarsi in uscita, consegnando credenziali a un server controllato dall’attaccante. E un collegamento a un host che semplicemente non risponde blocca il thread di caricamento fino al timeout, un modo economico per esaurire un pool di worker.

Avevo ritenuto che fosse una preoccupazione teorica finché non ho visto un documento di test recuperare un’immagine tramite un servizio che non dovrebbe assolutamente fare richieste in uscita. Nessuna di queste cose richiede un bug nella libreria di documenti. Seguire un collegamento è ciò che il formato richiede; la domanda è solo se il tuo server dovrebbe ottemperare.

Metodo 1 – Il nuovo valore predefinito

Nessun LoadOptions:

using var signature = new Signature(sourcePath);
return SavePagePreview(signature, previewPath);

Non viene recuperato nulla. L’anteprima mostra un segnaposto vuoto dove sarebbe l’immagine collegata, e il PNG è più piccolo di quanto sarebbe altrimenti. Questa differenza di dimensione è la prova più comoda disponibile che nessuna richiesta ha lasciato la macchina.

Quali funzionalità contano come esterne? Immagini collegate anziché incorporate, campi INCLUDEPICTURE, immagini collegate in presentazioni e fogli di calcolo, e le immagini e i fogli di stile a cui fa riferimento un SVG. Il contenuto incorporato rimane intatto – è già nel file.

Metodo 2 – Inserire nella whitelist un indirizzo

Molti documenti collegano a risorse legittime: un CDN aziendale, un server di immagini interno, un archivio di template. Consenti quello e nient’altro:

var loadOptions = new LoadOptions
{
    WhitelistedResources = new List<string> { trustedAddress }
};

using var signature = new Signature(sourcePath, loadOptions);

La regola di corrispondenza merita attenzione. È un test di sottostringa case‑insensitive sull’indirizzo della risorsa, il che significa che un frammento corto è pericoloso: github corrisponde a github.attacker.example/payload.png così come all’host che intendevi. Usa schema, host e percorso – l’esempio inserisce nella whitelist raw.githubusercontent.com/groupdocs-signature/.

Metodo 3 – Consentire tutto

Il comportamento pre‑26.9, ancora disponibile:

var loadOptions = new LoadOptions { SkipExternalResources = false };

Ragionevole per documenti prodotti dalla tua stessa applicazione. Una trappola da segnalare: la proprietà obsoleta LoadExternalResources ha polarità opposta, quindi SkipExternalResources = false è ciò che sostituisce LoadExternalResources = true. Copiando un valore dalla vecchia proprietà, inverti la tua postura di sicurezza senza alcun errore che te lo segnali.

Confronto dei tre metodi: quando usarli

Modalità Ideale per Vantaggi principali Limitazioni
Predefinita (skip) upload da parte degli utenti, e‑mail, file di partner nessuna richiesta in uscita è possibile le immagini collegate vengono visualizzate come segnaposto
Whitelist documenti che collegano a un host di tua proprietà mantiene funzionanti i collegamenti legittimi il confronto di sottostringa richiede un frammento lungo e specifico
Consenti tutto file generati dai tuoi sistemi le anteprime appaiono esattamente come prima ripristina l’esposizione SSRF che la predefinita rimuoveva

La firma ha bisogno delle risorse?

No, e questo è il vantaggio pratico. Una firma QR‑code viene applicata con le impostazioni di caricamento predefinite e nessuna risorsa esterna viene richiesta mentre il documento è caricato, firmato o salvato:

var options = new QrCodeSignOptions("Approved by GroupDocs.Signature")
{
    EncodeType = QrCodeTypes.QR,
    Left = 400,
    Top = 50,
    Width = 120,
    Height = 120
};

SignResult result = signature.Sign(outputPath, options);

L’output firmato mantiene il suo collegamento, quindi un utente che apre il documento in seguito vede ancora l’immagine risolta sulla propria macchina. Saltare la richiesta è una politica lato server, non una modifica al documento – ed è proprio questo a renderla sicura da applicare a file che gestisci per conto di altri.

Cosa cambia con l’aggiornamento

Per la maggior parte dei servizi, nulla di visibile a prima vista, e vale la pena dirlo chiaramente perché una modifica di sicurezza predefinita che cambia comportamento ovunque non supererebbe una revisione di aggiornamento. L’eccezione è ovunque un’anteprima o una miniatura mostrava un’immagine collegata e ora mostra un segnaposto; questo è il cambiamento che fa il suo lavoro, e la soluzione è inserire nella whitelist l’host se è tuo, o accettare il risultato se il documento proviene da fuori.

Il modo più onesto per verificare è quello usato nel campione: renderizzare lo stesso documento in tutti e tre i modi e confrontare le dimensioni dell’output. Se le anteprime predefinite e quelle in whitelist hanno dimensioni identiche, nulla è stato recuperato in entrambi i casi – il che di solito significa che l’host è irraggiungibile dalla macchina piuttosto che che la whitelist abbia fallito, e il campione stampa un suggerimento che lo indica esattamente.

L’aiutante per l’anteprima, poiché non è ovvio

Due dei tre modi sopra chiamano un piccolo helper, e vale la pena mostrarlo perché PreviewOptions non accetta un percorso:

var previewOptions = new PreviewOptions(
    pageData => File.Create(previewPath),
    (pageData, pageStream) => pageStream.Dispose())
{
    PreviewFormat = PreviewOptions.PreviewFormats.PNG
};

signature.GeneratePreview(previewOptions);

Accetta due factory di stream – una per creare uno stream per pagina, l’altra per rilasciarlo. Il documento di esempio ha una sola pagina, quindi viene scritto un file; per input multi‑pagina, inserisci il numero di pagina nel nome del file altrimenti ogni pagina sovrascriverà l’ultima.

Buone pratiche

  • Considera tutto ciò che non hai generato come non attendibile, inclusi i file provenienti da partner con buone posture di sicurezza.
  • Rendi i frammenti della whitelist sufficientemente lunghi da essere univoci e rivedili quando un CDN cambia.
  • Non impostare mai SkipExternalResources con un valore che prima era assegnato a LoadExternalResources.
  • Verifica con le dimensioni dell’output anziché con l’impostazione; una configurazione che sembra corretta e una richiesta che non è avvenuta sono affermazioni diverse.

Dove colloca SVG

Vale la pena evidenziarlo separatamente, perché SVG è sia un formato di upload comune sia un vettore SSRF frequente. Un SVG può fare riferimento a immagini e fogli di stile tramite URL, e questi riferimenti sono risorse esterne secondo la stessa regola – ignorate per impostazione predefinita, inseribili nella whitelist, ripristinabili. Un servizio che accetta avatar o loghi SVG e li rende lato server era esattamente il tipo di sistema che questo cambiamento protegge.

Se la tua pipeline accetta SVG dagli utenti, la predefinita è l’impostazione che desideri, e la whitelist serve per il caso in cui i tuoi template richiedano un foglio di stile condiviso da un host che gestisci.

Conclusione

Il valore predefinito è stato invertito in modo che il comportamento rischioso richieda una decisione esplicita e quello sicuro non richieda nulla. Mantieni la predefinita per input non attendibili, usa whitelist ristrette dove sono coinvolti i tuoi host, e ricorda che la firma stessa non ha mai avuto bisogno della rete. Eseguire il campione su uno dei tuoi documenti richiede un minuto e ti dice, in tre dimensioni di file, esattamente cosa il tuo servizio ha recuperato.

Risorse aggiuntive