💡 Voll funktionsfähiges Beispiel auf GitHub verfügbar:
skip-external-resources-when-signing-dotnet

Einführung

Ein Word‑Dokument kann ein Bild enthalten, das nicht in der Datei selbst liegt. Das Dokument enthält eine Adresse, und das Programm, das es öffnet, ruft diese Adresse ab. Auf einem Desktop ist das ein Feature – das Bild wird aktualisiert, wenn die Quelle sich ändert. Auf einem Server, der Uploads akzeptiert, bedeutet das, dass die Person, die Ihnen die Datei geschickt hat, entscheidet, welche URLs Ihre Infrastruktur anfragt.

Sicheres Laden von Dokumenten ist ein Verhalten von GroupDocs.Signature für .NET, das diese Anfragen ablehnt. Ab Version 26.9 ist LoadOptions.SkipExternalResources standardmäßig auf true gesetzt. Dieser Artikel vergleicht die drei Lademodi anhand desselben Dokuments, zeigt, wie man einen Host zulässt, ohne alle zu erlauben, und erklärt, warum das Signieren einer nicht vertrauenswürdigen Datei überhaupt keinen Netzwerkzugriff benötigt.

Warum das wichtiger ist, als es klingt

Der Angriff hat einen Namen – Server‑Side Request Forgery – und drei konkrete Ausprägungen.

Eine interne Adresse, die vom Internet aus nicht erreichbar ist, ist von Ihrem Server aus erreichbar, sodass ein manipuliertes Dokument Ihren Dienst dazu bringen kann, http://169.254.169.254/ oder einen Admin‑Endpunkt auf localhost abzurufen und je nach Weiterverarbeitung das Ergebnis zu leaken. Ein UNC‑Pfad in einem Dokument kann einen Windows‑Host zur ausgehenden Authentifizierung veranlassen und so Anmeldedaten an einen Angreifer‑Server übergeben. Und ein Link zu einem Host, der einfach nie antwortet, blockiert den Ladevorgang, bis er timeoutet, was eine günstige Methode ist, einen Worker‑Pool zu erschöpfen.

Ich hatte das zunächst für ein theoretisches Problem gehalten, bis ich ein Testdokument beobachtete, das ein Bild über einen Dienst zog, der überhaupt keine ausgehenden Anfragen stellen sollte. Keines davon erfordert einen Bug in der Dokumentenbibliothek. Das Folgen eines Links ist das, was das Format verlangt; die Frage ist nur, ob Ihr Server dem nachkommen soll.

Methode 1 – Der neue Standard

Keine LoadOptions überhaupt:

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

Es wird nichts abgerufen. Die Vorschau rendert einen leeren Platzhalter dort, wo das verknüpfte Bild stehen würde, und das PNG ist kleiner, als es sonst wäre. Dieser Größenunterschied ist der praktischste Beweis dafür, dass keine Anfrage die Maschine verlassen hat.

Welche Features zählen als extern? Verknüpfte Bilder statt eingebetteter, INCLUDEPICTURE‑Felder, verknüpfte Bilder in Präsentationen und Tabellenkalkulationen sowie die Bilder und Stylesheets, auf die ein SVG verweist. Eingebettete Inhalte bleiben unverändert – sie befinden sich bereits in der Datei.

Methode 2 – Eine Adresse auf die Whitelist setzen

Viele Dokumente verlinken auf legitime Quellen: ein Unternehmens‑CDN, ein interner Bild‑Server, ein Vorlagen‑Store. Erlauben Sie das und nichts anderes:

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

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

Die passende Regel verdient Aufmerksamkeit. Sie ist ein case‑insensitiver Substring‑Test gegen die Ressourcen‑Adresse, was bedeutet, dass ein kurzer Ausschnitt gefährlich ist: github trifft auf github.attacker.example/payload.png genauso leicht wie auf den von Ihnen beabsichtigten Host. Verwenden Sie ein Schema, einen Host und einen Pfad – das Beispiel whitelisted raw.githubusercontent.com/groupdocs-signature/.

Methode 3 – Alles zulassen

Das Verhalten vor Version 26.9, weiterhin verfügbar:

var loadOptions = new LoadOptions { SkipExternalResources = false };

Sinnvoll für Dokumente, die Ihre eigene Anwendung erzeugt hat. Eine Falle, die es zu erwähnen gilt: Die veraltete Eigenschaft LoadExternalResources hat die entgegengesetzte Polarität, sodass SkipExternalResources = false das ersetzt, was LoadExternalResources = true bedeutet. Kopieren Sie einen Wert von der alten Eigenschaft, invertieren Sie damit unbeabsichtigt Ihre Sicherheitslage, ohne dass ein Hinweis erscheint.

Vergleich der drei Varianten: Wann welche verwenden

Modus Am besten geeignet für Hauptvorteile Einschränkungen
Standard (skip) Benutzer‑Uploads, E‑Mails, Partnerdateien Keine ausgehende Anfrage möglich Verknüpfte Bilder werden als Platzhalter angezeigt
Whitelist Dokumente, die zu einem eigenen Host verlinken Legitime Links bleiben funktionsfähig Substring‑Abgleich erfordert einen langen, spezifischen Ausschnitt
Alle zulassen Dateien, die Ihre eigenen Systeme erzeugt haben Vorschauen sehen exakt wie vorher aus Stellt die SSRF‑Gefährdung wieder her, die der Standard entfernt hat

Braucht das Signieren die Ressourcen?

Nein, und das ist der praktische Nutzen. Eine QR‑Code‑Signatur wird mit den Standard‑Ladeeinstellungen angewendet, und es wird keine externe Ressource abgefragt, während das Dokument geladen, signiert oder gespeichert wird:

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);

Die signierte Ausgabe behält ihren Link, sodass ein Benutzer, der das Dokument später öffnet, das Bild auf seiner eigenen Maschine aufgelöst sieht. Das Überspringen ist eine serverseitige Richtlinie, keine Änderung am Dokument – genau das macht es sicher, auf Dateien anzuwenden, die Sie im Auftrag anderer bearbeiten.

Was ändert sich beim Upgrade?

Für die meisten Dienste ist auf den ersten Blick nichts sichtbar, und das sollte klar gesagt werden, weil ein Sicherheitsstandard, der das Verhalten überall ändert, bei einer Upgrade‑Prüfung nicht überleben würde. Die Ausnahme ist überall dort, wo eine Vorschau oder ein Thumbnail früher ein verknüpftes Bild zeigte und jetzt einen Platzhalter anzeigt; das ist die beabsichtigte Änderung, und die Lösung ist ein Whitelist‑Eintrag, wenn der Host Ihnen gehört, oder die Akzeptanz, wenn das Dokument von außen stammt.

Der einfachste Weg, das zu prüfen, ist der, den das Beispiel verwendet: Rendern Sie dasselbe Dokument in allen drei Modi und vergleichen Sie die Ausgabengrößen. Wenn die Standard‑ und die Whitelist‑Vorschauen identisch groß sind, wurde in keinem Fall etwas abgerufen – was meist bedeutet, dass der Host von dieser Maschine aus nicht erreichbar ist, nicht dass die Whitelist fehlgeschlagen ist, und das Beispiel gibt einen Hinweis aus, der genau das sagt.

Der Preview‑Helper, weil er nicht offensichtlich ist

Zwei der drei Modi oben rufen einen kleinen Helfer auf, und es lohnt sich, ihn zu zeigen, weil PreviewOptions keinen Pfad annimmt:

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

signature.GeneratePreview(previewOptions);

Er nimmt zwei Stream‑Fabriken – eine zum Erzeugen eines Streams pro Seite, eine zum Freigeben. Das Beispiel‑Dokument hat eine einzelne Seite, daher wird eine Datei geschrieben; bei mehrseitigem Input sollte die Seitennummer im Dateinamen stehen, sonst überschreibt jede Seite die vorherige.

Best Practices

  • Behandeln Sie alles, was Sie nicht selbst erzeugt haben, als unzuverlässig, einschließlich Dateien von Partnern mit guter Sicherheitslage.
  • Machen Sie Whitelist‑Fragmente lang genug, um eindeutig zu sein, und überprüfen Sie sie, wenn ein CDN Änderungen vornimmt.
  • Setzen Sie SkipExternalResources niemals aus einem Wert, der zuvor LoadExternalResources zugewiesen wurde.
  • Verifizieren Sie anhand der Ausgabengrößen statt nur anhand der Einstellung; eine scheinbar korrekte Konfiguration und eine nicht erfolgte Anfrage sind unterschiedliche Behauptungen.

Wo das SVG betrifft

Besonders erwähnenswert, weil SVG sowohl ein gängiges Upload‑Format als auch ein häufiger SSRF‑Vektor ist. Ein SVG kann Bilder und Stylesheets per URL referenzieren, und diese Referenzen sind externe Ressourcen nach derselben Regel – standardmäßig übersprungen, whitelist‑fähig, wiederherstellbar. Ein Dienst, der SVG‑Avatare oder Logos akzeptiert und serverseitig rendert, ist genau das Szenario, das diese Änderung schützt.

Wenn Ihre Pipeline SVGs von Benutzern annimmt, ist die Standardeinstellung die, die Sie wollen, und die Whitelist dient dem Fall, dass Ihre eigenen Vorlagen ein gemeinsames Stylesheet von einem von Ihnen betriebenen Host laden.

Fazit

Der Standard wurde umgekehrt, sodass das riskante Verhalten eine explizite Entscheidung erfordert und das sichere nichts. Behalten Sie den Standard für unzuverlässige Eingaben bei, setzen Sie die Whitelist eng dort ein, wo Ihre eigenen Hosts beteiligt sind, und denken Sie daran, dass das Signieren selbst nie das Netzwerk brauchte. Das Ausführen des Beispiels gegen ein eigenes Dokument dauert eine Minute und zeigt Ihnen in drei Dateigrößen genau, was Ihr Service abgerufen hat.

Weitere Ressourcen