تخطَّ إلى المحتوى

الأمان والتشغيل في compat-legacy

يستخدم المحوِّل نموذج الأمان الخاص بمحرِّك ⁨NextPDF⁩، ويضيف بعض إجراءات التحصين المقصودة فوق ⁨TCPDF 6.2.13⁩ القديم. توضِّح هذه الصفحة بدقة ما هو متاح وما هو غير متاح، من غير مبالغة. اقرأ قسم التوقيع بعناية؛ فنطاقه محدود عن قصد.

السلوكيات القديمة المُحصَّنة

قسم بعنوان «السلوكيات القديمة المُحصَّنة»

يغيِّر المحوِّل ثلاثة سلوكيات تاريخية في ⁨TCPDF 6.2.13⁩ لأسباب تتعلق بالسلامة. وهذه السلوكيات غير قابلة للضبط للرجوع إلى الصيغة غير الآمنة:

المجال محل الاهتمام⁨TCPDF 6.2.13⁩ القديمالمحوِّل
معالجة الأخطاءيستدعي Error() الدالة die() وينهي العمليةيطرح Error() استثناء RuntimeException؛ ويمكن للمستدعِين رصد الفشل والتعامل معه، من غير إنهاء العملية بصمت.
تنفيذ ⁨HTML⁩يمكن لمنفذ التفلُّت أن يشغِّل ⁨PHP⁩ من الترميزالثابت K_TCPDF_CALLS_IN_HTML مُثبَّت على false؛ ولا يمكن للترميز أن يطلق تنفيذ ⁨PHP.⁩
الإخراج المباشريطبع Output() إلى مخزن الإخراج النشطيمر الإخراج عبر جسر وجهة آمن، ولا يلوِّث مخزن إخراج يتحكم فيه المستدعِي.

يضمن تغيير معالجة الأخطاء إمكانية رصد الفشل بدلاً من فقدان العملية بسبب الإنهاء. ينص معيار التحقق من أمان التطبيقات (⁨ASVS⁩) 5.0 الصادر عن مشروع أمان تطبيقات الويب المفتوح عالميًا (⁨OWASP⁩) في §16.5.3 على أن التطبيق ينبغي أن يفشل بسلاسة وبأمان، وأن يمنع حالات الفشل المفتوح. يطبِّق تغيير “الطرح بدلاً من الإنهاء” هذا المبدأ. ويزيل تحصين ⁨HTML⁩ منفذًا كان يتيح تنفيذ الشيفرة. عامِل الشيفرة القديمة التي اعتمدت على السلوك القديم باعتبارها خللاً يجب إصلاحه أثناء /⁨integrations/tcpdf-compat/migration/.⁩ يوجد ملخص البند المثبَّت في مقدمة الصفحة citations.

يكشف المحوِّل دالة SetProtection() الخاصة بـ ⁨TCPDF⁩، ويفوِّض إلى معالج الأمان القياسي لمحرِّك ⁨NextPDF.⁩

  • يستخدم المعالج القياسي ⁨AES-256⁩. يُقبَل المعامل القديم $mode من أجل توافق توقيع الدالة ويُتجاهَل؛ ولا توجد طريقة لاختيار شيفرة تشفير أضعف عبر هذه الدالة. عند تفعيل الوضع الصارم، يطرح $mode غير الافتراضي استثناءً، بحيث تُجبَر عملية الترحيل على الإقرار به (مؤكَّد في tests/Unit/Compat/Tcpdf/TcpdfStrictModeTest.php).
  • إذا لم تُقدَّم كلمة مرور للمالك، يولِّد المحوِّل كلمة مرور مالك عشوائية وقوية تشفيريًا بدلاً من إعادة استخدام كلمة مرور المستخدم. يمنع هذا حائزي الوصول بمستوى المستخدم من الحصول على تحكُّم بمستوى المالك في المستند.
  • لا يُجرى التشفير المستند إلى الشهادات (المفتاح العام) عبر SetProtection()؛ إذ يتجاهل المحوِّل معاملها $pubkeys. استخدم نقطة دخول تشفير المفتاح العام الحديثة المكشوفة على المحوِّل (setPublicKeyEncryption())، فهي تفوِّض إلى المحرِّك.

يعكس سلوك التشفير معالج الأمان القياسي الموصوف في ⁨ISO 32000-2⁩ §7. يعرِّف ذلك البند مدخلات قاموس التشفير ومعالج ⁨AES-256⁩ القياسي الذي يستخدمه المحرِّك. لا يدّعي هذا التوثيق أن المُخرَج “آمن افتراضيًا” أو “مقاوم للعبث”. بل يوضِّح فقط شيفرة التشفير المستخدمة وسلوك كلمة مرور المالك الذي تنفِّذه الشيفرة. يوجد ملخص البند المثبَّت في مقدمة الصفحة citations.

examples/security-encryption.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF();
$pdf->AddPage();
$pdf->SetFont('helvetica', '', 12);
$pdf->Cell(0, 10, 'Encrypted document');
// User password set; owner password auto-generated (strong, random).
$pdf->SetProtection([], 'user-secret');
$pdf->Output(__DIR__ . '/encrypted.pdf', 'F');

التوقيعات الرقمية — بيان النطاق

قسم بعنوان «التوقيعات الرقمية — بيان النطاق»

اقرأ هذا القسم بحرفية. فهو محافظ عن قصد.

  • دالتا ⁨TCPDF⁩ القديمتان setSignature() وaddEmptySignatureAppearance() غير مُنفَّذتين في المحوِّل على المحرِّك الأساسي. في الوضع الافتراضي، لا تنفِّذان أي إجراء. في الوضع الصارم، تطرحان TcpdfNotImplementedException.
  • التوقيع الرقمي ليس قدرة من قدرات التوزيعة الأساسية عبر هذا المحوِّل. يتطلب دعم التوقيع الأساسي إصدارًا تجاريًا من ⁨NextPDF.⁩
  • إذا كان إصدار تجاري متاحًا، يكشف المحوِّل نقطة دخول توقيع حديثة (setSignatureV2()) تفوِّض إلى المحرِّك. ملفه الافتراضي هو الملف الأساسي (⁨B-B⁩).
  • لا يقدِّم هذا التوثيق أي ادعاء بأن أي إصدار ينتج ملفات توقيع ذات طابع زمني أو ذات تحقُّق طويل الأمد أو أرشيفية عبر هذا المحوِّل. وتحديدًا، لا يؤكِّد سلوك ⁨B-T⁩ أو ⁨B-LT⁩ أو ⁨B-LTA.⁩ تعرِّف المواصفة الأساسية للتوقيعات الإلكترونية المتقدمة في ⁨PDF⁩ (⁨PAdES⁩) في §6.1 أربعة مستويات أساسية متمايزة: ⁨B-B⁩ و⁨B-T⁩ و⁨B-LT⁩ و⁨B-LTA.⁩ ولكل منها متطلباته الخاصة. ⁨B-B⁩ هو المستوى الأساسي، أما المستويات الأعلى (الطابع الزمني، طويل الأمد، الأرشيفي) فهي ملفات منفصلة وأكثر تطلُّبًا. المستوى الأساسي ⁨B-B⁩ وحده يقع ضمن نطاق توثيق طبقة التوافق هذه. أما المستويات الأعلى فهي خارج النطاق صراحةً، ولا يُدَّعى بها لأي إصدار هنا. يوجد ملخص البند المثبَّت في مقدمة الصفحة citations.
  • لا يقدِّم هذا التوثيق في أي موضع أي ادعاء بتوقيع “مُصدَّق” أو “مضمون” أو “صالح قانونيًا” أو “مؤهَّل وفق ⁨eIDAS⁩”. صحة التوقيع، وسياسة مرتكز الثقة، والصلاحية القانونية مسؤولية إصدار التوقيع والبنية التحتية للمفتاح العام (⁨PKI⁩) الخاصة بالمستدعِي، وليست مسؤولية طبقة التوافق هذه.

إذا تطلَّب ترحيلك التوقيع، فعامِله باعتباره مسار عمل منفصلاً: اعتمد واجهة برمجة التطبيقات (⁨API⁩) الحديثة للتوقيع في إصدار تجاري، وتحقَّق من التوقيع الناتج باستخدام مُدقِّق مستقل. لا تعتمد على استدعاء ⁨TCPDF⁩ setSignature()؛ فهو بلا أثر هنا.

تُقبَل الدالة القديمة setTimeStamp() من أجل توافق توقيع الدالة وتُصدِر تنبيهًا؛ وهي لا تنتج توقيعًا ذا طابع زمني عبر هذا المحوِّل.

يُقبَل علم pdfa في المُنشئ من أجل توافق توقيع الدالة. تتطلب مطابقة الأرشفة وفق ⁨PDF/A⁩ إصدارًا تجاريًا من ⁨NextPDF.⁩ يكشف المحوِّل enablePdfA()، التي تفوِّض إلى المحرِّك، ويعيد المحرِّك خطأ تهيئة قابلاً للمعالجة عند غياب الإصدار المطلوب. لا ينتج المحوِّل بصمت ملفًا غير مطابق مع ادعاء مطابقة ⁨PDF/A.⁩

المُخرَج دائمًا ⁨PDF 2.0⁩ (⁨ISO 32000-2⁩). يحدِّد ⁨ISO 32000-2⁩ §7.5.2 أن الكاتب المطابق يعرِّف إصدار المستند بأنه 2.0، ولا يخفِّضه إلى إصدار أقدم عند الحفظ. ومن ثَمَّ، لا يمكن لـ setPDFVersion() أن يستهدف إصدارًا أقدم (انظر /⁨integrations/tcpdf-compat/method-coverage/⁩ §4). يوجد ملخص البند المثبَّت في مقدمة الصفحة citations.

  • لا إنهاء للعملية. لأن Error() يطرح استثناءً بدلاً من die()، غلِّف نقاط دخول العرض بـ try/catch، وحوِّل حالات الفشل إلى عقد الأخطاء في تطبيقك. لا تفترض أن فشل العرض ينهي الطلب.
  • سلامة مخزن الإخراج. يعيد Output() مع S بايتات؛ ومع F يكتب ملفًا؛ ومع E يعيد متن امتدادات بريد الإنترنت متعددة الأغراض (⁨MIME⁩) بترميز ⁨base64⁩؛ ومع I/D يوجِّه عبر مسار إخراج المحرِّك. فضِّل S أو F في العمَّال ومعالِجات بروتوكول نقل النص التشعبي (⁨HTTP⁩) لتتحكم في الاستجابة بنفسك؛ انظر /⁨integrations/tcpdf-compat/production-usage/.⁩
  • الوضع الصارم ليس إعدادًا للإنتاج. اقصره على مهمة تكامل مستمر (⁨CI⁩) أو مهمة تدقيق. فالاستثناء في مسار عرض إنتاجي أسوأ من معامل مُتدنٍّ بصمت.
  • نظافة الثوابت. عرِّف ثوابت PDF_* / K_* قبل أول إنشاء للمحوِّل. لا يمكن تخفيف العلمين المُحصَّنين (K_TCPDF_CALLS_IN_HTML وK_TCPDF_THROW_EXCEPTION_ERROR)؛ فلا تحاول تخفيفهما.
  • كلمات مرور المالك العشوائية. إذا كنت تعتمد على كلمة مرور مالك حتمية، فعيِّنها صراحةً. وإلا، تُولَّد كلمة قوية عشوائية لكل مستند ولا يمكن استرجاعها.
  • بالنسبة لدوال الصور، يرفض المحوِّل مسار غلاف الدفق قبل أي قراءة من نظام الملفات. يعامل كشف نوع الصورة (TcpdfImages::getImageFileType) أي مسار scheme://، بما في ذلك phar:// وphp:// وغيرها من أغلفة دفق ⁨PHP⁩، باعتباره غلافًا، ويتخطى فحص file_get_contents / getimagesize، ثم يرجع إلى الاستدلال بالامتداد وحده. يُغلق هذا متجه فك تسلسل بيانات ⁨phar⁩ الوصفية على هدف النقل العكسي إلى ⁨PHP 7.4⁩؛ ويرفض المحرِّك نفسه تضمين مسار الغلاف.
  • لا يضيف المحوِّل تحققًا من المسارات أو تطهيرًا لها لمسارات الملفات المُمرَّرة إلى دوال الصور أو الإخراج بما يتجاوز ما يفعله المحرِّك. عامِل المسارات وعناوين ⁨URL⁩ التي يقدِّمها المستدعِي باعتبارها غير موثوقة عند حدود تطبيقك.
  • يعرض المحرِّك ما يُمرَّر من ⁨HTML⁩ إلى دوال ⁨HTML⁩، وليس مُحلِّل ⁨HTML⁩ الخاص بـ ⁨TCPDF.⁩ منفذ تنفيذ ⁨PHP⁩ القديم مُغلق، لكن ينبغي لك مع ذلك أن تعامل ما يقدِّمه المستدعِي من ⁨HTML⁩ باعتباره مُدخلاً غير موثوق.
  • يحمي التشفير سرية المستند أثناء سكونه في ظل المعالج القياسي. وهو ليس بديلاً عن أمان النقل أو التحكم في الوصول في تطبيقك.
  • /⁨integrations/tcpdf-compat/method-coverage/⁩ — السلوك الدقيق لـ SetProtection() وsetSignature()
  • /⁨integrations/tcpdf-compat/configuration/⁩ — العلمان المُحصَّنان غير القابلين للضبط
  • /⁨integrations/tcpdf-compat/production-usage/⁩ — العمَّال، والمخازن، ومعالجة الفشل
  • docs/TCPDF_COVERAGE.md — مصفوفة التغطية المرجعية
  • ملف NOTICE الخاص بالحزمة — بيان التنفيذ المستقل