Ga naar inhoud

Contracts / Beveiligingsbeleid

Het security-policy-domein definieert drie standaard-weigerende contracts: CryptoPolicyInterface bewaakt de keuze van algoritmen en sleutels, HtmlSecurityPolicyInterface beperkt het functieoppervlak van Hypertext Markup Language (HTML) en ExternalResourcePolicyInterface regelt het laden van externe resources. Omdat ze alle drie contracts zijn, kun je een strenger deploymentbeleid leveren zonder te forken.

Terminal window
composer require nextpdf/core:^3

CryptoPolicyInterface is de cryptopoort. Core roept deze aan vóór elke stap voor ondertekening, versleuteling of hashing. De controle omvat de hash, de object identifier (OID) van de handtekening, het versleutelingsalgoritme en de sleutelsterkte. Het contract rapporteert ook de minimale hash en een beleidsnaam voor het auditlogboek. Gebruik deze interface om een regelset toe te passen, zoals Federal Information Processing Standards (FIPS) 140-3 of eIDAS. De code voor ondertekening en versleuteling verandert niet. Wanneer er geen beleid is ingesteld, is elk algoritme toegestaan. Een gereguleerde site moet een expliciet beleid instellen.

HtmlSecurityPolicyInterface werkt op de HTML-parselaag. Het wordt uitgevoerd voordat content een renderer bereikt. Het bepaalt of een tag, een attribuut, een Cascading Style Sheets (CSS)-eigenschap of een uniform resource locator (URL)-schema is toegestaan. Het begrenst ook de invoergrootte en de nestingdiepte. Het werkt samen met de renderer-specifieke transportbeleidsregels (Chrome, Cloudflare, Gotenberg), die groottelimieten en Content Security Policy (CSP)-headers instellen. Het HTML-beleid verkleint het aanvalsoppervlak op de parselaag. Een verwijderde tag bereikt nooit de lay-out. Een geïnjecteerd element kan de uitvoer niet wijzigen. Wanneer er geen beleid is ingesteld, staat de standaard de volledige functieset toe.

ExternalResourcePolicyInterface bepaalt of de HTML-pipeline een extern lettertype, stylesheet of afbeelding mag ophalen. Het stelt ook de limieten voor elke ophaalactie in. De standaardhouding is: alles weigeren. Elke optie staat uit totdat je deze inschakelt. Het contract volgt het principe van minimale rechten. Niet-vertrouwde HTML kan verwijzen naar een door een aanvaller beheerde URL. Het reguleert ophaalacties voor @font-face op basis van schema, grootte en aantal glyphs. Het reguleert @import op basis van schema, diepte en totale grootte. Het reguleert background-image op basis van een schemalijst en een toegestane-domeinlijst met exacte overeenkomst. Het begrenst de grootte van data-URI’s (Uniform Resource Identifier). Het reguleert ook externe verwijzingen in Scalable Vector Graphics (SVG). Het contract bepaalt dat productie deze altijd moet weigeren. Ze maken request forgery en scriptinjectie mogelijk. Onbeperkt URL’s ophalen is een pad voor server-side request forgery. URL-wijzigingen kunnen toegangscontrole omzeilen, zoals beschreven in de Open Worldwide Application Security Project (OWASP) Top 10 2025. Externe componenten mogen alleen uit officiële herkomsten en via veilig transport worden betrokken.

TypeSoortBelangrijkste ledenStabiliteitSinds
CryptoPolicyInterfaceinterfaceisHashAlgorithmAllowed(), isSignatureAlgorithmAllowed(), isEncryptionAlgorithmAllowed(), isKeyStrengthAllowed(), getPreferredHashAlgorithm(), getName()stabiel1.9.0
HtmlSecurityPolicyInterfaceinterfaceisTagAllowed(), isAttributeAllowed(), isCssPropertyAllowed(), isUrlSchemeAllowed(), getMaxInputSize(), getMaxNestingDepth(), getName()stabiel3.1.0
ExternalResourcePolicyInterfaceinterfaceisFontFaceAllowed(), getAllowedFontSchemes(), getMaxFontFileSize(), getMaxFontGlyphs(), isImportAllowed(), getMaxImportDepth(), isBackgroundImageAllowed(), getAllowedImageDomains(), getMaxDataUrlSize(), isSvgExternalReferenceAllowed()stabiel4.0.0

ExternalResourcePolicyInterface retourneert getypeerde limieten: positive-int-groottes, int<1, 100>-importdiepte en list<non-empty-string>-lijsten met schema’s en domeinen. De standaardimplementatie weigert elke optie.

examples/contracts/security-policy-quickstart.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\HtmlSecurityPolicyInterface;
/**
* Decide whether a tag survives the policy.
*
* @param HtmlSecurityPolicyInterface $policy A core or custom policy.
*/
function tagSurvives(HtmlSecurityPolicyInterface $policy, string $tag): bool
{
return $policy->isTagAllowed($tag);
}

De functie is alleen afhankelijk van het contract. Zowel een restrictief beleid als het standaardbeleid voldoet aan dat contract.

examples/contracts/security-policy-production.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\CryptoPolicyInterface;
use NextPDF\Contracts\ExternalResourcePolicyInterface;
use NextPDF\Contracts\HtmlSecurityPolicyInterface;
use Psr\Log\LoggerInterface;
final readonly class UntrustedHtmlGate
{
public function __construct(
private HtmlSecurityPolicyInterface $htmlPolicy,
private ExternalResourcePolicyInterface $resourcePolicy,
private CryptoPolicyInterface $cryptoPolicy,
private LoggerInterface $logger,
) {}
/**
* Reject input that exceeds the configured limits before rendering.
*
* @param string $html Untrusted HTML markup.
*/
public function assertAcceptable(string $html): void
{
$maxInput = $this->htmlPolicy->getMaxInputSize();
if ($maxInput > 0 && \strlen($html) > $maxInput) {
$this->logger->warning('HTML rejected: input over limit', [
'policy' => $this->htmlPolicy->getName(),
'limit' => $maxInput,
]);
throw new \LengthException('HTML input exceeds policy limit.');
}
if ($this->resourcePolicy->isSvgExternalReferenceAllowed()) {
$this->logger->error('Unsafe policy: SVG external references enabled.');
throw new \LogicException('SVG external references must be denied in production.');
}
}
}

Deze poort dwingt de invoerlimiet af en weigert een onveilig resourcebeleid voordat de pipeline draait. De poort logt de beleidsnaam voor audit en gooit een specifieke uitzondering.

  • CryptoPolicyInterface staat elk algoritme toe wanneer er geen beleid is ingesteld. De open standaardinstelling is bedoeld voor ontwikkeling, niet als productiehouding. Stel in elke gereguleerde deployment een expliciet beleid in.
  • HtmlSecurityPolicyInterface::getMaxInputSize() retourneert 0 voor onbeperkt. Beschouw 0 als “geen beleidslimiet”, niet als “alles weigeren”. Pas ook een limiet op de transportlaag toe.
  • ExternalResourcePolicyInterface weigert standaard alles. Het inschakelen van @font-face of background-image zonder een schemalijst in te stellen, opent een aanvalsoppervlak voor request forgery; stel tegelijk de lijst met toegestane schema’s in.
  • Een lege lijst met toegestane domeinen bij getAllowedImageDomains() betekent dat alle domeinen zijn toegestaan zodra achtergrondafbeeldingen zijn ingeschakeld. Een lege lijst is geen weigerregel; lever expliciete domeinen aan.
  • isSvgExternalReferenceAllowed() moet in productie false retourneren. Dat staat in het contract; een beleid dat true retourneert, is een bevinding, geen configuratiekeuze.

Een beleidscontrole is een predicaataanroep: O(1), zonder kosten die met de invoer meegroeien. Het beleid wordt tijdens het parsen geraadpleegd per tag, per attribuut, per CSS-eigenschap en per URL. Een pathologisch document vermenigvuldigt het aantal aanroepen, maar elke aanroep blijft constante tijd. Het performance_budget van 1500 ms wandtijd en 64 MB piek wordt gedomineerd door parsen en renderen, niet door beleidsevaluatie. De limieten voor invoergrootte en nestingdiepte begrenzen de kosten van de parser zelf. Een streng beleid verbetert de worstcaseprestaties door een te groot of diep genest document vóór de lay-out te weigeren.

Deze contracts vormen de verdedigingsgrens van de engine, dus het dreigingsmodel is expliciet. CryptoPolicyInterface beperkt algoritmedowngrade door zwakke hashes en korte sleutels te blokkeren vóór elke bewerking. HtmlSecurityPolicyInterface beperkt cross-site scripting die de Portable Document Format (PDF)-uitvoer beïnvloedt en contentinjectie door niet-toegestane tags, attributen en CSS op de parselaag te verwijderen voordat de renderer draait. ExternalResourcePolicyInterface beperkt server-side request forgery, decompressiebommen en cumulatieve-groottebommen door standaard alles te weigeren en elke ophaalactie te begrenzen op schema, grootte, diepte en domein. Limieten voor invoergrootte, nestingdiepte, lettertypeglyphs en importdiepte beperken resource-uitputting. Omdat elk beleid een contract is, kun je de perimeter verstevigen zonder de engine te forken, en wordt de beleidsnaam beschikbaar gemaakt voor auditlogging. Behandel alle HTML, alle URL’s en alle lettertype- en afbeeldingsbytes als vijandig. Deze pagina is gemarkeerd als export_control_class: legal-review-required omdat de contracts cryptografisch beleid regelen; de tekst parafraseert alle normatieve bronnen en citeert er niet letterlijk uit.

BeweringStandaardClausuleBewijs
Ongelimiteerde URL-verwerking kan via URL-wijzigingen toegangscontrole omzeilen; het externe-resourcebeleid beperkt dit met standaardinstellingen die alles weigeren en een toegestane-domeinlijst met exacte overeenkomst.OWASP Top 10 2025A01
Externe componenten mogen alleen uit officiële herkomsten en via veilig transport worden betrokken; het beleid ondersteunt dit via toegestane-schemalijsten.OWASP Top 10 2025Softwareketen

Beide punten parafraseren OWASP-richtlijnen. De pagina verwijst per clausule naar OWASP-materiaal; de engine geeft de tekst ervan niet weer.

Core definieert de drie beleidscontracts en legt ze vast. Het levert tolerante standaardinstellingen voor ontwikkeling en strenge standaardinstellingen voor het resourcebeleid dat alles weigert. De Enterprise-editie levert een FIPS 140-3-profiel achter CryptoPolicyInterface, zodat een gereguleerde deployment een gevalideerde algoritmehouding krijgt zonder de code voor ondertekening of versleuteling te wijzigen. Het contractoppervlak is identiek voor alle edities. Het verschil is de beleidsimplementatie die je injecteert.