💡 Volledig werkend voorbeeld beschikbaar op GitHub:
merge-untrusted-html-uploads-dotnet

Veilig samenvoegen van niet‑vertrouwde HTML‑documenten is een GroupDocs.Merger‑workflow voor .NET die de externe bronnen die een upload referereert – externe URL’s, UNC‑paden en lokale bestanden – weigert, tenzij je ze expliciet toestaat.

De oude manier was pijnlijk

Stel je voor dat je facturatie‑portaal een door de klant geüploade factuur combineert met een leveringsnota van dezelfde bestelling tot één HTML‑document voor archivering. De factuur is platte HTML – een stylesheet‑link, een logo‑afbeelding, een paar alinea’s – maar jij hebt het niet geschreven, de browser of exporttool van de klant wel. Voor GroupDocs.Merger 26.10 laadde de samenvoeging de externe bronnen die de HTML referende – externe stylesheets, externe afbeeldingen, absolute lokale bestandspaden – en er was geen optie om dit te stoppen.

Dat is een probleem zodra de upload niet volledig vertrouwd is. Een stylesheet‑URL kan ook een tracking‑pixel zijn. Een afbeelding‑src kan wijzen naar http://169.254.169.254/latest/meta-data/iam/security-credentials/ – een cloud‑metadata‑adres – en jouw samenvoegstap zou die op verzoek van de uploader ophalen. Een absoluut file:///‑pad werd ook gelezen, zodat een verwijzing naar een andere klant‑upload dat bestand in de samengevoegde output kon trekken.

De werkelijke kosten van blind samenvoegen: een samenvoegtaak die alles ophaalt wat een upload vraagt, maakt van je server een proxy voor SSRF, en een file:///‑referentie wordt een manier voor de samenvoeging van de ene klant om het bestand van een andere klant te lezen.

Er is een betere manier

GroupDocs.Merger for .NET lost dit standaard op. Sinds versie 26.10 stelt elke LoadOptions‑constructor SkipExternalResources = true, en een Merger die zonder load‑options wordt gemaakt, gebruikt diezelfde standaard – er wordt niets extern geladen tenzij je het anders aangeeft.

Vereisten:

  • .NET (een van de vier doel‑frameworks die GroupDocs.Merger for .NET ondersteunt)
  • GroupDocs.Merger for .NET 26.10 of later (verkrijg een tijdelijke licentie)
  • Twee HTML‑documenten om te combineren, waarvan er ten minste één van een bron komt die je niet volledig vertrouwt

Installeer met één commando:

dotnet add package GroupDocs.Merger --version 26.10.0

De nieuwe manier: HTML samenvoegen zonder het te vertrouwen

Zo ziet het samenvoegen van twee HTML‑uploads eruit met de veilige standaardinstellingen, een handler die elke beslissing registreert, en – in een tweede stap – een handler die één vertrouwde asset levert.

Stap 1 - Maak Load Options voor het formaat

LoadOptions heeft geen parameterloze constructor en is sinds 26.10 sealed; het voorbeeld noemt het formaat expliciet.

// LoadOptions(FileType.HTML) already denies everything external by default
var audit = new ResourceAudit();
var loadOptions = new LoadOptions(FileType.HTML) { ExternalResourceHandler = audit };

Stap 2 - Voeg de uploads samen en inspecteer de beslissingen

// Both uploads follow the options of the Merger they are joined to
using (var merger = new Merger(firstUpload, loadOptions))
{
    merger.Join(secondUpload);
    merger.Save(outputPath);
}

foreach (string decision in audit.Decisions)
{
    Console.WriteLine(decision);
}

Belangrijke punten:

  • SkipExternalResources: hier impliciet true, dus elke externe URL, UNC‑pad en lokale bestandsreferentie wordt geweigerd, inclusief een bestand in de eigen map van de upload.
  • Één LoadOptions per samenvoeging: de tweede upload krijgt geen eigen opties – hij erft wat de Merger waarmee hij werd samengevoegd, heeft gekregen.

Stap 3 - Sta precies één vertrouwde bron toe

// Lever de bytes van het logo direct aan in plaats van het via het netwerk op te vragen
var trustedAssets = new Dictionary<string, byte[]>
{
    [logoUrl] = File.ReadAllBytes(logoPath)
};
var audit = new ResourceAudit(trustedAssets);
var loadOptions = new LoadOptions(FileType.HTML) { ExternalResourceHandler = audit };

De OnLoading‑methode van de handler zet args.Skipped = false en args.Data op die bytes wanneer de gevraagde URI overeenkomt, zodat het document het logo krijgt zonder dat GroupDocs.Merger ergens een verzoek doet.

Toen we de standaard‑samenvoeging uitvoerden op de factuur‑ en leveringsnota‑uploads, werden alle zeven externe referenties in beide bestanden geblokkeerd – de externe stylesheet, het externe logo, de metadata‑stijl‑URL, de afbeelding in dezelfde map, een file:///‑pad, een UNC‑pad en een tracking‑URL met query‑string. joined.html behoudt de tekst van beide uploads; een tijdelijke aanduiding staat in plaats van elke geblokkeerde afbeelding. Met de vertrouwde‑logo‑handler toegevoegd, werd het logo supplied en de andere zes blocked.

Zij-aan-zij: Voor en na

Voor (geen optie) Na (GroupDocs.Merger 26.10)
Externe verzoeken Elke referentie automatisch geladen Geweigerd tenzij expliciet toegestaan
Absolute lokale bestandspaden Geladen in de output Geweigerd zoals elke andere referentie
Vertrouwde uitzonderingen Niet nodig – alles geladen Één bron via een handler, of een witgelijste prefix
Foute whitelist‑vermelding Er bestond geen whitelist Afgewezen met ArgumentException bij constructie
Vereiste code Geen manier om laden te beperken Een paar regels op LoadOptions

Het contrast zit in wat mogelijk is, niet alleen in wat handig is: vóór 26.10 bestond er geen instelling die het laden stopte; daarna is weigeren de standaard en elke uitzondering moet expliciet worden gemaakt.

Zal dit HTML breken die al afhankelijk was van het laden van externe afbeeldingen?

Als die HTML nog steeds wordt samengevoegd met de standaard LoadOptions, ja – de afbeeldingen worden niet geladen en een tijdelijke aanduiding neemt hun plaats in de output in. De oplossing is expliciet, geen tijdelijke omweg: lijst de vertrouwde bronnen op in WhitelistedResources, of koppel een IExternalResourceHandler die de specifieke assets levert die je nog wilt renderen. Hoe dan ook blijft de samenvoeging draaien; hij stopt alleen met het ophalen van alles wat je niet hebt genoemd.

Praktijkvoorbeeld: Factuur- en leveringsnota-consolidatie

Een document‑pipeline die door klanten ingediende HTML samenvoegt tot een archiefkopie is precies het scenario dat dit voorbeeldproject modelleert: een factuur‑upload en een leveringsnota van dezelfde bestelling, samengevoegd tot één bestand. Geen van beide uploads is door het eigen team van de pipeline geschreven, dus geen van beide kan als veilig worden beschouwd om letterlijk te lezen. De factuur vermeldt een te betalen bedrag en een klant, Northwind Traders, en bevat een logo‑referentie, een tracking‑stylesheet, een cloud‑metadata‑stijl‑URL, een afbeelding in dezelfde map en een file:///‑pad – zeven externe referenties tussen de twee uploads, waarvan de archiverings‑pipeline geen enkele namens de klant mag ophalen.

Voor de samenvoegtaak live gaat, is het de moeite waard om per documenttype te bepalen of er überhaupt een uitzondering nodig is. Het facturatiescenario van dit voorbeeld had precies één: het eigen logo van het bedrijf, geserveerd vanaf een bestand dat al op schijf staat in plaats van opgehaald te worden van de externe URL die de HTML noemt. Alles andere – de tracking‑stylesheet, het metadata‑adres, het sibling‑bestand, de UNC‑ en file:///‑paden – had geen legitieme reden om opgehaald te worden, dus de standaardinstellingen alleen waren het juiste antwoord.

// Weiger een whitelist‑vermelding die geen absolute URI‑prefix is
var loadOptions = new LoadOptions(FileType.HTML)
{
    WhitelistedResources = new List<string> { "cdn.example.com" }
};

Het doorgeven van een kale hostnaam in plaats van een absolute prefix zoals https://cdn.example.com/brand/ veroorzaakt een uitzondering met de melding Whitelisted resource 'cdn.example.com' must be an absolute URI without a query, fragment or encoded '/', '\' or '.'. (Parameter 'WhitelistedResources') – nog voordat een van beide uploads wordt geopend. Het opvangen van een verkeerd geconfigureerde whitelist bij het opstarten is waardevoller dan het pas later opmerken dat een resource stilletjes niet kon worden geladen in productie.

Wat kun je nog meer doen met GroupDocs.Merger for .NET?

  • Whitelist‑vermeldingen vroeg valideren: een misvormde WhitelistedResources‑vermelding faalt bij de constructie van Merger, zodat controles bij de start van een deployment het vangen vóórdat een document wordt verwerkt.
  • Vertrouwde assets vanaf schijf leveren: IExternalResourceHandler kan een verzoek beantwoorden met bytes die je al hebt, zonder enige netwerktoegang.
  • Één beleid toepassen op elk samengevoegd document: LoadOptions wordt één keer ingesteld op de Merger, en elk later toegevoegd document volgt dezelfde regels.
  • Meer dan alleen HTML dekken: tekstverwerking, HTML/MHTML, presentaties, spreadsheets, SVG‑ en EPUB‑documenten honoreren allemaal dezelfde opties.

Conclusie

HTML die je niet zelf hebt geschreven samenvoegen betekent niet langer dat je alles erin moet vertrouwen. GroupDocs.Merger for .NET weigert externe bronnen standaard sinds versie 26.10, en de twee manieren om een uitzondering toe te staan – een trusted‑asset‑handler en WhitelistedResources – geven je precies zoveel toegang als de pipeline nodig heeft, niets meer.

Klaar om het zelf te proberen?

Aanvullende bronnen