Beveiliging en beheer
In één oogopslag
Sectie met titel “In één oogopslag”Deze brug stuurt uw Hypertext Markup Language (HTML) over een netwerkgrens naar een browser-engine. Deze pagina documenteert de maatregelen die die grens beschermen, met de broncode als bron van waarheid. Wanneer een maatregel naar een standaard verwijst, is dat de verwijzing die in de docblock van de code is opgenomen. Deze pagina geeft de claim uit de code weer; ze reconstrueert geen normatieve formuleringen.
Dreigingsmodel
Sectie met titel “Dreigingsmodel”De docblocks van het package noemen de dreigingen waartegen het beschermt:
- XSS-naar-PDF — Cross-site scripting (XSS) via kwaadaardige markup die tijdens het renderen naar Portable Document Format (PDF) wordt uitgevoerd.
- SSRF — Server-side request forgery (SSRF) veroorzaakt door markup of een Uniform Resource Locator (URL) als bestemming die een verzoek naar een intern adres stuurt.
- Uitputting van resources — Te grote invoer of een decompressiebom.
- DNS-rebinding — Domain Name System (DNS)-rebinding, waarbij een hostnaam de validatie doorstaat en vervolgens bij het verbinden naar een privéadres verwijst.
- On-path TLS-onderschepping — On-path Transport Layer Security (TLS)-onderschepping via een vervangen certificaat op het netwerkpad naar de Worker.
Voor elke dreiging staat hieronder een specifieke, testbare maatregel.
Invoermaatregelen (voordat het verzoek PHP verlaat)
Sectie met titel “Invoermaatregelen (voordat het verzoek PHP verlaat)”CloudflareSecurityPolicy::validate() wordt uitgevoerd voordat er een verzoek wordt opgebouwd:
| Maatregel | Gedrag | Bron van de limiet |
|---|---|---|
| Groottelimiet | Weigert HTML die groter is dan maxHtmlSize | CloudflareRendererConfig, standaard 5000000 bytes |
| Base64-decompressiebombeveiliging | Schat de gedecodeerde grootte van elke data:…;base64,…-URI; weigert waarden die het maximum bereiken of overschrijden | MAX_DATA_URI_BYTES = 13631488 |
| Verbod op meta-refresh | Weigert elke <meta http-equiv="refresh">, ongeacht hoofdlettergebruik | regex in CloudflareSecurityPolicy |
Een overtreding veroorzaakt een RuntimeException met een bericht dat de afwijkende waarde en de limiet noemt. Het verbod op meta-refresh bestaat omdat een refresh-directive binnen de pagina die de Worker weergeeft navigatie kan starten: een SSRF-vector in de content, niet in de URL.
Het HTML-beveiligingsbeleid uit nextpdf/core (HtmlSecurityPolicyInterface, standaard DefaultHtmlSecurityPolicy) werkt op de parse-laag en vult de bovenstaande transportlaagcontroles aan. U haalt het op met getHtmlSecurityPolicy(). Injecteer via de constructor een eigen variant.
Bestemmingsmaatregelen (SSRF en DNS-rebinding)
Sectie met titel “Bestemmingsmaatregelen (SSRF en DNS-rebinding)”CloudflareSecurityPolicy::validateWorkerUrl():
- Weigert een URL die niet kan worden geparseerd of geen scheme/host bevat (
Invalid Worker URL). - Weigert elk ander scheme dan HTTPS (
Worker URL must use HTTPS). - Voor een host die een IP-literal is, weigert private of gereserveerde bereiken met
PHP’s
FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE. In de praktijk weigert dit de private adresruimte van RFC 1918, loopback en de link-local-adressen van RFC 3927. Tests dekken expliciet dat192.168.x,127.0.0.1en169.254.xworden geweigerd. De PHP-filterextensie bepaalt of een adres tot een bereik behoort; dit package koppelt die beslissing niet aan een clausule. RFC 1918 en RFC 3927 worden hier beschrijvend genoemd als de bekende definities van die bereiken. - Voor een hostnaam resolvet de methode alle A- en AAAA-records met
dns_get_record()(nietgethostbyname(), dat alleen het eerste antwoord teruggeeft) en weigert de host als enig geresolved adres privé of gereserveerd is.
Het resolven van alle records is opzettelijk. De docblock van de klasse beschrijft dit als verdediging tegen een host die meerdere records teruggeeft, waarbij een lookup van één record het openbare adres zou kunnen kiezen terwijl de latere verbinding een privéadres kiest. Dit komt overeen met de OWASP SSRF Prevention Cheat Sheet: resolve de A- en AAAA-antwoorden voor het domein en pas de controle op niet-openbare adressen toe op de volledige resultatenset.
validateWorkerUrl() geeft de gecontroleerde IP-set terug. Vlak voor verzending roept de renderer assertPinsStillValid() aan. Die aanroep resolvet de host opnieuw en weigert elk nieuw gezien IP (Worker URL DNS answer changed since validation — possible DNS rebinding attack). Dit sluit het time-of-check/time-of-use-venster tussen validatie en verbinding.
Transportmaatregelen (PinnedCurlTransport)
Sectie met titel “Transportmaatregelen (PinnedCurlTransport)”Wanneer een gecontroleerde IP-set of een Subject Public Key Info (SPKI)-pinset aanwezig is en er een PHP Standards Recommendation 17 (PSR-17) ResponseFactory is meegegeven, gebruikt de renderer Transport\PinnedCurlTransport in plaats van de geïnjecteerde PHP Standards Recommendation 18 (PSR-18)-client. Het transport handhaaft deze maatregelen op cURL-handle-niveau:
- Gepinde DNS —
CURLOPT_RESOLVEbindt de host:poort aan de gecontroleerde IP-set, zodat libcurl bij het verbinden geen eigen lookup uitvoert. Door deze binding geldt de userland-DNS-controle voor de daadwerkelijke verbinding; zonder die binding zou libcurl een ander adres kunnen resolven. - TLS-public-key-pinning —
CURLOPT_PINNEDPUBLICKEYwordt ingesteld op basis van de gecombineerde pinset. Dit volgt RFC 7469 §2.6: een gepinde verbinding wordt geaccepteerd wanneer de door de server gepresenteerde SPKI-fingerprintset overlapt met de geconfigureerde pinset, en een mislukte pinvalidatie is niet herstelbaar. Pin-strings worden genormaliseerd vansha256/<base64>naar desha256//<base64>-vorm van cURL; een ongeldige pin veroorzaakt eenInvalidSpkiPinException. - TLS-verificatie aan —
CURLOPT_SSL_VERIFYPEER => true,CURLOPT_SSL_VERIFYHOST => 2. - Geen automatische redirects —
CURLOPT_FOLLOWLOCATION => false,CURLOPT_MAXREDIRS => 0. Een 3xx-respons wordt aan de beleidslaag doorgegeven in plaats van door libcurl naar een niet-gecontroleerde host te worden gevolgd. De docblock van de klasse stelt dat dit opzettelijk is, zodat redirects opnieuw worden gevalideerd in plaats van stilzwijgend te worden gevolgd. - Harde time-out —
CURLOPT_TIMEOUTwordt ingesteld op basis vanrenderTimeout(standaard30seconden).
Een cURL-fout of een body die geen string is, veroorzaakt een CloudflareRenderException met het cURL-foutnummer en -bericht.
Operationele richtlijnen voor pinning
Sectie met titel “Operationele richtlijnen voor pinning”De configuratie bevat pinnedPublicKeys en een aparte backupPublicKeys. RFC 7469 §2.5 beschrijft een back-uppin als een fingerprint voor een secundair, nog niet uitgerold sleutelpaar dat offline wordt bewaard, en behandelt deze als de primaire herstelweg bij een onbedoeld mislukte pinvalidatie. Houd ten minste één back-uppin aan, zodat certificaatrotatie het endpoint niet onbruikbaar maakt. Via het aparte veld kunt u een rotatie onafhankelijk valideren. Operationeel:
- Pin de SPKI van het leaf-certificaat of van een intermediate waarvan u de rotatie beheert.
- Configureer altijd een back-uppin voor het volgende certificaat voordat u roteert.
- Een lege pinset schakelt pinning uit; gebruik dat alleen bij een stabiele, bekende certificaatketen. Pinning is opt-in via configuratie.
Authenticatie en omgang met geheimen
Sectie met titel “Authenticatie en omgang met geheimen”- Het Worker-verzoek bevat
Authorization: Bearer <apiToken>.apiTokenis#[SensitiveParameter], zodat stack traces deze maskeren. De bereikbaarheidsprobe verstuurt dezelfde bearer-header bij een Hypertext Transfer Protocol (HTTP)HEAD. - Cloudflare R2-toegangssleutels (
accessKeyId,secretAccessKey) zijn#[SensitiveParameter]en worden alleen gebruikt om de Amazon Web Services (AWS) Signature V4-ondertekensleutel af te leiden. ApiKeyValidatorvergelijkt sleutels methash_equals()(timing-veilig) en ondersteunt opslag van Secure Hash Algorithm 256 (SHA-256)-gehashte sleutels viavalidateHashed().- Configuratieobjecten zijn
final readonly— een eenmaal ingesteld geheim kan niet worden gewijzigd. - Haal geheimen uit omgevingsvariabelen of een secrets manager. Commit ze nooit. Het package volgt de bredere beveiligingsbasislijn van NextPDF: PHPStan Level 10,
declare(strict_types=1)in elk bestand, geeneval()/exec(), GitHub Actions vastgepind op SHA.
Wat dit package niet beweert
Sectie met titel “Wat dit package niet beweert”- Het noemt geen enkele Cloudflare-platformlimiet (CPU-tijd van de Worker, geheugen, maximale verzoekbody of aantal subverzoeken). De enige grootte- en tijdslimieten die deze documentatie noemt, zijn de limieten die het package zelf afdwingt, hierboven vermeld en in /integrations/cloudflare/configuration/. Raadpleeg voor platformlimieten de officiële documentatie van Cloudflare en de eigen implementatie van uw Worker.
- Het ondertekent geen PDF’s en doet geen enkele bewering over conformiteit van handtekeningen. Wanneer handtekeningen vereist zijn, render dan hier en onderteken daarna met de engine. NextPDF Pro biedt alleen PDF Advanced Electronic Signatures (PAdES) B-B-ondertekening; profielen voor langetermijnvalidatie zijn een Enterprise-functie en vallen buiten de scope van deze brug.
- Het certificeert of garandeert de pijplijn niet en maakt deze niet „tamper-proof”. Het implementeert uitsluitend de specifieke, in de broncode verifieerbare maatregelen die op deze pagina worden beschreven.
Operationele runbook
Sectie met titel “Operationele runbook”| Symptoom | Eerste controle |
|---|---|
Worker URL must use HTTPS | Controleer het scheme van de geconfigureerde workerUrl. |
private or reserved IP | Controleer de DNS-records van de Worker-hostnaam; zoek naar een record dat resolvet naar de adresruimte van RFC 1918 / loopback / RFC 3927. |
DNS answer changed since validation | DNS-instabiliteit of een rebindingpoging; resolve opnieuw en inspecteer de volledige recordset. |
cURL transport error | Controleer het netwerkpad, de TLS-keten en — als er pins zijn ingesteld — of de SPKI van het aangeboden certificaat nog in de pinset staat. |
| Renderings mislukken direct na een certificaatrotatie | Een pinset zonder bijbehorende back-uppin. Voeg de nieuwe SPKI als back-up toe voordat u roteert. |
is not installed / no LocalRendererFactoryInterface | Fallback is ingeschakeld maar er is geen factory aangesloten, of nextpdf/artisan ontbreekt. |
| Weigeringen door de rate limit zijn inconsistent tussen nodes | De in-memory limiter werkt per proces; plaats er een gedeelde store voor. |
Incidenten melden
Sectie met titel “Incidenten melden”Meld kwetsbaarheden via GitHub Security Advisories of het beveiligingscontact in de SECURITY.md van de repository. Dien beveiligingsproblemen niet in als openbare GitHub-issues.
Zie ook
Sectie met titel “Zie ook”- /integrations/cloudflare/overview/ — waarom dit package rond deze grens is opgebouwd.
- /integrations/cloudflare/configuration/ — velden voor pinset en limieten.
- /integrations/cloudflare/troubleshooting/ — volledige toewijzing van fouten naar exceptions.