Bezpieczeństwo i eksploatacja Artisan
W skrócie
Dział zatytułowany „W skrócie”Mostek renderuje w Chrome potencjalnie niezaufany kod HTML za dwiema niezależnymi barierami sieciowymi i restrykcyjną polityką treści. Piaskownica Chrome na poziomie systemu operacyjnego to odrębny, opcjonalny mechanizm o jasno określonych ograniczeniach. Ta strona dokumentuje tę granicę. Nie twierdzi, że jest ona absolutna.
Przegląd koncepcyjny
Dział zatytułowany „Przegląd koncepcyjny”Renderowanie oznacza wykonanie żądania po stronie serwera: aplikacja przekazuje kod HTML silnikowi przeglądarki, który domyślnie może pobierać zasoby. Gdy niezaufane dane wejściowe sterują pobieraniem zasobów zewnętrznych, ryzykiem jest fałszowanie żądań po stronie serwera (SSRF): wpis Common Weakness Enumeration (CWE) CWE-918 definiuje je jako pobranie przez serwer zawartości podanego adresu URL bez wystarczającej pewności, że żądanie dociera do oczekiwanego miejsca docelowego. SSRF (CWE-918) należy do słabości z listy CWE Top 25. Application Security Verification Standard (ASVS) organizacji Open Worldwide Application Security Project (OWASP) wymaga kontrolowania żądań wychodzących z komponentów serwerowych, zamiast zdawania się na ustawienia domyślne. OWASP SSRF Prevention Cheat Sheet uznaje blokowanie na warstwie sieciowej wywołań do dowolnych miejsc docelowych za silny mechanizm kontroli. Opisana poniżej konfiguracja sieciowa z domyślną odmową jest odpowiedzią mostka na to wymaganie. National Institute of Standards and Technology (NIST) Special Publication (SP) 800-53 SC-7 opisuje tę samą zasadę granicy: „odmów wszystkiego, zezwalaj na wyjątki”, którą mostek stosuje na warstwie transportowej.
Rezydencja danych i ograniczanie ryzyka związanego z danymi osobowymi
Dział zatytułowany „Rezydencja danych i ograniczanie ryzyka związanego z danymi osobowymi”Kod HTML przekazany do mostka jest przetwarzany w całości w ramach procesu i lokalnej instancji Chrome. Mostek nie wykonuje żadnych własnych wychodzących żądań sieciowych i uniemożliwia Chrome wykonywanie takich żądań (zobacz model sieciowy poniżej), więc treść wejściowa nie opuszcza hosta przez mechanizm renderujący. Dane osobowe (PII) zawarte w danych wejściowych są renderowane do tworzonego wyjściowego pliku Portable Document Format (PDF), dlatego do danych wyjściowych stosuj takie same mechanizmy kontroli rezydencji jak do danych wejściowych. Mostek nie utrwala danych wejściowych ani wyjściowych na dysku; utrwalanie należy do obowiązków wywołującego.
Bezpieczna telemetria i czyszczenie dzienników
Dział zatytułowany „Bezpieczna telemetria i czyszczenie dzienników”ChromeHtmlRenderer i BrowserPool przyjmują opcjonalny LoggerInterface zgodny z PHP Standard Recommendation (PSR)-3. Mostek rejestruje wyłącznie metadane operacyjne: długość wejścia w bajtach, docelową szerokość i wysokość, długość wyjścia w bajtach, zmierzoną wysokość treści, uruchomienie przeglądarki ze skonfigurowaną ścieżką pliku binarnego, powiadomienia o ponownym uruchomieniu z liczbą renderowań oraz zdarzenia zamknięcia. Nie rejestruje treści HTML, renderowanych bajtów ani wyodrębnionego tekstu. Jest to zgodne z wytycznymi NIST SP 800-92: należy rejestrować zdarzenia operacyjne, ale nie zapisywać w dziennikach danych wrażliwych. Ścieżka pliku binarnego jest rejestrowana. Traktuj ją jako niewrażliwe metadane wdrożenia. Testy potwierdzają kształty wywołań rejestrujących w tests/Unit/Artisan/ChromeHtmlRendererTest.php::renderLogsDebugWithSizeWidthHeightAndPdfSize oraz tests/Unit/Artisan/BrowserPoolTest.php::getBrowserLogsInfoOnLaunchWithBinaryPath.
Model izolacji sieciowej (obrona w głąb)
Dział zatytułowany „Model izolacji sieciowej (obrona w głąb)”Mostek stosuje dwie niezależne bariery, tak aby obejście jednej z nich nie narażało hosta:
-
Content-Security-Policy. Każde renderowanie jest opakowywane przez
ChromeSecurityPolicy::wrapHtml()w dokument, który zawiera:default-src 'none'; style-src 'unsafe-inline'; img-src data:;base-uri 'none'; form-action 'none'; frame-ancestors 'none';navigate-to 'none';Dyrektywa Content Security Policy (CSP)
default-src 'none'odmawia dostępu do wszystkich źródeł zasobów.img-src data:zezwala wyłącznie na obrazy osadzone w treści.navigate-to 'none'blokuje nawigację po stronie klienta.style-src 'unsafe-inline'to jedyne złagodzenie wymagane, aby ChromeprintToPDFmógł zastosować style osadzone w treści. Zweryfikowano to wsrc/Artisan/ChromeSecurityPolicy.phpi potwierdzono przezChromeSecurityPolicyTest::wrapHtmlIncludesNavigationCspDirectives. -
Blokada transportu Chrome DevTools Protocol (CDP). Przed załadowaniem treści
ChromeHtmlRendererwysyłaNetwork.enable, a następnieNetwork.setBlockedURLsze wzorcem['*']. Blokuje to każdy adres URL podzasobu na warstwie transportowej Chrome DevTools Protocol, niezależnie od CSP. Zweryfikowano to wsrc/Artisan/ChromeHtmlRenderer::blockAllNetworkRequests()i potwierdzono przezChromeHtmlRendererTest::renderAutoFitsHeightAndBlocksNetworkRequests(który sprawdza dokładną kolejność metod CDP oraz parametr['urls' => ['*']]). Jest to blokada na warstwie sieciowej, którą wytyczne OWASP SSRF zalecają jako najsilniejszy mechanizm kontroli, a zarazem domyślna odmowa na całej warstwie transportowej, zgodna z NIST SP 800-53 SC-7.
Skutek: zdalny adres URL w elemencie <img>, arkuszu stylów, czcionce, skrypcie lub ramce iframe w danych wejściowych nie zostaje załadowany. Mostek nie implementuje listy dozwolonych domen ani filtra prywatnych adresów IP, ponieważ ich nie potrzebuje: nie zezwala na żadne pobieranie podzasobów na zewnątrz.
Uwaga o rozbieżności: docblock
nextpdf/coreprzywriteHtmlChrome()mówi, że Chrome „będzie pobierać zasoby zewnętrzne”, i zaleca skonfigurowanie polityki tak, aby „blokować prywatne zakresy IP i ograniczać dozwolone domeny.” Opisuje to konfigurowalny model listy dozwolonych. Dostarczana w Artisan politykaChromeSecurityPolicynie udostępnia listy dozwolonych; blokuje wszystkie żądania podzasobów bezwarunkowo. Rozstrzygający jest kod, a nie docblock w core. Ta rozbieżność została odnotowana dla zespołu dokumentacji core.
Walidacja danych wejściowych (przed Chrome)
Dział zatytułowany „Walidacja danych wejściowych (przed Chrome)”ChromeSecurityPolicy::validate() działa, zanim mostek skontaktuje się z Chrome, i odrzuca:
| Kontrola | Limit | Uzasadnienie |
|---|---|---|
| Rozmiar HTML | > maxHtmlSize (domyślnie 5 MB) | Ogranicza wyczerpywanie zasobów (niekontrolowane zużycie zasobów z listy CWE Top 25) |
| URI danych base64 | grupa przechwytująca >= 13_000_000 bajtów | Ogranicza ryzyko bomby dekompresyjnej |
<meta http-equiv="refresh"> | dowolny (bez rozróżniania wielkości liter, pojedynczy/podwójny cudzysłów) | Blokuje przekierowania po stronie klienta do wewnętrznych punktów końcowych — wektor nawigacyjny SSRF |
Blokowanie meta-refresh to jawne wzmocnienie ochrony przed SSRF. Bez niego kontrolowany przez atakującego kod HTML mógłby przekierować Chrome do punktu końcowego metadanych chmury przed printToPDF. Warunki brzegowe potwierdza ChromeSecurityPolicyTest (validateThrowsOnOversizedHtml, validateRejectsMetaRefreshRedirect, validateRejectsMetaRefreshCaseInsensitive, validateRejectsMetaRefreshWithSingleQuotes, validateRejectsOversizedBase64DataUri, validateRejectsBase64DataUriAtExactThreshold).
Dodatkowo ChromeSecurityPolicy::wrapHtml() usuwa </style> z defaultCss przed wstrzyknięciem, aby zapobiec wyjściu z bloku stylów do kontekstu skryptu (potwierdza to ChromeSecurityPolicyTest::wrapHtmlStripsStyleClosingTagsFromDefaultCss).
Granica piaskownicy Chrome — sformułowana jawnie
Dział zatytułowany „Granica piaskownicy Chrome — sformułowana jawnie”Piaskownica Chrome na poziomie systemu operacyjnego to mechanizm odrębny od opisanych powyżej barier sieciowych, a mostek go nie gwarantuje.
- Domyślnie
noSandboxma wartośćfalse, więc Chrome uruchamia się z włączoną własną piaskownicą. Mostek nie implementuje tej piaskownicy; polega na piaskownicy zapewnianej przez plik binarny Chrome, która zależy od obsługi w jądrze hosta. - Ustawienie
noSandbox: trueuruchamia Chrome z--no-sandbox. Usuwa to piaskownicę izolacji procesów w Chrome. Jest udostępniane dla kontenerów, w których piaskownica nie może się zainicjować. To realne zmniejszenie izolacji: skompromitowanie mechanizmu renderującego nie jest już ograniczane przez piaskownicę Chrome. - Bariery sieciowe mostka (CSP + blokada CDP) pozostają w mocy niezależnie od tego, czy piaskownica jest włączona, ale nie zastępują izolacji procesów. Stosują się wytyczne OWASP ASVS dotyczące najmniejszych uprawnień: uruchamiaj Chrome jako użytkownik bez uprawnień roota, w ograniczonym kontenerze, z
noSandboxtylko tam, gdzie jest to nieuniknione, i traktuj wdrożenie z--no-sandboxjako wymagające wyższego poziomu zaufania do danych wejściowych.
Ta dokumentacja nie twierdzi, że mostek jest „bezpieczny domyślnie” ani „odporny na manipulacje”. Nie twierdzi też, że wyłączenie piaskownicy jest bezpieczne. Określa istniejące mechanizmy kontroli oraz granice ich działania. Przygotowanie kontenera obsługującego piaskownicę zostało omówione na stronie /integrations/artisan/chrome-renderer-setup/.
Tryby awarii
Dział zatytułowany „Tryby awarii”Te tryby awarii wynikają z src/Artisan/Exception/ oraz kodu renderowania/transportu:
| Warunek | Zgłaszany jako | Źródło |
|---|---|---|
Brak biblioteki chrome-php/chrome | ChromeNotAvailableException (z poleceniem instalacji) | BrowserPool::getBrowser() |
HTML przekracza maxHtmlSize | RuntimeException („exceeds maximum allowed size”) | ChromeSecurityPolicy::validate() |
| Zbyt duży URI danych base64 | RuntimeException („oversized base64 data URI”) | ChromeSecurityPolicy::validate() |
| Niedozwolony meta-refresh | RuntimeException („forbidden meta refresh redirect”) | ChromeSecurityPolicy::validate() |
| Uruchomienie / przekroczenie czasu / awaria Chrome | ChromeRenderException (opakowujący przyczynę) | ChromeHtmlRenderer::render() |
| Chrome zwrócił pusty plik PDF | ChromeRenderException („returned empty data”) | ChromeHtmlRenderer::render() |
| Strona nie ma strumienia treści | PdfParseException | PageImporter::import() |
Jeśli ChromeRenderException zostanie zgłoszony w trakcie renderowania, jest ponownie rzucany bez zmian. Każdy inny Throwable jest opakowywany jako ChromeRenderException, z zachowaniem poprzedniego wyjątku (potwierdzają to ChromeHtmlRendererTest::renderRethrowsChromeRenderExceptionWithoutWrapping oraz ::renderWrapsUnexpectedThrowablesWithChromeRenderException). Strona Chrome jest zawsze zamykana w bloku finally, nawet w razie awarii.
Limity zasobów
Dział zatytułowany „Limity zasobów”- Rozmiar wejścia:
maxHtmlSize(domyślnie 5 MB) oraz limit 13 MB dla URI danych base64. - Czas:
renderTimeoutsekund ogranicza zarówno ładowanie treści, jak i synchroniczne wywołania CDP. Polecenia sterujące CDP używają stałego limitu czasu wynoszącego 5 sekund. - Proces:
BrowserPoolponownie uruchamia Chrome co 100 renderowań, aby ograniczyć wzrost zużycia pamięci, i zamyka proces przyclose()/ zniszczeniu.
Są to ograniczenia, a nie kwoty zasobów. W przypadku każdej ścieżki narażonej na niezaufane dane wejściowe nadal stosuj limity zasobów na poziomie hosta (cgroup, ulimit, budżet żądań), zgodnie z wytycznymi CWE Top 25 dotyczącymi zużycia zasobów.
Punkty zaczepienia obserwowalności
Dział zatytułowany „Punkty zaczepienia obserwowalności”Wstrzyknij rejestrator zgodny z PSR-3, aby przechwytywać rozpoczęcie renderowania (rozmiar, szerokość, wysokość), zakończenie renderowania (rozmiar wyjścia, wysokość treści), uruchomienie przeglądarki (ścieżka pliku binarnego), ponowne uruchomienie przeglądarki (liczba renderowań) oraz zamknięcie przeglądarki (liczba renderowań). To jedyne emitowane zdarzenia i nie zawierają żadnej treści ładunku. Wykorzystuj je do SLO dotyczących opóźnień oraz do powiadamiania o częstości ponownych uruchomień.
Zgodność
Dział zatytułowany „Zgodność”| Stwierdzenie | Odwołanie | clause_id | reference_id |
|---|---|---|---|
| Żądania wychodzące z komponentów serwerowych muszą być kontrolowane | OWASP ASVS 5.0 | § (SSRF/kontrola żądań wychodzących) | |
| SSRF = serwer pobiera podany adres URL bez walidacji miejsca docelowego | CWE Top 25 2025 (CWE-918) | cwe_top25_2025#x28.x2.p2 | |
| SSRF (CWE-918) należy do słabości z listy CWE Top 25 | CWE Top 25 2025 | cwe_top25_2025#x1.p73 | |
| Niekontrolowane zużycie zasobów należy do słabości z listy CWE Top 25 | CWE Top 25 2025 (CWE-400) | cwe_top25_2025#x19.x2.p2 | |
| Ochrona granicy z domyślną odmową (zezwalanie na wyjątek) | NIST SP 800-53 Rev 5 SC-7 | SC-7 | |
| Blokada na warstwie sieciowej wywołań do dowolnych miejsc docelowych to silny mechanizm kontroli SSRF | OWASP Cheat Sheet Series (SSRF Prevention §Network layer) | owasp_cheatsheet_series#x132.x2 | |
| Chroń przed SSRF komponenty pobierające adresy URL | OWASP Cheat Sheet Series | § (zapobieganie SSRF, narzędzia pobierające adresy URL) | |
| Izoluj renderowanie niezaufanych treści, najmniejsze uprawnienia | OWASP ASVS 5.0 | § (piaskownica / najmniejsze uprawnienia) | |
| Rejestruj zdarzenia operacyjne; nie umieszczaj ładunków w dziennikach | NIST SP 800-92 | § (wytyczne dotyczące treści dziennika) |
Cytaty zostały pobrane za pomocą silnika zgodności NextPDF (manifest korpusu 1d05b7c4…d790b6); tekst klauzul jest parafrazowany i nigdy nie jest cytowany.
Model zagrożeń
Dział zatytułowany „Model zagrożeń”| Zagrożenie | Mechanizm kontroli | Ryzyko szczątkowe |
|---|---|---|
| SSRF przez zdalny podzasób | CSP default-src 'none' + CDP setBlockedURLs('*') | Błąd silnika Chrome, który obchodzi obie bariery (obrona w głąb obniża ryzyko, ale go nie eliminuje) |
| SSRF przez nawigację meta-refresh | Walidacja przed Chrome odrzuca ten znacznik | Nowy wektor nawigacyjny nieobjęty wzorcem |
| Wyczerpanie zasobów | Limity rozmiaru wejścia i base64 + limit czasu + ponowne uruchomienie co 100 renderowań | Brak kwoty na poziomie hosta; połącz z cgroup/ulimit |
| Skompromitowanie procesu mechanizmu renderującego | Piaskownica Chrome, gdy jest włączona | noSandbox: true całkowicie usuwa ten mechanizm kontroli |
| Wyjście z bloku stylów / wstrzyknięcie | Usuwanie </style> w defaultCss; CSP blokuje skrypty | Wstrzyknięcie przez przyszły wektor, który nie jest usuwany |
Zachowanie w trybie FIPS
Dział zatytułowany „Zachowanie w trybie FIPS”Mostek nie wykonuje żadnych operacji kryptograficznych. Produkuje bajty PDF za pośrednictwem Chrome i je osadza. Podpisywanie, szyfrowanie oraz zachowanie w trybie Federal Information Processing Standards (FIPS) należą do core/Premium i pozostają niezmienione przez Artisan.
Zobacz też
Dział zatytułowany „Zobacz też”- /integrations/artisan/configuration/
- /integrations/artisan/chrome-renderer-setup/
- /integrations/artisan/troubleshooting/
- /integrations/artisan/production-usage/
- /integrations/artisan/overview/