أمان NextPDF Gotenberg وتشغيله
لمحة سريعة
قسم بعنوان «لمحة سريعة»يرسل هذا الجسر المستندات من تطبيقك إلى خدمة خارجية عبر الشبكة. لذلك فهو يمثّل سطح طلب من جانب الخادم وسطح أمان نقل في الوقت نفسه. تطبّق الحزمة ضوابط محددة وقابلة للتحقق لكليهما، لكنها لا تؤمّن النظام بأكمله بمفردها. لا تعمل هذه الضوابط إلا إذا نشرت Gotenberg وشغّلته مع الضمانات الملائمة لها. تشرح هذه الصفحة الضوابط التي تطبّقها الحزمة والواجبات التشغيلية التي تكمّلها.
لا شيء هنا يُعدّ ضمانة مطلقة. فكل ضابط هو سلوك محدد ومغطى بالاختبارات وله حدود معلنة.
طبقتا السياسة
قسم بعنوان «طبقتا السياسة»يطبّق الجسر سياستَي أمان مختلفتين عند طبقتين مختلفتين:
- سياسة النقل (
GotenbergSecurityPolicy) — تفرض مخطط عنوان URL، وتفحص تزوير الطلب من جانب الخادم (SSRF)، وتدافع ضد إعادة ربط نظام أسماء النطاقات (DNS)، وتضع حدودًا لحجم الإدخال، وتفحص أسماء الملفات. هذه هي الطبقة الموثّقة بالتفصيل أدناه. - سياسة تحليل HTML — سياسة محتوى على طبقة التحليل، وقيمتها الافتراضية هي سياسة NextPDF الافتراضية الأساسية، وتعمل قبل أن يصل المحتوى إلى أداة العرض. وهي تكمّل سياسة النقل لكنها تبقى مستقلة عنها. تتناول هذه الصفحة سياسة النقل.
فحص تزوير الطلب من جانب الخادم (SSRF)
قسم بعنوان «فحص تزوير الطلب من جانب الخادم (SSRF)»يفحص الجسر عنوان URL المُهيَّأ لـ API قبل أن يغادر أي بايت العملية. يتكوّن هذا الضابط من ثلاثة أجزاء.
فرض المخطط. لا يُقبل إلا https (غير حساس لحالة الأحرف). ويُرفض عنوان URL العادي بصيغة http://. لذلك يكون أمان طبقة النقل (TLS) إلزاميًّا لكل عملية تحويل ولفحص السلامة.
فحص العناوين. إذا كان المضيف عنوان IP صريحًا، يرفضه الجسر عندما يقع ضمن نطاق خاص أو محجوز. وإذا كان المضيف اسمًا، يحلّه الجسر إلى جميع سجلات A وAAAA الخاصة به، ويرفض الطلب إذا كان أي عنوان محلول خاصًّا أو محجوزًا. إنّ حلّ مجموعة السجلات كاملة، بدلًا من عنوان واحد، هو الضابط الذي يُحبط مهاجمًا يخفي عنوانًا خاصًّا خلف اسم يعيد أيضًا عنوانًا عامًّا. يتبع هذا نهج إرشادات OWASP للوقاية من SSRF: استرجع كل عنوان IP خلف اسم النطاق (سجلات A وAAAA، لـ IPv4 وIPv6)، وتحقّق من كل عنوان مقابل قائمة سماح (OWASP Cheat Sheet Series، الوقاية من SSRF، الدفاع على طبقة التطبيق؛ مثبّت في الملحق الجانبي للتوليد المعزَّز بالاسترجاع (RAG) الخاص بالصفحة).
إعادة الفحص لوقت-التحقق/وقت-الاستخدام (TOCTOU). يعيد الجسر حلّ مجموعة العناوين المُلتقطة أثناء التحقق ويقارنها قبيل الطلب مباشرةً. وإذا ظهر عنوان جديد، يُلغى الطلب مع خطأ إعادة ربط DNS. وهذا يغلق النافذة بين التحقق والاتصال التي كان يمكن أن يستغلها هجوم إعادة الربط.
عندما يستخدم الجسر نقله المثبَّت عبر cURL، تُربط مجموعة العناوين المُتحقَّق منها بالاتصال عبر CURLOPT_RESOLVE، فتتصل النواة بالعنوان المُدقَّق بدلًا من أي عنوان قد يعيده بحث DNS جديد وقت الاتصال. واتّباع عمليات إعادة التوجيه مُعطَّل على ذلك النقل (CURLOPT_FOLLOWLOCATION مُوقَف، وCURLOPT_MAXREDIRS صفر)، فلا يمكن لاستجابة 3xx أن ترسل الطلب بصمت إلى مضيف غير مُدقَّق. بل تتلقى طبقة السياسة الاستجابة بدلًا من ذلك.
الأثر التشغيلي. يرفض حارس SSRF العناوين الخاصة والمحجوزة بحكم التصميم. إذا كان Gotenberg لديك يعمل على شبكة خاصة، فلا يمكنك توجيه الجسر إلى عنوانه الخاص. اعرضه عبر عنوان يقبله الحارس واحمِ ذلك المسار بتجزئة الشبكة والمصادقة، كما هو موضّح في قسم النشر أدناه.
أمان النقل وتثبيت المفتاح العام
قسم بعنوان «أمان النقل وتثبيت المفتاح العام»يكون التحقق من قرين TLS والمضيف مُفعَّلًا دائمًا في النقل المثبَّت عبر cURL (CURLOPT_SSL_VERIFYPEER صحيح، وCURLOPT_SSL_VERIFYHOST 2). وإلى جانب التحقق القياسي من السلسلة، يدعم الجسر تثبيت SubjectPublicKeyInfo (SPKI).
كل تثبيت هو تجزئة SHA-256 لـ SubjectPublicKeyInfo الخاص بالخادم، مُعبَّر عنها بالصيغة sha256/<base64>. يقبل الجسر الشهادة عندما تطابق تجزئة SPKI الخاصة بها أي تثبيت في المجموعة المدمجة من الأساسي زائد الاحتياطي. يتبع نموذج التثبيت الاحتياطي هذا RFC 7469 §4.3، الذي يعرّف التثبيت الاحتياطي — بصمة زوج مفاتيح ثانوي لم يُنشَر بعد — باعتباره مسار التعافي الأساسي من فشل غير مقصود في التحقق من التثبيت، و§2.5، الذي يشترط أن تتضمن المجموعة المثبَّتة تثبيتًا واحدًا على الأقل غير موجود في سلسلة الشهادات الحالية (RFC 7469 §4.3 و§2.5؛ مثبّت في الملحق الجانبي لـ RAG الخاص بالصفحة). تعلن شيفرة الجسر RFC 7469 §2.1 و§2.6 لدلالات وجود تثبيت احتياطي واحد على الأقل وتقاطع المجموعة المدمجة. التثبيت اختياري بالاشتراك: إذا لم تُهيّأ أي تثبيتات، يُطبَّق التحقق القياسي من السلسلة ولا يُفرَض التثبيت.
التثبيت الذي يتعذر تحليله يثير خطأ تهيئة قبل أي طلب. والشهادة الحية التي لا يطابق SPKI الخاص بها أي تثبيت مُهيَّأ تجعل النقل يُفشل الطلب، بحكم التصميم.
إجراء تدوير التثبيت
قسم بعنوان «إجراء تدوير التثبيت»التدوير غير الصحيح يحجب الجسر عن الخدمة. للتدوير دون انقطاع:
- قبل تغيير مفتاح الخادم، أنشئ تثبيت SPKI للمفتاح الجديد وأضفه إلى قائمة التثبيت الاحتياطي. انشر تلك التهيئة. يقبل الجسر الآن المفتاح الحالي والمفتاح المستقبلي معًا.
- دوِّر شهادة الخادم أو مفتاحه لاستخدام المفتاح الجديد.
- تأكّد من أن عمليات التحويل لا تزال تنجح (يطابق المفتاح الجديد الآن التثبيت الاحتياطي).
- انقل التثبيت الجديد من القائمة الاحتياطية إلى القائمة الأساسية وأزل تثبيت المفتاح المُتقاعد. انشر.
- أنشئ التثبيت للتدوير التالي وهيّئه باعتباره الاحتياطي الجديد كي تبقى المجموعة حاملةً احتياطيًّا صالحًا للاستخدام دائمًا.
إن إبقاء القائمة الاحتياطية منفصلة عن القائمة الأساسية يتيح لك تهيئة التثبيت التالي والتحقق منه دون المساس بالتثبيت النشط.
المصادقة
قسم بعنوان «المصادقة»عندما لا يكون apiKey فارغًا، يرسله الجسر باعتباره ترويسة Authorization: Bearer على طلب التحويل. يُوسَم الحقل بـ #[\SensitiveParameter] كي تُحجب القيمة من تتبّعات المكدس. لا يحمّل الجسر السر نيابةً عنك؛ وفّره من مدير أسرار عند بدء العملية ولا تودِعه في المستودع أبدًا. لا يُكتب الرمز إلى سجل الطلبات؛ إذ يحتوي إدخال التصحيح المُسجَّل على عنوان URL واسم الملف والتنسيق وطول المحتوى فقط.
حدّ الثقة في الاستجابة
قسم بعنوان «حدّ الثقة في الاستجابة»لا تُقبل الاستجابة إلا عندما تكون الحالة 200، ويحتوي Content-Type على application/pdf، ويبدأ الجسم بتوقيع %PDF. يُعدّ فحص توقيع البايتات مهمًّا لأن نوع المحتوى المُعلَن وحده لا يُثبت ماهية البايتات. يضفي معيار WHATWG MIME Sniffing الطابع الرسمي على المنطق نفسه في خوارزمية استشعار نوع MIME الخاصة به، التي تشتق نوعًا محسوبًا من مطابقة أنماط البايتات الاستهلالية بدلًا من النوع المُورَّد. وتنص إرشادات OWASP لرفع الملفات على المبدأ التطبيقي المقابل: تحقّق من نوع الملف ولا تثق في ترويسة Content-Type المُعلَنة، لأنه يمكن انتحالها (WHATWG MIME Sniffing §6.2.3؛ OWASP Cheat Sheet Series، التحقق من رفع الملفات؛ كلاهما مثبّت في الملحق الجانبي لـ RAG الخاص بالصفحة). يطبّق الجسر الفحص المكافئ دفاعيًّا على الجانب الوارد: يثير عدم التطابق استثناءً مُحدَّد النوع، ولا تُعاد البايتات أبدًا كنتيجة.
هذا الحدّ هو أيضًا سبب أهمية عقد PSR-18 هنا. لا يثير عميل PSR-18 استثناءً إلا عندما يتعذر عليه إرسال الطلب أو تحليل الاستجابة إلى كائن PSR-7، وهو لا يثير استثناءً على رمز حالة خطأ. تُعاد استجابة 4xx/5xx سليمة التكوين إلى المُستدعي بصورة طبيعية (PSR-18، “Exceptions”؛ مثبّت في الملحق الجانبي لـ RAG الخاص بالصفحة). لذلك يفحص الجسر الحالة والنوع والتوقيع بنفسه بدلًا من افتراض أن الاستجابة المُعادة ناجحة. دلالات HTTP لانتهاك قيد content-type — رفض 415 (نوع وسائط غير مدعوم)، حيث يرفض الخادم محتوًى بتنسيق غير مدعوم — هي النموذج الذي يحاكيه الفحص الوارد (RFC 9110 §15.5.16؛ مثبّت في الملحق الجانبي لـ RAG الخاص بالصفحة).
حدود الموارد
قسم بعنوان «حدود الموارد»للجسر حدّ موارد واحد داخل العملية: maxFileSize (الافتراضي 52,428,800 بايت = 50 MiB). يُفرَض قبل الطلب، فلا يصل إدخال مُفرط الحجم إلى الخدمة أبدًا. لا يحتوي الجسر على حدّ تزامن مدمج، ولا حدّ معدّل، ولا سقف لحجم المخرجات. فتلك من مسؤوليات النشر والمُستدعي (انظر /integrations/gotenberg/production-usage/). اضبط maxFileSize على أصغر قيمة تتطلبها مستنداتك الفعلية، فالسقف الأضيق ضابط أرخص لمنع رفض الخدمة.
نشر خدمة Gotenberg وتأمينها
قسم بعنوان «نشر خدمة Gotenberg وتأمينها»لا يكون الجسر آمنًا إلا بقدر أمان الخدمة التي يستدعيها. أنت من يشغّل تلك الخدمة؛ والواجبات أدناه تكمّل الضوابط الواردة أعلاه.
- أنهِ TLS أمام Gotenberg. تتحدث حاوية Gotenberg بـ HTTP العادي افتراضيًّا. يتطلب الجسر HTTPS، لذا ضع Gotenberg خلف وكيل عكسي ينهي TLS، أو دخول، أو شبكة خدمات، ووجّه الجسر إلى نقطة نهاية HTTPS. ثبّت SPKI الخاص بالوكيل إذا فعّلت التثبيت.
- لا تعرض Gotenberg علنًا. فهو يحوّل المستندات بمحركات من فئة LibreOffice وChromium، وليس خدمة موجَّهة إلى الإنترنت. قيّد الدخول على مضيفات التطبيقات التي تستدعيه، باستخدام سياسة الشبكة أو قواعد جدار الحماية.
- اشترط المصادقة على المسار. يرسل الجسر رمز حامل عند تهيئته؛ افرضه (أو TLS المتبادل) عند الوكيل كي لا يصل طلب غير مُصادَق عليه إلى محرك التحويل.
- ثبّت إصدارًا محددًا من الخدمة. يفترض الجسر مسارَي خدمة اثنين بالضبط —
/forms/libreoffice/convertو/health. ثبّت صورة Gotenberg على وسم تصحيح محدد، وتحقّق من هذين المسارين مقابل الإصدار الذي تنشره، ثم أعد التحقق عند كل ترقية. - حدّد سعة التحويل عن قصد. تحتجز كل عملية تحويل عاملًا طوال مدة الطلب. حدّد حجم نشر Gotenberg بما يناسب ذروة معدل التحويل المتزامن لديك، وقيّد عمليات التحويل الجارية على جانب المُستدعي بما يطابقه. السعة خاصية من خصائص نشرك، لا من خصائص هذه الحزمة.
- تعامل مع مدخلات التحويل باعتبارها غير موثوقة. تُعالَج المستندات المُمرَّرة عبر التحويل بواسطة محركات معقدة. قيّد
maxFileSize، واعزل نشر Gotenberg (مقطع شبكة خاص به، وحدّ أدنى من الصادر، ولا وصول إلى الخدمات الداخلية)، وأبقِ المحرك مُحدَّثًا بالتصحيحات.
ما لا تدّعيه هذه الحزمة
قسم بعنوان «ما لا تدّعيه هذه الحزمة»- إنها ليست “آمنة افتراضيًّا”: الضوابط حقيقية، لكنها تعتمد على صحة النشر والتهيئة.
- إنها لا تجعل التحويل “مقاومًا للعبث” ولا المخرجات “مُعتمَدة”. فهي تتحقق من النقل وشكل الاستجابة، لكنها لا تشهد على محتوى المستند.
- إنها لا توفّر التوقيع ولا الختم الزمني ولا التحقق طويل الأمد. فتلك من شؤون المعالجة اللاحقة. دعم PAdES في إصدار Pro هو خط الأساس B-B فقط ولا يشمل B-T أو B-LT أو B-LTA؛ ولا شيء في هذا الجسر يوحي بقدرة على الختم الزمني أو التحقق طويل الأمد (LTV).
- إنها لا تدعم “جميع ملفات Office”. إنها تدعم التنسيقات الستة المُعدَّدة وترفض كل ما عداها قبل أي طلب.
انظر أيضًا
قسم بعنوان «انظر أيضًا»- /integrations/gotenberg/configuration/ — قواعد اختيار النقل ونموذج التثبيت الكامل.
- /integrations/gotenberg/production-usage/ — إعادات المحاولة، والمهلات، والتزامن، وقابلية المراقبة.
- /integrations/gotenberg/troubleshooting/ — كل استثناء أمان ومُسبِّبه.
- /integrations/gotenberg/overview/ — تدفق التحويل ونموذج التبعيات.