ข้ามไปยังเนื้อหา

Contracts / นโยบายความปลอดภัย

โดเมน security-policy กำหนด contract แบบปฏิเสธโดยปริยายไว้สามรายการ ได้แก่ CryptoPolicyInterface สำหรับควบคุมการเลือกอัลกอริทึมและคีย์ HtmlSecurityPolicyInterface สำหรับจำกัดขอบเขตฟีเจอร์ของ Hypertext Markup Language (HTML) และ ExternalResourcePolicyInterface สำหรับกำกับการโหลดทรัพยากรระยะไกล เนื่องจากแต่ละรายการเป็น contract คุณจึงสามารถกำหนดนโยบายสำหรับการ deploy ที่เข้มงวดยิ่งขึ้นได้โดยไม่ต้อง fork

Terminal window
composer require nextpdf/core:^3

CryptoPolicyInterface เป็นเกตด้านการเข้ารหัสลับ Core เรียกใช้ contract นี้ก่อนขั้นตอนการลงนาม การเข้ารหัสลับ หรือการแฮชทุกรายการ การตรวจสอบครอบคลุมแฮช ตัวระบุออบเจ็กต์ของลายเซ็น (OID) ไซเฟอร์ และความแข็งแรงของคีย์ contract นี้ยังรายงานแฮชขั้นต่ำและชื่อนโยบายสำหรับบันทึกการตรวจสอบด้วย ใช้ contract นี้เพื่อบังคับใช้ชุดกฎ เช่น Federal Information Processing Standards (FIPS) 140-3 หรือ eIDAS โดยไม่ต้องเปลี่ยนโค้ดสำหรับการลงนามและการเข้ารหัสลับ เมื่อไม่ได้กำหนดนโยบายไว้ ทุกอัลกอริทึมจะได้รับอนุญาต ไซต์ที่อยู่ภายใต้การกำกับดูแลจึงต้องกำหนดนโยบายอย่างชัดเจน

HtmlSecurityPolicyInterface ทำงานที่ชั้นการแยกวิเคราะห์ HTML การตรวจสอบจะทำงานก่อนที่เนื้อหาจะไปถึงตัวเรนเดอร์ใด ๆ โดยพิจารณาว่าแท็ก แอตทริบิวต์ พร็อพเพอร์ตี้ Cascading Style Sheets (CSS) หรือสคีมา uniform resource locator (URL) ได้รับอนุญาตหรือไม่ และยังจำกัดขนาดอินพุตกับความลึกของการซ้อนด้วย การตรวจสอบนี้ทำงานร่วมกับนโยบายการขนส่งเฉพาะตัวเรนเดอร์ (Chrome, Cloudflare, Gotenberg) ซึ่งกำหนดขีดจำกัดขนาดและส่วนหัว Content Security Policy (CSP) นโยบาย HTML ช่วยลดพื้นผิวการโจมตีที่ชั้นการแยกวิเคราะห์ แท็กที่ถูกตัดออกจะไม่ไปถึงขั้นตอนการจัดวางเลย เอลิเมนต์ที่ถูกแทรกเข้ามาจึงไม่สามารถเปลี่ยนแปลงเอาต์พุตได้ เมื่อไม่ได้กำหนดนโยบายไว้ ค่าเริ่มต้นจะอนุญาตชุดฟีเจอร์ทั้งหมด

ExternalResourcePolicyInterface ตัดสินว่าไปป์ไลน์ HTML สามารถดึงฟอนต์ สไตล์ชีต หรือรูปภาพภายนอกได้หรือไม่ และกำหนดขีดจำกัดสำหรับการดึงแต่ละครั้งด้วย ท่าทีเริ่มต้นของ contract นี้คือปฏิเสธทั้งหมด ทุกตัวเลือกจะปิดอยู่จนกว่าคุณจะเปิดใช้งาน contract นี้ยึดหลักสิทธิ์น้อยที่สุด HTML ที่ไม่น่าเชื่อถืออาจชี้ไปยัง URL ที่ผู้โจมตีควบคุม contract นี้ควบคุมการดึง @font-face ตามสคีมา ขนาด และจำนวนกลิฟ ควบคุม @import ตามสคีมา ความลึก และขนาดรวม และควบคุม background-image ด้วยรายการสคีมาและรายการโดเมนที่อนุญาตแบบตรงทุกตัวอักษร contract นี้จำกัดขนาด data-URI (Uniform Resource Identifier) และยังควบคุมการอ้างอิงภายนอกของ Scalable Vector Graphics (SVG) ด้วย contract ระบุว่าระบบโปรดักชันต้องปฏิเสธรายการเหล่านั้นเสมอ เพราะเปิดทางให้เกิดการปลอมแปลงคำขอและการแทรกสคริปต์ การดึง URL แบบเปิดเป็นช่องทางการปลอมแปลงคำขอฝั่งเซิร์ฟเวอร์ การควบคุมการเข้าถึงถูกข้ามผ่านได้ด้วยการเปลี่ยน URL ตามที่ระบุไว้ใน Open Worldwide Application Security Project (OWASP) Top 10 2025 การจัดหาคอมโพเนนต์ภายนอกต้องจำกัดอยู่ที่แหล่งที่เป็นทางการและการขนส่งที่ปลอดภัยเท่านั้น

ชนิดประเภทสมาชิกหลักเสถียรภาพตั้งแต่
CryptoPolicyInterfaceinterfaceisHashAlgorithmAllowed(), isSignatureAlgorithmAllowed(), isEncryptionAlgorithmAllowed(), isKeyStrengthAllowed(), getPreferredHashAlgorithm(), getName()เสถียร1.9.0
HtmlSecurityPolicyInterfaceinterfaceisTagAllowed(), isAttributeAllowed(), isCssPropertyAllowed(), isUrlSchemeAllowed(), getMaxInputSize(), getMaxNestingDepth(), getName()เสถียร3.1.0
ExternalResourcePolicyInterfaceinterfaceisFontFaceAllowed(), getAllowedFontSchemes(), getMaxFontFileSize(), getMaxFontGlyphs(), isImportAllowed(), getMaxImportDepth(), isBackgroundImageAllowed(), getAllowedImageDomains(), getMaxDataUrlSize(), isSvgExternalReferenceAllowed()เสถียร4.0.0

ExternalResourcePolicyInterface คืนค่าขีดจำกัดที่มีชนิดข้อมูลกำกับ ได้แก่ ขนาดแบบ positive-int ความลึกของการ import แบบ int<1, 100> และรายการสคีมากับโดเมนแบบ list<non-empty-string> การนำไปใช้งานค่าเริ่มต้นจะปฏิเสธทุกความสามารถ

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);
}

ฟังก์ชันนี้ขึ้นอยู่กับ 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.');
}
}
}

เกตนี้บังคับใช้ขีดจำกัดอินพุตและปฏิเสธนโยบายทรัพยากรที่ไม่ปลอดภัยก่อนที่ไปป์ไลน์จะทำงาน พร้อมบันทึกชื่อนโยบายไว้สำหรับการตรวจสอบและโยน exception ที่เจาะจง

  • CryptoPolicyInterface จะอนุญาตทุกอัลกอริทึมเมื่อไม่ได้กำหนดนโยบายไว้ ค่าเริ่มต้นแบบเปิดมีไว้เพื่อความสะดวกในการพัฒนา ไม่ใช่ท่าทีสำหรับโปรดักชัน ต้องกำหนดนโยบายอย่างชัดเจนในการ deploy ที่อยู่ภายใต้การกำกับดูแลทุกครั้ง
  • HtmlSecurityPolicyInterface::getMaxInputSize() คืนค่า 0 เพื่อหมายถึงไม่จำกัด ให้ถือว่า 0 หมายถึง “ไม่มีขีดจำกัดจากนโยบาย” ไม่ใช่ “ปฏิเสธทั้งหมด” และควรกำหนดขีดจำกัดที่ชั้นการขนส่งด้วยเช่นกัน
  • ExternalResourcePolicyInterface เป็นแบบปฏิเสธทั้งหมดโดยค่าเริ่มต้น การเปิดใช้งาน @font-face หรือ background-image โดยไม่กำหนดรายการสคีมาจะเปิดพื้นผิวการปลอมแปลงคำขอ จึงควรกำหนดรายการที่อนุญาตไปพร้อมกัน
  • รายการโดเมนที่อนุญาตว่างเปล่าใน getAllowedImageDomains() หมายความว่าทุกโดเมนได้รับอนุญาตเมื่อเปิดใช้งานภาพพื้นหลังแล้ว รายการว่างเปล่าไม่ใช่กฎการปฏิเสธ จึงต้องระบุโดเมนอย่างชัดเจน
  • isSvgExternalReferenceAllowed() ควรคืนค่า false ในระบบโปรดักชัน contract ระบุเรื่องนี้ไว้ในเอกสาร นโยบายที่คืนค่า true ถือเป็นข้อค้นพบ ไม่ใช่ตัวเลือกสำหรับการกำหนดค่า

การตรวจสอบนโยบายเป็นการเรียก predicate แบบ O(1) โดยไม่มีต้นทุนที่แปรผันตามอินพุต ระบบจะตรวจสอบนโยบายระหว่างการแยกวิเคราะห์สำหรับแต่ละแท็ก แต่ละแอตทริบิวต์ แต่ละพร็อพเพอร์ตี้ CSS และแต่ละ URL เอกสารที่ผิดปกติจะทำให้จำนวนการเรียกเพิ่มทวีคูณ แต่การเรียกแต่ละครั้งยังคงใช้เวลาคงที่ performance_budget ที่ 1500 ms ของเวลานาฬิกาและ 64 MB ของจุดสูงสุดถูกครอบงำโดยการแยกวิเคราะห์และการเรนเดอร์ ไม่ใช่การประเมินนโยบาย ขีดจำกัดขนาดอินพุตและความลึกของการซ้อนเป็นตัวจำกัดต้นทุนของตัวแยกวิเคราะห์เอง นโยบายที่เข้มงวดช่วยปรับปรุงประสิทธิภาพในกรณีเลวร้ายที่สุดด้วยการปฏิเสธเอกสารที่มีขนาดใหญ่เกินไปหรือซ้อนลึกก่อนการจัดวาง

contract เหล่านี้ประกอบกันเป็นแนวป้องกันของเอนจิน ดังนั้นจึงระบุโมเดลภัยคุกคามไว้อย่างชัดเจน CryptoPolicyInterface ลดความเสี่ยงจากการลดระดับอัลกอริทึมด้วยการปิดกั้นแฮชที่อ่อนแอและคีย์ที่สั้นก่อนการดำเนินการใด ๆ HtmlSecurityPolicyInterface ลดความเสี่ยงจาก cross-site scripting ที่ส่งผลต่อเอาต์พุต Portable Document Format (PDF) และจากการแทรกเนื้อหา ด้วยการตัดแท็ก แอตทริบิวต์ และ CSS ที่ไม่ได้รับอนุญาตออกที่ชั้นการแยกวิเคราะห์ก่อนที่ตัวเรนเดอร์จะทำงาน ExternalResourcePolicyInterface ลดความเสี่ยงจากการปลอมแปลงคำขอฝั่งเซิร์ฟเวอร์ decompression bomb และ cumulative-size bomb ด้วยค่าเริ่มต้นแบบปฏิเสธทั้งหมด และจำกัดการดึงทุกครั้งตามสคีมา ขนาด ความลึก และโดเมน ขีดจำกัดขนาดอินพุต ความลึกของการซ้อน จำนวนกลิฟฟอนต์ และความลึกของการ import ช่วยลดความเสี่ยงจากการใช้ทรัพยากรจนหมด เนื่องจากแต่ละนโยบายเป็น contract คุณจึงสามารถเสริมความแข็งแกร่งให้แนวป้องกันได้โดยไม่ต้อง fork เอนจิน และระบบจะเปิดเผยชื่อนโยบายไว้สำหรับบันทึกการตรวจสอบ ให้ถือว่า HTML ทั้งหมด URL ทั้งหมด และไบต์ของฟอนต์กับรูปภาพทั้งหมดเป็นภัยคุกคาม หน้านี้ถูกทำเครื่องหมายเป็น export_control_class: legal-review-required เนื่องจาก contract เหล่านี้กำกับนโยบายการเข้ารหัสลับ เนื้อความสรุปแหล่งข้อมูลเชิงบรรทัดฐานทั้งหมดด้วยถ้อยคำของตนเองและไม่อ้างอิงข้อความใดโดยตรง

ข้อกล่าวอ้างมาตรฐานข้อกำหนดหลักฐาน
การจัดการ URL ที่ไม่มีข้อจำกัดทำให้การเปลี่ยน URL ข้ามผ่านการควบคุมการเข้าถึงได้ นโยบายทรัพยากรภายนอกลดความเสี่ยงนี้ด้วยค่าเริ่มต้นแบบปฏิเสธทั้งหมดและรายการโดเมนที่อนุญาตแบบตรงทุกตัวอักษรOWASP Top 10 2025A01
การจัดหาคอมโพเนนต์ภายนอกต้องจำกัดอยู่ที่แหล่งที่เป็นทางการและการขนส่งที่ปลอดภัย นโยบายรองรับข้อกำหนดนี้ผ่านรายการสคีมาที่อนุญาตOWASP Top 10 2025ห่วงโซ่อุปทานซอฟต์แวร์ (Software supply chain)

ทั้งสองประเด็นเป็นการสรุปแนวทางของ OWASP ด้วยถ้อยคำของตนเอง หน้านี้อ้างอิงเอกสารของ OWASP ตามข้อกำหนด โดยเอนจินไม่ได้ทำซ้ำข้อความดังกล่าว

Core กำหนดและตรึง contract นโยบายทั้งสามรายการ Core มาพร้อมค่าเริ่มต้นแบบอนุญาตกว้างสำหรับการพัฒนา และค่าเริ่มต้นแบบเข้มงวดสำหรับนโยบายทรัพยากรแบบปฏิเสธทั้งหมด รุ่น Enterprise มาพร้อมโปรไฟล์ FIPS 140-3 ที่อยู่เบื้องหลัง CryptoPolicyInterface ดังนั้นการ deploy ที่อยู่ภายใต้การกำกับดูแลจึงได้ท่าทีด้านอัลกอริทึมที่ผ่านการตรวจสอบแล้ว โดยไม่ต้องเปลี่ยนโค้ดสำหรับการลงนามหรือการเข้ารหัสลับ ขอบเขตของ contract เหมือนกันในทุกรุ่น ความแตกต่างอยู่ที่การนำนโยบายไปใช้งานที่คุณ inject เข้าไป

  • Contracts: อินเทอร์เฟซสาธารณะ 41 รายการ (service provider interface, SPI) — ภาพรวมและระดับความเสถียร
  • Contracts / SigningCryptoPolicyInterface ที่นำไปใช้กับการลงนาม
  • Contracts / Document — จุดเข้า writeHtml() และ image() ที่นโยบายเหล่านี้ควบคุม
  • Security — ขอบเขตการเข้ารหัสลับที่นโยบายการเข้ารหัสลับจำกัดไว้
  • HTML — ไปป์ไลน์การแยกวิเคราะห์ที่นโยบาย HTML และนโยบายทรัพยากรปกป้องไว้
  • Audit — การบันทึกการตรวจสอบชื่อนโยบาย