💡 Pełny działający przykład dostępny na GitHubie: merge-untrusted-html-uploads-dotnet
Bezpieczne scalanie niezaufanych dokumentów HTML jest przepływem pracy GroupDocs.Merger dla .NET, który odrzuca zewnętrzne zasoby, do których odwołuje się przesyłka – zdalne adresy URL, ścieżki UNC i pliki lokalne – chyba że wyraźnie je zezwolisz.
Stara metoda była bolesna
Wyobraź sobie, że Twój portal fakturujący scala przesłany przez klienta plik faktury z notą dostawy z tego samego zamówienia w jeden dokument HTML do archiwizacji. Faktura jest zwykłym HTML‑em – odnośnik do arkusza stylów, obraz logo, kilka akapitów – z tym że nie Ty go napisałeś, a przeglądarka klienta lub narzędzie eksportujące. Przed wersją GroupDocs.Merger 26.10 scalanie ładowało zewnętrzne zasoby, do których odwoływał się HTML – zdalne arkusze stylów, zdalne obrazy, bezwzględne ścieżki do plików lokalnych – i nie było możliwości tego zatrzymać.
To jest problem w momencie, gdy przesyłka nie jest w pełni zaufana. URL arkusza stylów może być również pikselem śledzącym. Atrybut src obrazu może wskazywać na http://169.254.169.254/latest/meta-data/iam/security-credentials/ – adres metadanych chmury – i Twój krok scalania wykonałby żądanie w imieniu nadawcy. Bezpośrednia ścieżka file:/// również była odczytywana, więc odwołanie do przesyłki innego klienta mogło wciągnąć ten plik do scalonego wyniku.
Rzeczywisty koszt ślepego scalania: zadanie scalania, które pobiera wszystko, o co prosi przesyłka, zamienia Twój serwer w proxy dla SSRF, a odwołanie
file:///w sposób, w którym scalanie jednego klienta może odczytać plik innego klienta.
Jest lepszy sposób
GroupDocs.Merger dla .NET naprawia to domyślnie. Od wersji 26.10 każdy konstruktor LoadOptions ustawia SkipExternalResources = true, a Merger utworzony bez opcji ładowania używa tego samego domyślnego ustawienia – żadne zewnętrzne zasoby nie są ładowane, chyba że wyraźnie zezwolisz.
Wymagania wstępne:
- .NET (dowolny z czterech docelowych frameworków obsługiwanych przez GroupDocs.Merger dla .NET)
- GroupDocs.Merger dla .NET 26.10 lub nowszy (uzyskaj tymczasową licencję)
- Dwa dokumenty HTML do połączenia, przynajmniej jeden z źródła, któremu nie ufasz w pełni
Instalacja jednym poleceniem:
dotnet add package GroupDocs.Merger --version 26.10.0
Nowy sposób: scalanie HTML bez zaufania
To, jak wygląda łączenie dwóch przesłanych plików HTML przy użyciu bezpiecznych ustawień domyślnych, obsługi rejestrującej każdą decyzję oraz – w drugim przebiegu – obsługi dostarczającej jeden zaufany zasób.
Krok 1 – Utwórz Load Options dla formatu
LoadOptions nie ma konstruktora bez parametrów i jest sealed od wersji 26.10; w przykładzie format jest określony explicite.
// LoadOptions(FileType.HTML) already denies everything external by default
var audit = new ResourceAudit();
var loadOptions = new LoadOptions(FileType.HTML) { ExternalResourceHandler = audit };
Krok 2 – Połącz przesyłki i sprawdź decyzje
// 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);
}
Kluczowe punkty:
SkipExternalResources: domyślnietruew tym przypadku, więc każdy zdalny URL, ścieżka UNC i odwołanie do pliku lokalnego jest odrzucane, w tym plik w własnym folderze przesyłki.- Jedno
LoadOptionsna połączenie: druga przesyłka nie otrzymuje własnych opcji – dziedziczy to, z czym został utworzonyMerger, do którego została dołączona.
Krok 3 – Zezwól dokładnie na jeden zaufany zasób
// Supply the logo's bytes directly instead of requesting it over the network
var trustedAssets = new Dictionary<string, byte[]>
{
[logoUrl] = File.ReadAllBytes(logoPath)
};
var audit = new ResourceAudit(trustedAssets);
var loadOptions = new LoadOptions(FileType.HTML) { ExternalResourceHandler = audit };
Metoda OnLoading obsługi ustawia args.Skipped = false i args.Data na te bajty, gdy żądany URI się zgadza, więc dokument otrzymuje logo bez tego, aby GroupDocs.Merger wykonywał jakiekolwiek żądanie.
Kiedy uruchomiliśmy domyślne scalanie na fakturze i notatce dostawy, wszystkie siedem zewnętrznych odwołań w obu plikach zostało zablokowanych – zdalny arkusz stylów, zdalne logo, adres w stylu metadanych, obraz z folderu sąsiadującego, ścieżka file:///, ścieżka UNC i URL śledzący z ciągiem zapytania. joined.html zachowuje tekst z obu przesyłek; dla każdego zablokowanego obrazu wstawiany jest placeholder. Po podłączeniu obsługi zaufanego logo, logo zostało dostarczone, a pozostałe sześć pozostało zablokowane.
Porównanie: przed i po
| Przed (bez opcji) | Po (GroupDocs.Merger 26.10) | |
|---|---|---|
| Zewnętrzne żądania | Każde odwołanie ładowane automatycznie | Odrzucane, chyba że wyraźnie dozwolone |
| Bezwzględne ścieżki do plików lokalnych | Ładowane do wyniku | Odrzucane jak każde inne odwołanie |
| Zaufane wyjątki | Niepotrzebne – wszystko ładowane | Jeden zasób przez obsługę lub prefiks z białej listy |
| Nieprawidłowy wpis na białej liście | Brak białej listy | Odrzucony z ArgumentException przy konstrukcji |
| Wymagany kod | Brak możliwości ograniczenia ładowania | Kilka linii w LoadOptions |
Kontrast polega na tym, co jest możliwe, a nie tylko na tym, co jest wygodne: przed wersją 26.10 nie było ustawienia, które zatrzymywało ładowanie; po niej odrzucanie jest domyślne, a każdy wyjątek musi być jawny.
Czy to zepsuje HTML, który już zależał od ładowania zdalnych obrazów?
Jeśli ten HTML jest nadal scalany przy użyciu domyślnych LoadOptions, tak – obrazy nie zostaną załadowane, a w ich miejscu w wyniku pojawi się placeholder. Naprawa jest jawna, a nie obejściem: wymień zaufane źródła w WhitelistedResources lub podłącz IExternalResourceHandler, który dostarczy konkretne zasoby, które nadal chcesz renderować. W każdym przypadku scalanie będzie kontynuowane; po prostu przestanie pobierać cokolwiek, czego nie wymieniłeś.
Przykład z życia: konsolidacja faktury i noty dostawy
Pipeline dokumentów, który scala HTML przesłany przez klienta do kopii archiwalnej, dokładnie odzwierciedla scenariusz modelowany w projekcie przykładowym tej strony: przesyłka faktury i noty dostawy z tego samego zamówienia, połączone w jeden plik. Żadna z przesyłek nie została napisana przez zespół pipeline’u, więc nie można ich uznać za bezpieczne do dosłownego odczytu. Faktura podaje kwotę do zapłaty i klienta, Northwind Traders, oraz zawiera odwołanie do logo, arkusza stylów śledzącego, adresu w stylu metadanych chmury, odwołanie do obrazu w tym samym folderze i ścieżkę file:/// – siedem zewnętrznych odwołań między dwoma przesyłkami, z których żadne nie powinno być pobrane przez pipeline archiwizujący w imieniu klienta.
Zanim zadanie scalania zostanie uruchomione, warto zdecydować, typ dokumentu po typie dokumentu, czy w ogóle potrzebny jest jakiś wyjątek. Scenariusz fakturowania w tym przykładzie wymagał dokładnie jednego: własnego logo firmy, serwowanego z pliku już znajdującego się na dysku, a nie pobieranego z zdalnego URL, który podaje HTML. Wszystko inne – arkusz stylów śledzący, adres metadanych, plik sąsiadujący, ścieżki UNC i file:/// – nie miało uzasadnionego powodu, aby być pobrane, więc same domyślne ustawienia były właściwą odpowiedzią.
// Reject a whitelist entry that is not an absolute URI prefix
var loadOptions = new LoadOptions(FileType.HTML)
{
WhitelistedResources = new List<string> { "cdn.example.com" }
};
Przekazanie samej nazwy hosta zamiast bezwzględnego prefiksu URI, takiego jak https://cdn.example.com/brand/, powoduje wyjątek z komunikatem Whitelisted resource 'cdn.example.com' must be an absolute URI without a query, fragment or encoded '/', '\' or '.'. (Parameter 'WhitelistedResources') – zanim którakolwiek z przesyłek zostanie otwarta. Wykrycie niepoprawnie skonfigurowanej białej listy przy starcie jest warte więcej niż wykrycie jej po tym, jak zasób cicho nie załaduje się w produkcji.
Co jeszcze możesz zrobić z GroupDocs.Merger dla .NET?
- Waliduj wpisy białej listy wcześnie: nieprawidłowy wpis
WhitelistedResourcespowoduje błąd przy konstrukcjiMerger, więc kontrole przy uruchamianiu wdrożenia wykrywają go przed przetworzeniem jakiegokolwiek dokumentu. - Dostarczaj zaufane zasoby z dysku:
IExternalResourceHandlermoże odpowiedzieć na żądanie bajtami, które już posiadasz, bez żadnego dostępu do sieci. - Zastosuj jedną politykę do każdego połączonego dokumentu:
LoadOptionsjest ustawiane raz naMerger, a każdy dokument dołączany później podąża za tymi samymi zasadami. - Obsługuj więcej niż HTML: dokumenty edytorskie, HTML/MHTML, prezentacje, arkusze kalkulacyjne, SVG i EPUB respektują te same opcje.
Podsumowanie
Scalanie HTML, którego nie napisałeś, nie oznacza już zaufania wszystkiemu, co w nim jest. GroupDocs.Merger dla .NET od wersji 26.10 domyślnie odrzuca zewnętrzne zasoby, a dwa sposoby przyznania wyjątku – obsługa zaufanego zasobu i WhitelistedResources – dają dokładnie tyle dostępu, ile potrzebuje dany pipeline, nic więcej.
Gotowy, aby wypróbować to samodzielnie?
- Wypróbuj darmową tymczasową licencję
- Przeczytaj jak pominąć ładowanie zewnętrznych zasobów
- Dowiedz się, kiedy GroupDocs.Merger uzyskuje dostęp do sieci
- Przeglądaj przewodnik krok po kroku
- Sprawdź projekt przykładowy na GitHubie(merge-untrusted-html-uploads-dotnet)