Sicherheit und Betrieb von Artisan
Auf einen Blick
Abschnitt betitelt „Auf einen Blick“Die Bridge rendert potenziell nicht vertrauenswürdiges HTML in Chrome, hinter zwei voneinander unabhängigen Netzwerkbarrieren und einer strikten Content-Policy. Die Betriebssystem-Sandbox von Chrome ist eine separate, optionale Kontrolle mit klar benannten Grenzen. Diese Seite dokumentiert diese Grenze; sie behauptet nicht, sie sei absolut.
Konzeptioneller Überblick
Abschnitt betitelt „Konzeptioneller Überblick“Ein Render-Vorgang ist die serverseitige Ausführung einer Anfrage: Die Anwendung übergibt HTML an eine Browser-Engine, die standardmäßig Ressourcen abrufen kann. Ein ausgehender Abruf, der durch nicht vertrauenswürdige Eingaben gesteuert wird, ist Server-Side Request Forgery: CWE-918 definiert sie als einen Server, der den Inhalt einer übergebenen URL abruft, ohne ausreichend sicherzustellen, dass die Anfrage an das erwartete Ziel gerichtet ist. SSRF (CWE-918) ist eine CWE-Top-25-Schwachstelle. OWASP ASVS verlangt, dass ausgehende Anfragen von Serverkomponenten kontrolliert werden und nicht implizit erfolgen. Das OWASP SSRF Prevention Cheat Sheet behandelt das Unterbinden von Aufrufen an beliebige Ziele auf der Netzwerkebene als starke Kontrolle. Die unten beschriebene Deny-by-Default-Netzwerkhaltung ist die Antwort der Bridge auf diese Anforderung. NIST SP 800-53 SC-7 beschreibt dasselbe Prinzip einer Deny-all-permit-by-exception-Grenze, das die Bridge auf der Transportebene anwendet.
Datenresidenz und PII-Minderungen
Abschnitt betitelt „Datenresidenz und PII-Minderungen“An die Bridge übergebenes HTML wird vollständig im Prozess und innerhalb der lokalen Chrome-Instanz verarbeitet. Die Bridge stellt selbst keine ausgehenden Netzwerkanfragen und hindert Chrome daran, solche Anfragen zu stellen (siehe das Netzwerkmodell unten), sodass Eingabeinhalte den Host nicht über den Renderer verlassen. PII in der Eingabe wird in das PDF gerendert, das Sie erzeugen — behandeln Sie die Ausgabe mit denselben Residenzkontrollen wie die Eingabe. Die Bridge schreibt weder Eingabe noch Ausgabe auf die Festplatte; die Persistenz liegt in der Verantwortung des Aufrufers.
Sichere Telemetrie und Log-Scrubbing
Abschnitt betitelt „Sichere Telemetrie und Log-Scrubbing“ChromeHtmlRenderer und BrowserPool akzeptieren einen optionalen PSR-3-LoggerInterface. Die Bridge protokolliert ausschließlich betriebliche Metadaten: Bytelänge der Eingabe, Zielbreite und -höhe, Bytelänge der Ausgabe, gemessene Inhaltshöhe, Browser-Start mit dem konfigurierten Binärpfad, Neustarthinweise mit einem Render-Zähler sowie Schließereignisse. Sie protokolliert nicht HTML-Inhalte, gerenderte Bytes oder extrahierten Text. Das entspricht der Vorgabe von NIST SP 800-92, betriebliche Ereignisse zu protokollieren und zugleich sensible Payloads aus den Logs herauszuhalten. Der Binärpfad wird protokolliert; behandeln Sie ihn als nicht sensible Deployment-Metadaten. Die Struktur der Log-Aufrufe wird durch tests/Unit/Artisan/ChromeHtmlRendererTest.php::renderLogsDebugWithSizeWidthHeightAndPdfSize und tests/Unit/Artisan/BrowserPoolTest.php::getBrowserLogsInfoOnLaunchWithBinaryPath abgesichert.
Netzwerk-Isolationsmodell (Defense in Depth)
Abschnitt betitelt „Netzwerk-Isolationsmodell (Defense in Depth)“Die Bridge wendet zwei voneinander unabhängige Barrieren an, sodass eine umgangene Barriere den Host nicht allein offenlegt:
-
Content-Security-Policy. Jeder Render-Vorgang wird durch
ChromeSecurityPolicy::wrapHtml()in ein Dokument eingebettet, das mit folgenden Direktiven versehen ist:default-src 'none'; style-src 'unsafe-inline'; img-src data:;base-uri 'none'; form-action 'none'; frame-ancestors 'none';navigate-to 'none';default-src 'none'verweigert Ressourcen von allen Origins.img-src data:erlaubt ausschließlich Inline-Bilder.navigate-to 'none'blockiert clientseitige Navigation.style-src 'unsafe-inline'ist die einzige Ausnahme, die ChromeprintToPDFbenötigt, um Inline-Styles anzuwenden. Geprüft insrc/Artisan/ChromeSecurityPolicy.phpund abgesichert durchChromeSecurityPolicyTest::wrapHtmlIncludesNavigationCspDirectives. -
CDP-Transport-Block. Bevor Inhalte geladen werden, ruft
ChromeHtmlRendererNetwork.enableund anschließendNetwork.setBlockedURLsmit dem Muster['*']auf und blockiert damit jede Subressourcen-URL auf der Transportebene des Chrome DevTools Protocol, unabhängig von der CSP. Geprüft insrc/Artisan/ChromeHtmlRenderer::blockAllNetworkRequests()und abgesichert durchChromeHtmlRendererTest::renderAutoFitsHeightAndBlocksNetworkRequests(das die genaue Reihenfolge der CDP-Methoden und den Parameter['urls' => ['*']]prüft). Das ist die Blockierung auf Netzwerkebene, die die OWASP-SSRF-Vorgabe als stärkste Kontrolle empfiehlt, und ein Deny-all auf Transportebene im Einklang mit NIST SP 800-53 SC-7.
Das Ergebnis: Eine entfernte <img>-, Stylesheet-, Font-, Skript- oder iframe-URL in der Eingabe wird nicht geladen. Die Bridge implementiert keine Domain-Allowlist und keinen Filter für private IPs, weil sie beides nicht benötigt — sie lässt überhaupt keinen ausgehenden Subressourcen-Abruf zu.
Drift-Hinweis: Der
nextpdf/core-Docblock zuwriteHtmlChrome()besagt, Chrome „werde externe Ressourcen abrufen“, und rät, eine Policy zu konfigurieren, um „private IP-Bereiche zu blockieren und erlaubte Domains zu begrenzen.“ Das beschreibt ein Modell mit konfigurierbarer Allowlist. Die ausgelieferte Artisan-ChromeSecurityPolicystellt keine Allowlist bereit und blockiert stattdessen alle Subressourcen-Anfragen bedingungslos. Maßgeblich ist der Code, nicht der Core-Docblock. Diese Drift wird für das Core-Docs-Team festgehalten.
Eingabevalidierung (vor Chrome)
Abschnitt betitelt „Eingabevalidierung (vor Chrome)“ChromeSecurityPolicy::validate() läuft, bevor Chrome kontaktiert wird, und weist Folgendes zurück:
| Prüfung | Grenze | Begründung |
|---|---|---|
| HTML-Größe | > maxHtmlSize (Standard 5 MB) | Grenze gegen Ressourcenerschöpfung (CWE Top 25 unkontrollierter Ressourcenverbrauch) |
| Base64-Daten-URI | Capture-Gruppe >= 13_000_000 Bytes | Grenze gegen Dekompressionsbomben |
<meta http-equiv="refresh"> | beliebige Variante (Groß-/Kleinschreibung egal, single/double quote) | Blockiert clientseitige Weiterleitungen an interne Endpunkte — einen SSRF-Navigationsvektor |
Das Blockieren von Meta-Refresh ist explizites SSRF-Hardening: Ohne diese Kontrolle könnte Angreifer-HTML Chrome vor printToPDF auf einen Cloud-Metadaten-Endpunkt umleiten. Dieses Grenzverhalten wird über ChromeSecurityPolicyTest abgesichert (validateThrowsOnOversizedHtml, validateRejectsMetaRefreshRedirect, validateRejectsMetaRefreshCaseInsensitive, validateRejectsMetaRefreshWithSingleQuotes, validateRejectsOversizedBase64DataUri, validateRejectsBase64DataUriAtExactThreshold).
Zusätzlich entfernt ChromeSecurityPolicy::wrapHtml() vor der Injektion </style> aus defaultCss, um einen Ausbruch aus dem Style-Block in den Skriptkontext zu verhindern (abgesichert durch ChromeSecurityPolicyTest::wrapHtmlStripsStyleClosingTagsFromDefaultCss).
Die Chrome-Sandbox-Grenze — explizit benannt
Abschnitt betitelt „Die Chrome-Sandbox-Grenze — explizit benannt“Die Betriebssystem-Sandbox von Chrome ist eine separate Kontrolle, getrennt von den Netzwerkbarrieren oben, und die Bridge garantiert sie nicht.
- Standardmäßig ist
noSandboxauffalsegesetzt, sodass Chrome mit aktivierter eigener Sandbox startet. Die Bridge implementiert die Sandbox nicht; sie verlässt sich auf die Sandbox des Chrome-Binaries, die von der Kernel-Unterstützung des Hosts abhängt. - Das Setzen von
noSandbox: truestartet Chrome mit--no-sandbox. Das entfernt die Prozessisolations-Sandbox von Chrome. Diese Option ist für Container vorgesehen, in denen die Sandbox nicht initialisiert werden kann. Sie ist eine echte Verringerung der Isolation: Eine Kompromittierung des Renderers wird nicht mehr durch die Sandbox von Chrome eingedämmt. - Die Netzwerkbarrieren der Bridge (CSP + CDP-Block) bleiben in Kraft, unabhängig davon, ob die Sandbox aktiviert ist, aber sie ersetzen die Prozessisolation nicht. Die OWASP-ASVS-Vorgabe zur geringsten Rechtevergabe gilt: Betreiben Sie Chrome als Nicht-Root-Nutzer, in einem eingeschränkten Container, mit
noSandboxnur dort, wo es unvermeidbar ist, und behandeln Sie ein--no-sandbox-Deployment als höhere Vertrauensanforderung an die Eingabe.
Diese Dokumentation erhebt keinen Anspruch darauf, dass die Bridge „standardmäßig sicher“ oder „manipulationssicher“ ist oder dass das Deaktivieren der Sandbox sicher ist. Sie benennt die vorhandenen Kontrollen und ihre Grenzen. Die Bereitstellung eines sandbox-fähigen Containers wird auf der Seite /integrations/artisan/chrome-renderer-setup/ behandelt.
Fehlermodi
Abschnitt betitelt „Fehlermodi“Abgeleitet aus src/Artisan/Exception/ und dem Render-/Transport-Code:
| Bedingung | Erscheint als | Quelle |
|---|---|---|
chrome-php/chrome-Bibliothek fehlt | ChromeNotAvailableException (mit Installationsbefehl) | BrowserPool::getBrowser() |
HTML überschreitet maxHtmlSize | RuntimeException („exceeds maximum allowed size“) | ChromeSecurityPolicy::validate() |
| Übergroßer Base64-Daten-URI | RuntimeException („oversized base64 data URI“) | ChromeSecurityPolicy::validate() |
| Verbotener Meta-Refresh | RuntimeException („forbidden meta refresh redirect“) | ChromeSecurityPolicy::validate() |
| Chrome-Start / -Timeout / -Absturz | ChromeRenderException (umschließt die Ursache) | ChromeHtmlRenderer::render() |
| Chrome lieferte leeres PDF | ChromeRenderException („returned empty data“) | ChromeHtmlRenderer::render() |
| Seite hat keinen Content-Stream | PdfParseException | PageImporter::import() |
Eine ChromeRenderException, die während des Render-Vorgangs ausgelöst wird, wird unverändert erneut geworfen. Jede andere Throwable wird als ChromeRenderException umschlossen, wobei die vorherige Ausnahme erhalten bleibt (abgesichert durch ChromeHtmlRendererTest::renderRethrowsChromeRenderExceptionWithoutWrapping und ::renderWrapsUnexpectedThrowablesWithChromeRenderException). Die Chrome-Seite wird immer in einem finally-Block geschlossen, auch bei einem Fehler.
Ressourcengrenzen
Abschnitt betitelt „Ressourcengrenzen“- Eingabegröße:
maxHtmlSize(Standard 5 MB) und das 13-MB-Limit für Base64-Daten-URIs. - Zeit:
renderTimeoutSekunden begrenzen sowohl das Laden der Inhalte als auch die synchronen CDP-Aufrufe. CDP-Steuerbefehle verwenden ein festes Timeout von 5 Sekunden. - Prozess:
BrowserPoolstartet Chrome alle 100 Render-Vorgänge neu, um das Speicherwachstum zu begrenzen, und schließt den Prozess beiclose()/ bei Zerstörung.
Das sind Grenzen, keine Kontingente. Eine Ressourcengrenze auf Host-Ebene (cgroup, ulimit, Anfrage-Budget) wird für jeden Pfad, der nicht vertrauenswürdigen Eingaben ausgesetzt ist, im Einklang mit der CWE-Top-25-Vorgabe zum Ressourcenverbrauch weiterhin empfohlen.
Observability-Hooks
Abschnitt betitelt „Observability-Hooks“Injizieren Sie einen PSR-3-Logger, um Folgendes zu erfassen: Render-Start (Größe, Breite, Höhe), Render-Abschluss (Ausgabegröße, Inhaltshöhe), Browser-Start (Binärpfad), Browser-Neustart (Render-Zähler), Browser-Schließung (Render-Zähler). Das sind die einzigen ausgegebenen Ereignisse, und sie enthalten keinen Payload-Inhalt. Nutzen Sie sie für Latenz-SLOs und Alarmierung zur Neustart-Rate.
Konformität
Abschnitt betitelt „Konformität“| Aussage | Referenz | clause_id | reference_id |
|---|---|---|---|
| Ausgehende Anfragen von Serverkomponenten müssen kontrolliert werden | OWASP ASVS 5.0 | § (SSRF/Kontrolle ausgehender Anfragen) | |
| SSRF = Server ruft eine übergebene URL ab, ohne das Ziel zu validieren | CWE Top 25 2025 (CWE-918) | cwe_top25_2025#x28.x2.p2 | |
| SSRF (CWE-918) ist eine Schwachstelle aus den CWE Top 25 | CWE Top 25 2025 | cwe_top25_2025#x1.p73 | |
| Unkontrollierter Ressourcenverbrauch ist eine Schwachstelle aus den CWE Top 25 | CWE Top 25 2025 (CWE-400) | cwe_top25_2025#x19.x2.p2 | |
| Deny-by-Default-Grenzschutz (Erlaubnis nur per Ausnahme) | NIST SP 800-53 Rev 5 SC-7 | SC-7 | |
| Ein Verbot von Aufrufen an beliebige Ziele auf der Netzwerkebene ist die starke SSRF-Kontrolle | OWASP Cheat Sheet Series (SSRF Prevention §Netzwerkebene) | owasp_cheatsheet_series#x132.x2 | |
| URL-abrufende Komponenten gegen SSRF schützen | OWASP Cheat Sheet Series | § (SSRF-Prävention, URL-Abruf-Tools) | |
| Rendering nicht vertrauenswürdiger Inhalte isolieren, geringste Rechtevergabe | OWASP ASVS 5.0 | § (Sandbox / geringste Rechtevergabe) | |
| Betriebliche Ereignisse protokollieren; Payloads aus den Logs heraushalten | NIST SP 800-92 | § (Vorgabe zu Log-Inhalten) |
Die Nachweise wurden über die NextPDF Compliance-Engine abgerufen (Korpus-Manifest 1d05b7c4…d790b6); der Klauseltext ist paraphrasiert, niemals zitiert.
Bedrohungsmodell
Abschnitt betitelt „Bedrohungsmodell“| Bedrohung | Kontrolle | Restrisiko |
|---|---|---|
| SSRF über entfernte Subressource | CSP default-src 'none' + CDP setBlockedURLs('*') | Ein Chrome-Engine-Bug, der beide Barrieren umgeht (Defense in Depth senkt das Risiko, beseitigt es aber nicht) |
| SSRF über Meta-Refresh-Navigation | Die Validierung vor Chrome weist das Tag zurück | Neuer Navigationsvektor, der nicht vom Muster erfasst wird |
| Ressourcenerschöpfung | Eingabegröße + Base64-Limits + Timeout + Neustart alle 100 Render-Vorgänge | Kein Kontingent pro Host; mit cgroup/ulimit kombinieren |
| Kompromittierung des Renderer-Prozesses | Chrome-Sandbox wenn aktiviert | noSandbox: true entfernt diese Kontrolle vollständig |
| Style-Ausbruch / Injektion | </style>-Entfernung in defaultCss; CSP blockiert Skripte | Injektion über einen künftigen, nicht entfernten Vektor |
FIPS-Modus-Verhalten
Abschnitt betitelt „FIPS-Modus-Verhalten“Die Bridge führt keine kryptografischen Operationen durch. Sie erzeugt PDF-Bytes über Chrome und bettet sie ein. Signierung, Verschlüsselung und FIPS-Modus-Verhalten liegen bei Core/Premium und werden von Artisan nicht berührt.
Siehe auch
Abschnitt betitelt „Siehe auch“- /integrations/artisan/configuration/
- /integrations/artisan/chrome-renderer-setup/
- /integrations/artisan/troubleshooting/
- /integrations/artisan/production-usage/
- /integrations/artisan/overview/