Enterprise รุ่น
Content Disarm and Reconstruction — เอกสารอ้างอิงเชิงลึก
ภาพรวมโดยย่อ
หัวข้อที่มีชื่อว่า “ภาพรวมโดยย่อ”หน้านี้เป็นการอ้างอิงเชิงลึกสำหรับโมดูล NextPDF\Enterprise\Security\Cdr โมดูลนี้ปลดอาวุธ PDF ที่ไม่น่าเชื่อถือและสร้างไฟล์สะอาดขึ้นใหม่จากอ็อบเจกต์ที่ปลอดภัยของมัน ไปป์ไลน์คือ: แจงส่วน ควบคุมการรับเข้า ตรวจจับภัยคุกคาม กรอง ขัดล้างการอ้างอิง สร้างใหม่ ผลลัพธ์เป็นการฉายด้านความปลอดภัยของอินพุต ไม่ใช่สำเนาเชิงหลักฐานเลย สำหรับคำแนะนำด้านเวิร์กโฟลว์ ให้อ่านหน้าความสามารถ CDRก่อน
ความพร้อมใช้งานและการออกใบอนุญาต
หัวข้อที่มีชื่อว่า “ความพร้อมใช้งานและการออกใบอนุญาต”ความสามารถนี้จัดส่งใน NextPDF Enterprise (nextpdf/enterprise) และเปิดใช้งานด้วยซองใบอนุญาตระดับ Enterprise การนำไปใช้งานที่ไม่มีสิทธิ์ดังกล่าวจะไม่โหลดคลาสของความสามารถนี้ เปรียบเทียบรุ่นและรับใบอนุญาต
พื้นผิว Public API
หัวข้อที่มีชื่อว่า “พื้นผิว Public API”| สัญลักษณ์ | พารามิเตอร์ | พฤติกรรมเริ่มต้น | ค่าที่คืน | โยนหรือล้มเหลวด้วย | หมายเหตุ |
|---|---|---|---|---|---|
CdrEngine::__construct | ไม่มี | สร้างตัวตรวจจับและตัวสร้างใหม่ภายใน | CdrEngine | ไม่ประกาศอะไรไว้ | ไม่มีผู้ร่วมงานที่ฉีดเข้าได้ |
CdrEngine::sanitize | string $pdfData, ?CdrPolicy $policy = null | รันไปป์ไลน์เต็มภายใต้ CdrPolicy::standard() | CdrResult | ไม่โยนบนอินพุตที่เป็นภัย การล้มเหลวในการแจงส่วนและการรับเข้าจะคืนผลลัพธ์ที่ถูกปฏิเสธ | ผลลัพธ์รายงานการปฏิเสธแยกจากการชำระล้างอย่างชัดเจน |
CdrPolicy::__construct | พารามิเตอร์แบบมีชื่อที่เลือกได้เจ็ดตัว ดูที่เฟนซ์ | ชุดกำจัดว่างเปล่า; allowUriActions เป็น false; flattenIncrementalUpdates เป็น true; ขีดจำกัด 100000 อ็อบเจกต์, 256 MiB ที่ถอดรหัสแล้ว, 10000 หน้า, อัตรา 1000.0 | CdrPolicy | ไม่ประกาศอะไรไว้ | final readonly; รายการ removeThreatTypes ที่ว่างเปล่าจะไม่ตรวจจับอะไรเลย |
CdrPolicy::standard | ไม่มี | ชุดภัยคุกคามแบบเดิม; กำจัด URI actions; ขีดจำกัดเริ่มต้น | self | ไม่ประกาศอะไรไว้ | ยกเว้นเคส Strip* ที่สูญเสียข้อมูลทั้งเจ็ด |
CdrPolicy::paranoid | ไม่มี | ชุดภัยคุกคามแบบเดิมพร้อมขีดจำกัดที่เข้มขึ้น: 50000 อ็อบเจกต์, 128 MiB, 5000 หน้า, อัตรา 100.0 | self | ไม่ประกาศอะไรไว้ | ยกเว้นเคส Strip* ที่สูญเสียข้อมูลทั้งเจ็ด |
CdrPolicy::permissive | ไม่มี | กำจัดเฉพาะ JavaScript, LaunchAction, NamedJavaScript, SubmitForm, ImportData; คงไว้ซึ่ง URI actions | self | ไม่ประกาศอะไรไว้ | มีไว้สำหรับแหล่งที่น่าเชื่อถือ |
CdrPolicy::allThreatTypes | ไม่มี | คืนทุกเคสของ ThreatType รวมถึงเคส Strip* ที่สูญเสียข้อมูล | list<ThreatType> | ไม่ประกาศอะไรไว้ | การเลือกเข้าใช้แบบ strip สูงสุดอย่างชัดแจ้ง |
CdrPolicy::legacyThreatTypes | ไม่มี | คืนทุกเคสยกเว้นเคส Strip* ทั้งเจ็ด | list<ThreatType> | ไม่ประกาศอะไรไว้ | ชุดกำจัดเริ่มต้นสำหรับ standard() และ paranoid() |
CdrPolicy::shouldRemove | ThreatType $type | ทดสอบความเป็นสมาชิกกับ removeThreatTypes | bool | ไม่ประกาศอะไรไว้ | คืน false สำหรับ UriAction เมื่อ allowUriActions เป็น true |
ThreatDetector::detect | PdfReader $reader, CdrPolicy $policy | สแกนทุกอ็อบเจกต์และแคตาล็อกในเทรลเลอร์เพื่อหาชนิดภัยคุกคามของนโยบาย | list<DetectedThreat> | ไม่โยน; อ็อบเจกต์ที่แจงส่วนไม่ได้จะกลายเป็นภัยคุกคาม UnparseableObject | การสแกนแคตาล็อกครอบคลุมทรี /Names/JavaScript |
CdrRebuilder::rebuild | PdfReader $reader, list<int> $safeObjNums, list<int> $removedObjNums, CdrPolicy $policy | ทำให้อ็อบเจกต์ที่ปลอดภัยเป็นอนุกรมลงในไฟล์ %PDF-2.0 รีวิชันเดียว | string | ไม่ประกาศอะไรไว้; อ็อบเจกต์ที่อ่านซ้ำไม่ผ่านหรือตรวจสอบ /Length ไม่ผ่านจะถูกข้าม | $policy สงวนไว้สำหรับการปรับแต่งการทำอนุกรมในอนาคต |
DetectedThreat::__construct | ThreatType $type, int $objectNumber, string $description, string $location = '' | อ็อบเจกต์ค่าของสิ่งที่ตรวจพบซึ่งไม่เปลี่ยนแปลง | DetectedThreat | ไม่ประกาศอะไรไว้ | คุณสมบัติทั้งสี่เป็น public readonly |
ThreatType | enum ที่หนุนด้วย string | ยี่สิบเคส: สิบสามเคสแบบเดิมบวกเจ็ดเคส Strip* แบบเลือกเข้าใช้ | ไม่มี | ไม่มี | ดูรายการเคสด้านล่าง |
ลายเซ็นจุดเข้า
หัวข้อที่มีชื่อว่า “ลายเซ็นจุดเข้า”final class CdrEngine{ public function __construct()
public function sanitize(string $pdfData, ?CdrPolicy $policy = null): CdrResult}final readonly class CdrPolicy{ public function __construct( public array $removeThreatTypes = [], public bool $allowUriActions = false, public bool $flattenIncrementalUpdates = true, public int $maxObjects = 100_000, public int $maxDecodedStreamBytes = 268_435_456, public int $maxPageCount = 10_000, public float $maxInflationRatio = 1000.0, )
public static function standard(): self
public static function paranoid(): self
public static function permissive(): self
public static function allThreatTypes(): array
public static function legacyThreatTypes(): array
public function shouldRemove(ThreatType $type): bool}final class ThreatDetector{ public function detect(PdfReader $reader, CdrPolicy $policy): array}final class CdrRebuilder{ public function rebuild(PdfReader $reader, array $safeObjNums, array $removedObjNums, CdrPolicy $policy): string}final readonly class DetectedThreat{ public function __construct( public ThreatType $type, public int $objectNumber, public string $description, public string $location = '', )}enum ThreatType: stringรายการเคสของ ThreatType
หัวข้อที่มีชื่อว่า “รายการเคสของ ThreatType”เคสแบบเดิมสิบสามเคสประกอบเป็นชุดกำจัดเริ่มต้น เคส Strip* สูญเสียข้อมูลโดยการออกแบบและจะไม่เข้าสู่นโยบายเริ่มต้นเลย
| เคส | ค่าที่หนุน | พื้นผิวการตรวจจับ |
|---|---|---|
ThreatType::JavaScript | javascript | คีย์ /JS บนอ็อบเจกต์ใดๆ หรือ action /S /JavaScript |
ThreatType::AdditionalActions | additional-actions | ดิกชันนารี /AA บนอ็อบเจกต์ใดๆ |
ThreatType::OpenAction | open-action | คีย์ /OpenAction บนอ็อบเจกต์ใดๆ |
ThreatType::LaunchAction | launch-action | action /S /Launch |
ThreatType::RemoteGoTo | remote-goto | action /S /GoToR หรือ /S /GoToE |
ThreatType::SubmitForm | submit-form | action /S /SubmitForm |
ThreatType::ImportData | import-data | action /S /ImportData |
ThreatType::EmbeddedFiles | embedded-files | ทรีชื่อ /EmbeddedFiles หรือดิกชันนารี /EF |
ThreatType::RichMedia | rich-media | /Subtype /RichMedia |
ThreatType::NamedJavaScript | named-javascript | ทรีชื่อ /Names/JavaScript ในแคตาล็อก |
ThreatType::UriAction | uri-action | action /S /URI; ระงับเมื่อ allowUriActions เป็น true |
ThreatType::Xfa | xfa | คีย์ /XFA |
ThreatType::UnparseableObject | unparseable-object | อ็อบเจกต์หรือแคตาล็อกใดๆ ที่แจงส่วนไม่สำเร็จ |
ThreatType::StripJavaScript | strip-javascript | ซูเปอร์เซตแบบเลือกเข้าใช้: คีย์ /JS, /S /JavaScript, หรือ /Subtype /JavaScript |
ThreatType::StripEmbeddedFiles | strip-embedded-files | เลือกเข้าใช้: /Type /EmbeddedFile, /Type /Filespec, /EmbeddedFiles, หรือ /EF |
ThreatType::StripFormFields | strip-form-fields | เลือกเข้าใช้: /Subtype /Widget, คีย์ /FT, หรือคีย์ /AcroForm |
ThreatType::StripAnnotationsRich | strip-annotations-rich | subtype แบบเลือกเข้าใช้: Movie, Sound, FileAttachment, 3D, RichMedia, Screen |
ThreatType::StripOcgNonDefault | strip-ocg-non-default | เลือกเข้าใช้: /Type /OCG ที่มีคีย์ /Usage หรือ /Visibility |
ThreatType::StripDigitalSignaturesAtRebuild | strip-digital-signatures-at-rebuild | เลือกเข้าใช้: /Type /Sig, /FT /Sig, /DSS, /VRI, หรือ /ByteRange |
ThreatType::Strip3dAndRichMedia | strip-3d-and-rich-media | subtype แบบเลือกเข้าใช้: 3D, U3D, PRC, RMF, RichMedia, Sound, Movie |
สัญญาพฤติกรรม
หัวข้อที่มีชื่อว่า “สัญญาพฤติกรรม”CdrEngine::sanitize ดำเนินการหกเฟสตามลำดับและไม่เคยโยนสำหรับอินพุตที่เป็นภัย
- แจงส่วน การแจงส่วนล้มเหลวจะคืนผลลัพธ์ที่มี
admittedเป็น false และเหตุผลการปฏิเสธแบบข้อผิดพลาดในการแจงส่วน ผลลัพธ์ที่ชำระล้างแล้วจะว่างเปล่าในกรณีนั้น - ควบคุมการรับเข้า จำนวนอ็อบเจกต์ ผลรวมไบต์ของสตรีมที่ถอดรหัสแล้ว อัตราการขยายต่อสตรีม และจำนวนหน้าจะถูกตรวจสอบกับขีดจำกัดของนโยบาย เอกสารที่เกินขีดจำกัดจะถูกปฏิเสธ ไม่ใช่ถูกชำระล้าง การปฏิเสธและการชำระล้างถูกรายงานแยกจากกันอย่างชัดเจน
- ตรวจจับ
ThreatDetector::detectสแกนทุกอ็อบเจกต์และแคตาล็อกในเทรลเลอร์เพื่อหาชนิดภัยคุกคามของนโยบาย อ็อบเจกต์ที่แจงส่วนไม่ได้จะถูกบันทึกเป็นสิ่งที่ตรวจพบชนิดThreatType::UnparseableObjectแทนที่จะถูกข้าม - กรอง อ็อบเจกต์ที่มีสิ่งที่ตรวจพบจะถูกจัดคิวเพื่อกำจัด แคตาล็อกเอกสารจะไม่ถูกกำจัดในฐานะอ็อบเจกต์ทั้งก้อนเลย สิ่งที่ตรวจพบระดับแคตาล็อก (
OpenAction,AdditionalActions,NamedJavaScript) จะได้รับการแก้ไขด้วยการลอกคีย์ออกแทน - ขัดล้างการอ้างอิง ทุกการอ้างอิงทางอ้อมไปยังอ็อบเจกต์ที่ถูกกำจัดจะถูกแทนที่ด้วย
nullระหว่างการทำอนุกรม - สร้างใหม่
CdrRebuilder::rebuildปล่อยไฟล์%PDF-2.0รีวิชันเดียวพร้อมอ็อบเจกต์ที่ถูกกำหนดหมายเลขใหม่ ตารางการอ้างอิงข้ามแบบคลาสสิก และเทรลเลอร์ใหม่ ไบต์ของสตรีมที่ปลอดภัยถูกคัดลอกแบบไบต์ต่อไบต์เหมือนกันทุกประการ แคตาล็อกที่สร้างใหม่ทิ้ง/OpenAction,/AA, และ/Names;/AAถูกทิ้งจากทุกอ็อบเจกต์
CdrResult ที่คืนมาเปิดเผยไบต์ที่สร้างใหม่ รายการภัยคุกคามที่ถูกกำจัด ขนาดไบต์ทั้งสองด้าน ธงการรับเข้า และเหตุผลการปฏิเสธ หากต้นฉบับมี /Root ที่แก้ค่าได้และผลลัพธ์ที่สร้างใหม่สูญเสียมันไป เอนจินจะปฏิเสธผลลัพธ์แทนที่จะคืนไฟล์ที่เสียหายเชิงโครงสร้าง นี่คือการรับประกันแบบ fail-closed: admitted เป็น true บ่งชี้ว่าผลลัพธ์ยังคงมีการอ้างอิงแคตาล็อกเอกสารอยู่
การอัปเดตเชิงเพิ่มไม่เคยรอด: การสร้างใหม่ทำอนุกรมเพียงรีวิชันเดียวภายใต้ทุกนโยบาย ดังนั้นรีวิชันช่วงหลังแบบเงาจึงถูกทำให้แบนราบโดยโครงสร้าง ลายเซ็นดิจิทัลต้นฉบับไม่สามารถคงความถูกต้องข้ามการสร้างใหม่ได้ เพราะช่วงไบต์ไม่ตรงกับผลลัพธ์อีกต่อไป
เส้นแดงเชิงสถาปัตยกรรม CDR เป็นชั้นการฉายด้านความปลอดภัย ไม่ใช่ชั้นการเก็บรักษา ต้องไม่ใช้ผลลัพธ์เพื่อการเก็บรักษาหลักฐานทางกฎหมาย การเปรียบเทียบแฮชกับต้นฉบับ หรือสำเนาเพื่อการเก็บถาวร
เคสขอบและโหมดความล้มเหลว
หัวข้อที่มีชื่อว่า “เคสขอบและโหมดความล้มเหลว”- นโยบาย
nullจะแก้ค่าเป็นCdrPolicy::standard()นโยบายที่สร้างด้วยremoveThreatTypesว่างเปล่าเริ่มต้นจะตรวจจับและกำจัดไม่ได้อะไรเลย - การตั้ง
allowUriActionsเป็นtrueจะระงับการกำจัดUriActionแม้เคสจะปรากฏอยู่ในremoveThreatTypes flattenIncrementalUpdatesเป็นเชิงประกาศในรีลีสนี้: การสร้างใหม่ปล่อยรีวิชันเดียวภายใต้ทุกนโยบาย รวมถึงpermissive()ซึ่งตั้งธงเป็นfalse- การตรวจสอบอัตราการขยายถือว่าความยาวสตรีมดิบเป็นศูนย์นับเป็นหนึ่ง ดังนั้นสตรีมที่ขยายจากศูนย์ยังคงถูกกำหนดขอบเขต เมื่อไม่มีการเก็บรูปแบบที่ถอดรหัสไว้ ความยาวสตรีมดิบจะนับรวมเข้าในงบประมาณรวม
- การตรวจสอบการรับเข้าด้วยจำนวนหน้าทำได้เท่าที่พยายาม: การอ่านแคตาล็อกหรือทรีหน้าล้มเหลวจะไม่ปฏิเสธเอกสารด้วยตัวมันเอง งบประมาณจำนวนอ็อบเจกต์และการคลายบีบอัดถูกบังคับใช้เสมอ
- อ็อบเจกต์ที่ความยาวสตรีมดิบขัดแย้งกับรายการ
/Lengthแบบจำนวนเต็มของมันจะถูกข้ามตอนสร้างใหม่ (การป้องกัน polyglot) การอ้างอิงไปยังอ็อบเจกต์ที่ถูกข้ามเช่นนั้นจะยังคงเลขอ็อบเจกต์ต้นทางไว้และอาจแก้ค่าไม่ได้ในผลลัพธ์sanitize()ปฏิเสธผลลัพธ์ที่เสียหายอย่างตรวจพบได้ (/Rootที่หายไป) แต่ผู้เรียกที่ขับCdrRebuilder::rebuild()ระดับต่ำโดยตรงต้องตรวจสอบโครงสร้างผลลัพธ์และความสมบูรณ์ของการอ้างอิงด้วยตนเอง - เมื่อเทรลเลอร์ต้นฉบับมี
/IDเทรลเลอร์ที่สร้างใหม่จะมี/IDแบบสุ่มที่สร้างขึ้นใหม่ ไม่ใช่ตัวเดิม รายการเทรลเลอร์อื่นๆ รวมถึง/Infoจะไม่ถูกนำมาด้วย; เทรลเลอร์ที่สร้างใหม่ถือ/Size,/Rootเมื่อแก้ค่าได้ และ/IDที่สร้างใหม่ - ไบต์ของชื่อและคีย์ที่ถอดรหัสแล้วจะถูกปล่อยออกมาใหม่พร้อม escape แบบเลขฐานสิบหกสำหรับตัวคั่น ช่องว่าง และไบต์ที่พิมพ์ไม่ได้ ดังนั้นชื่อที่เป็นภัยจึงไม่สามารถฉีดไวยากรณ์ดิกชันนารีลงในผลลัพธ์ได้
- ค่าสตริงภายใต้คีย์ดิกชันนารีนอกชุดที่มีค่าเป็นชื่อที่รู้จักจะถูกปล่อยออกมาเป็นสตริงตามตัวอักษรอย่างระมัดระวัง
CdrPolicy::legacyThreatTypes()ถือว่าเคส enum ในอนาคตใดๆ เป็นค่ากำจัดเริ่มต้นเว้นแต่จะลงทะเบียนเป็นเคสStrip*ดังนั้นเคสที่สูญเสียข้อมูลใหม่จึงไม่สามารถเข้าสู่นโยบายเริ่มต้นอย่างเงียบๆ ได้- CDR ไม่ใช่โมดูลการเข้ารหัส การใช้ความสุ่มเพียงอย่างเดียวของมันคือ
/IDในเทรลเลอร์ที่สร้างใหม่ การตรวจสอบลายเซ็นอยู่นอกขอบเขตที่นี่ ดูการอ้างอิงเชิงลึกของลายเซ็น
ความสอดคล้อง
หัวข้อที่มีชื่อว่า “ความสอดคล้อง”| ข้ออ้าง | มาตรฐาน | ข้อกำหนด |
|---|---|---|
| การเรียก action แบบ ECMAScript ทำให้ตัวประมวลผล PDF รันสคริปต์ที่ฝังอยู่ | ISO 32000-2 | §12.6.4.17 |
สคริปต์ระดับเอกสารในทรีชื่อ JavaScript ทั้งหมดจะรันเมื่อเอกสารเปิดขึ้น | ISO 32000-2 | §12.6.4.17 |
ดิกชันนารีชื่อในแคตาล็อกอาจถือทรีชื่อ JavaScript ของ action สคริปต์ระดับเอกสาร | ISO 32000-2 | §7.7.4 (Table 32) |
| launch action เปิดใช้แอปพลิเคชัน หรือเปิดหรือพิมพ์เอกสาร | ISO 32000-2 | §12.6.4.6 |
ดิกชันนารี additional-actions /AA ขยายเหตุการณ์ทริกเกอร์บน annotation หน้า ฟิลด์ และแคตาล็อก | ISO 32000-2 | §12.6.3 |
| การรับไฟล์ที่ไม่น่าเชื่อถือต้องกำหนดขอบเขตการมีอยู่ ปริมาณ และเนื้อหาของไฟล์ที่เข้ามา | OWASP ASVS 5.0 | §5.2 |
| ระบบควรป้องกันการรันไฟล์ที่อัปโหลดอย่างไม่เหมาะสมและตรวจจับเนื้อหาอันตราย | OWASP ASVS 5.0 | §5.3 |
ทุกข้อกำหนดถูกถอดความ; NextPDF ไม่ทำซ้ำข้อความเชิงบรรทัดฐาน NextPDF ไม่กล่าวอ้างการรับรองใดๆ CDR กำจัดพื้นผิวเนื้อหาที่ทำงานได้ซึ่งระบุโดย ThreatType ภายใต้นโยบายที่กำหนดค่าไว้; มันเป็นความสามารถ ไม่ใช่เครื่องมือชำระล้างที่ได้รับการรับรอง CDR ไม่ใช่โปรแกรมสแกนไวรัสและไม่ตรวจจับลายเซ็นมัลแวร์; มันเสริม และไม่ทำให้สมบูรณ์แทน การควบคุมอย่างเช่นการสแกนไวรัสตาม OWASP ASVS 5.4.3 ว่าไฟล์ที่ถูกปลดอาวุธจะยอมรับได้สำหรับไปป์ไลน์การรับใดหนึ่งหรือไม่ยังคงเป็นการตัดสินใจด้านความเสี่ยงของผู้ปฏิบัติการ
บันทึกการพัฒนา
หัวข้อที่มีชื่อว่า “บันทึกการพัฒนา”- ซอร์สของโมดูลถือ
@since 1.9.0; การอ้างอิงนี้บันทึกพื้นผิวตามที่จัดส่งในnextpdf/enterprise3.1.0 - ทุกอย่างรันในกระบวนการบนโฮสต์ของคุณ ไม่มีการเข้าถึงเครือข่ายเกิดขึ้นระหว่างการชำระล้าง
CdrPolicyและDetectedThreatเป็นfinal readonly; สร้างอินสแตนซ์นโยบายใหม่เพื่อเปลี่ยนขีดจำกัดCdrEngineสร้างตัวตรวจจับและตัวสร้างใหม่ภายในของมันThreatDetectorและCdrRebuilderยังคงใช้ได้โดยตรงสำหรับไปป์ไลน์แบบเป็นขั้นที่จัดหาPdfReaderของตัวเอง- พารามิเตอร์
$policyของCdrRebuilder::rebuildปัจจุบันถูกสงวนไว้; ซอร์สบันทึกว่ามันถูกเก็บไว้เพื่อความเข้ากันได้ของจุดเรียกและการปรับแต่งการทำอนุกรมต่อนโยบายในอนาคต - ผลลัพธ์สามารถทำซ้ำได้เชิงโครงสร้าง ไม่ใช่เชิงบิต:
/IDที่สร้างใหม่แตกต่างกันทุกครั้งที่รันเมื่อต้นฉบับมีมัน - ชนิดผลลัพธ์
CdrResult(ค่าที่คืนของsanitize()) ถูกครอบคลุมเชิงพฤติกรรมด้านบน; ฟิลด์ของมันเป็นpublic readonlyโดยมีhadThreats()และthreatCount()เป็นตัวอำนวยความสะดวก
ดูเพิ่มเติม
หัวข้อที่มีชื่อว่า “ดูเพิ่มเติม”- Content Disarm and Reconstruction (CDR) — หน้าความสามารถพร้อมคำแนะนำด้านเวิร์กโฟลว์และนโยบาย
- ความปลอดภัย — การอ้างอิงเชิงลึก
- การตรวจสอบความถูกต้อง — การอ้างอิงเชิงลึก
- นิติวิทยา — การอ้างอิงเชิงลึก
ขอบเขตการเผยแพร่
หัวข้อที่มีชื่อว่า “ขอบเขตการเผยแพร่”หน้านี้บันทึกพฤติกรรมที่สังเกตได้จากภายนอกและพื้นผิว Public API ที่รองรับเท่านั้น เส้นทาง namespace ภายใน คลาสตัวช่วย ตารางกลไก ชื่อไฟล์ runbook และคำนำหน้าตั๋วอยู่นอกขอบเขต