💡 Exemple complet fonctionnel disponible sur GitHub : merge-untrusted-html-uploads-dotnet

Fusionner en toute sécurité des documents HTML non fiables est un flux de travail GroupDocs.Merger pour .NET qui refuse les ressources externes référencées par un téléchargement – URL distantes, chemins UNC et fichiers locaux – à moins que vous ne les autorisiez explicitement.

L’ancienne méthode était pénible

Imaginez que votre portail de facturation fusionne le téléchargement de facture d’un client avec une note de livraison de la même commande en un seul document HTML pour l’archivage. La facture est du HTML simple – un lien de feuille de style, une image de logo, quelques paragraphes – sauf que vous ne l’avez pas écrite, c’est le navigateur du client ou l’outil d’exportation qui l’a fait. Avant GroupDocs.Merger 26.10, la fusion chargeait les ressources externes référencées par le HTML – feuilles de style distantes, images distantes, chemins de fichiers locaux absolus – et il n’y avait aucune option pour l’empêcher.

C’est un problème dès que le téléchargement n’est pas totalement fiable. Une URL de feuille de style peut aussi être un pixel de suivi. Un src d’image peut pointer vers http://169.254.169.254/latest/meta-data/iam/security-credentials/ – une adresse de métadonnées cloud – et votre étape de fusion la demanderait au nom du téléchargeur. Un chemin absolu file:/// était également lu, de sorte qu’une référence à l’upload d’un autre client pouvait extraire ce fichier dans le résultat fusionné.

Le vrai coût d’une fusion à l’aveugle : un travail de fusion qui récupère tout ce qu’un téléchargement demande transforme votre serveur en proxy pour SSRF, et une référence file:/// en un moyen pour la fusion d’un client de lire le fichier d’un autre client.

Il existe une meilleure façon

GroupDocs.Merger pour .NET corrige cela par défaut. Depuis la version 26.10, chaque constructeur LoadOptions définit SkipExternalResources = true, et un Merger créé sans options de chargement utilise cette même valeur par défaut – aucune ressource externe n’est chargée à moins que vous ne le disiez autrement.

Prérequis :

  • .NET (l’un des quatre frameworks cibles pris en charge par GroupDocs.Merger pour .NET)
  • GroupDocs.Merger pour .NET 26.10 ou ultérieur (obtenir une licence temporaire)
  • Deux documents HTML à joindre, dont au moins un provenant d’une source que vous ne faites pas entièrement confiance

Installer avec une seule commande :

dotnet add package GroupDocs.Merger --version 26.10.0

La nouvelle méthode : fusionner du HTML sans lui faire confiance

Voici à quoi ressemble la jointure de deux téléchargements HTML avec les paramètres sécurisés par défaut, un gestionnaire qui enregistre chaque décision, et – dans un second passage – un gestionnaire qui fournit une ressource fiable.

Étape 1 – Créer les Load Options pour le format

LoadOptions n’a pas de constructeur sans paramètre et est scellé depuis la version 26.10 ; l’exemple indique explicitement le format.

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

Étape 2 – Joindre les téléchargements et inspecter les décisions

// Les deux téléchargements suivent les options du Merger auquel ils sont joints
using (var merger = new Merger(firstUpload, loadOptions))
{
    merger.Join(secondUpload);
    merger.Save(outputPath);
}

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

Points clés :

  • SkipExternalResources : implicitement true ici, donc chaque URL distante, chemin UNC et référence de fichier local sont refusés, y compris un fichier dans le dossier du téléchargement.
  • Un LoadOptions par jointure : le deuxième téléchargement ne reçoit pas ses propres options – il hérite de ce avec lequel le Merger auquel il a été joint a été créé.

Étape 3 – Autoriser exactement une ressource fiable

// Fournir les octets du logo directement au lieu de le demander via le réseau
var trustedAssets = new Dictionary<string, byte[]>
{
    [logoUrl] = File.ReadAllBytes(logoPath)
};
var audit = new ResourceAudit(trustedAssets);
var loadOptions = new LoadOptions(FileType.HTML) { ExternalResourceHandler = audit };

La méthode OnLoading du gestionnaire définit args.Skipped = false et args.Data à ces octets lorsque l’URI demandée correspond, de sorte que le document obtient le logo sans que GroupDocs.Merger ne fasse de requête nulle part.

Lorsque nous avons exécuté la fusion par défaut sur les téléchargements de facture et de note de livraison, les sept références externes des deux fichiers ont été bloquées – la feuille de style distante, le logo distant, l’URL de type métadonnées, l’image du dossier frère, un chemin file:///, un chemin UNC et une URL de suivi avec chaîne de requête. joined.html conserve le texte des deux téléchargements ; un espace réservé remplace chaque image bloquée. Avec le gestionnaire de logo fiable attaché, le logo a été supplied et les six autres sont restés blocked.

Comparaison côte à côte : avant vs. après

Avant (sans option) Après (GroupDocs.Merger 26.10)
Requêtes externes Chaque référence chargée automatiquement Refusées sauf si explicitement autorisées
Chemins de fichiers locaux absolus Chargés dans le résultat Refusés comme toute autre référence
Exceptions de confiance Non nécessaires – tout chargé Une ressource via un gestionnaire, ou un préfixe sur liste blanche
Entrée de liste blanche incorrecte Aucune liste blanche n’existait Rejetée avec ArgumentException lors de la construction
Code requis Aucun moyen de restreindre le chargement Quelques lignes sur LoadOptions

Le contraste réside dans ce qui est possible, pas seulement dans ce qui est pratique : avant la 26.10 il n’y avait aucun paramètre pour arrêter le chargement ; après, le refus est la valeur par défaut et chaque exception est explicite.

Cela va-t-il casser le HTML qui dépendait déjà du chargement d’images distantes ?

Si ce HTML est encore fusionné avec les LoadOptions par défaut, oui – les images ne seront pas chargées, et un espace réservé les remplacera dans le résultat. La solution est explicite, pas une solution de contournement : répertoriez les sources fiables dans WhitelistedResources, ou attachez un IExternalResourceHandler qui fournit les actifs spécifiques que vous souhaitez toujours rendre. Dans les deux cas, la fusion continue ; elle cesse simplement de récupérer tout ce que vous n’avez pas nommé.

Exemple réel : consolidation de facture et de note de livraison

Un pipeline de documents qui fusionne le HTML soumis par le client dans une copie d’archive correspond exactement au scénario modélisé par le projet d’exemple de cette page : un téléchargement de facture et une note de livraison de la même commande, joints en un seul fichier. Aucun des deux téléchargements n’a été écrit par l’équipe du pipeline, donc aucun ne peut être considéré comme sûr à lire littéralement. La facture indique un montant dû et un client, Northwind Traders, et comporte une référence de logo, une feuille de style de suivi, une URL de type métadonnées cloud, une référence d’image du même dossier, et un chemin file:/// – sept références externes entre les deux téléchargements, aucune que le pipeline d’archivage ne devrait récupérer au nom du client.

Avant que le travail de fusion ne soit mis en production, il vaut la peine de décider, type de document par type de document, si une exception est nécessaire. Le scénario de facturation de cet exemple nécessitait exactement une exception : le logo de l’entreprise, servi à partir d’un fichier déjà présent sur le disque plutôt que récupéré depuis l’URL distante indiquée dans le HTML. Tout le reste – la feuille de style de suivi, l’adresse de type métadonnées, le fichier frère, les chemins UNC et file:/// – n’avait aucune raison légitime d’être récupéré, donc les valeurs par défaut seules étaient la bonne réponse.

// Rejeter une entrée de liste blanche qui n’est pas un préfixe d’URI absolu
var loadOptions = new LoadOptions(FileType.HTML)
{
    WhitelistedResources = new List<string> { "cdn.example.com" }
};

Passer un simple nom d’hôte au lieu d’un préfixe absolu comme https://cdn.example.com/brand/ génère une exception, avec le message Whitelisted resource 'cdn.example.com' must be an absolute URI without a query, fragment or encoded '/', '\' or '.'. (Parameter 'WhitelistedResources') – avant même que l’un des téléchargements ne soit ouvert. Détecter une liste blanche mal configurée au démarrage vaut mieux que de la détecter après qu’une ressource a silencieusement échoué à se charger en production.

Que pouvez‑vous faire d’autre avec GroupDocs.Merger pour .NET ?

  • Validate whitelist entries early : une entrée WhitelistedResources mal formée échoue à la construction du Merger, ainsi les vérifications au démarrage du déploiement la détectent avant tout traitement de document.
  • Supply trusted assets from disk : IExternalResourceHandler peut répondre à une requête avec des octets déjà disponibles, sans aucun accès réseau.
  • Apply one policy to every joined document : LoadOptions est défini une fois sur le Merger, et chaque document joint ultérieurement suit les mêmes règles.
  • Cover more than HTML : le traitement de texte, HTML/MHTML, présentations, feuilles de calcul, SVG et documents EPUB respectent tous les mêmes options.

Conclusion

La fusion de HTML que vous n’avez pas écrit ne signifie plus faire confiance à tout ce qu’il contient. GroupDocs.Merger pour .NET refuse les ressources externes par défaut depuis la version 26.10, et les deux moyens d’accorder une exception – un gestionnaire d’actif fiable et WhitelistedResources – vous offrent exactement l’accès dont un pipeline donné a besoin, rien de plus.

Prêt à l’essayer vous‑même ?

Ressources supplémentaires