ما الذي تفعله ترويسات الأمان وما الذي لا تفعله
ترويسة الأمان ترويسة استجابة تطلب من المتصفح أن يكون أشد صرامة مع صفحتك مما يكون افتراضيًّا: أن يستخدم HTTPS وحده، ويكفّ عن تخمين أنواع الملفات، ويبقى خارج إطارات المواقع الأخرى، ويشارك أقل في Referer، ويُبقي الكاميرا مطفأة، ولا يشغّل إلا السكربتات التي أقررتها.
إنها دفاع متعدد الطبقات. لا تُصلح أيٌّ منها تطبيقًا فيه ثغرة: حقن SQL أو تسجيل دخول معطوب يبقى معطوبًا مع أكمل مجموعة ترويسات. ما تفعله هو تقليص ضرر الأخطاء التي يستطيع المتصفح احتواءها، مثل cross-site scripting وclickjacking وخفض البروتوكول وتسرّب البيانات عبر المُحيل، لكل زائر، مقابل بضع مئات من البايتات.
وهي تعمل في المتصفحات فقط. عميل الواجهة البرمجية والزاحف وسكربت المهاجم يتجاهلونها جميعًا، لذا يبقى WAF وكود التطبيق نفسه خط الدفاع الأول.
Strict-Transport-Security (HSTS)
تطلب Strict-Transport-Security من المتصفح استخدام HTTPS لاسم مضيفك وتذكّر ذلك مدة max-age ثانية، فلا يغادر الجهازَ حتى عنوان http:// مكتوب يدويًّا بنص صريح. إنها الترويسة ذات الأثر الأكبر مقابل أقل جهد، بشرط أن يعمل كل رابط في الموقع عبر HTTPS مسبقًا.
البداية الآمنة هي max-age=31536000: سنة واحدة، لهذا المضيف وحده. أما includeSubDomains وpreload فيمتدان أبعد ويصعب التراجع عنهما. يشرح دليل HSTS ما يُلزمك به كل منهما، وكيف تتحقق من الترويسة، وكيف تتراجع.
على CDN.com.tr تُفعَّل HSTS بإعداد جاهز للحساب في قواعد التسليم، فلا حاجة لكتابة سطر ترويسة لها. وهي ترسل بالضبط max-age=31536000 في استجابات HTTPS ولا شيء في HTTP العادي.
X-Content-Type-Options: nosniff
اعتادت المتصفحات تخمين نوع الملف من محتواه حين تبدو ترويسة Content-Type خاطئة. هذا التخمين، المسمى MIME sniffing، كان يتيح لملف مرفوع يشبه السكربت أن يُنفَّذ كسكربت. تُطفئ X-Content-Type-Options: nosniff هذا التخمين: يجب أن تصل ورقة الأنماط بنوع text/css والسكربت بنوع JavaScript، وإلا رفضهما المتصفح.
nosniff هي القيمة الوحيدة، والترويسة آمنة في كل استجابة، HTML كانت أم لا. تحقق أولًا من أمر واحد: أن خادمك يصنّف الملفات تصنيفًا صحيحًا. فالسكربت المقدَّم بنوع text/plain يتوقف عن التحميل لحظة إضافة الترويسة، وهذا بالضبط السلوك الذي طلبته.
X-Frame-Options وframe-ancestors: من يحق له وضع صفحاتك في إطار
يحمّل clickjacking صفحتك داخل إطار غير مرئي في موقع آخر، ويطابق أحد أزراره مع أحد أزرارك، فيضغط الزائر «حذف الحساب» وهو يظن أنه ضغط «تشغيل». والدفاع أن تخبر المتصفح بمن يحق له وضع صفحتك في إطار.
لـX-Frame-Options قيمتان مفيدتان: DENY لمنع الجميع، وSAMEORIGIN للصفحات من أصلك أنت. أما القيمة القديمة ALLOW-FROM فتتجاهلها المتصفحات الحالية. وللسماح بقائمة مواقع استخدم توجيه CSP frame-ancestors، مثل frame-ancestors 'self' https://partner.example.
حين تحمل الاستجابة الاثنين معًا، تتبع المتصفحات التي تفهم frame-ancestors هذا التوجيه وتتجاهل X-Frame-Options. وإرسال الاثنين شائع وغير ضار، فالترويسة القديمة تغطي المتصفحات القديمة، ما دامتا تقولان الشيء نفسه. وثمة حدّ واحد: frame-ancestors تعمل كترويسة HTTP فقط، ولا تعمل أبدًا في وسم <meta>.
Referrer-Policy: ما الذي يغادر مع كل نقرة
حين يتبع الزائر رابطًا، أو تحمّل صفحتك صورة أو سكربتًا أو خطًّا من موقع آخر، قد يرسل المتصفح عنوان صفحتك في ترويسة Referer. والروابط الكاملة تسرّب أكثر مما يُظن: عبارات البحث، وأرقام الطلبات، والرمز في رابط إعادة تعيين كلمة المرور.
القيمة المعقولة هي strict-origin-when-cross-origin: الرابط الكامل داخل موقعك، والأصل وحده (https://example.com/) إلى المواقع الأخرى، ولا شيء حين ترتبط صفحة HTTPS بـHTTP عادي. والمتصفحات الحالية تطبّق هذا أو ما هو أشد إن لم تقل الصفحة شيئًا؛ وضبطه صراحةً يثبّت السلوك مهما صار الافتراضي في أي متصفح. وفي تطبيق روابطه حساسة، لا ترسل no-referrer شيئًا على الإطلاق، مقابل خسارة بيانات الإحالة في تحليلات المواقع الأخرى.
Permissions-Policy: أطفئ ما لا تستخدمه
تحدد Permissions-Policy أي ميزات المتصفح القوية يحق لصفحتك والإطارات داخلها استخدامها: الكاميرا والميكروفون والموقع الجغرافي والدفع وUSB وغيرها. القائمة الفارغة () تطفئ الميزة للجميع، و(self) تسمح بها لأصلك وحده، ويمكنك ذكر أصول المحتوى المضمَّن الذي يحتاجها فعلًا.
موقع شركة أو متجر نادرًا ما يحتاج أيًّا منها، لذا فإن camera=(), microphone=(), geolocation=() بداية معقولة؛ أضف غيرها كلما راجعت ما تضمّنه. المكسب هو الاحتواء: سكربت طرف ثالث مخترَق أو إطار إعلاني لا يستطيع أن يطلب كاميرا الزائر. تطبّق المتصفحات المبنية على Chromium هذه الترويسة، فاعتبرها تقوية فوق الضوابط الأخرى لا بديلًا عنها.
Content-Security-Policy: قوية وتستحق خطة
تخبر Content Security Policy المتصفح من أين يجوز أن تأتي السكربتات والأنماط والصور والخطوط والاتصالات والإطارات، وهل يجوز تشغيل الكود المضمَّن. إن أُحسن إعدادها حوّلت معظم أخطاء cross-site scripting من «مهاجم يشغّل كودًا في جلسات مستخدميك» إلى «المتصفح حجب سكربتًا وأبلغ عنه».
وهي أيضًا الترويسة التي تكسر الصفحات. كتل <script> المضمَّنة، وسمات onclick، ومدير وسوم يحقن سكربتات أخرى، وعنوان تحليلات نسيه الجميع: كل واحد منها يجب السماح به أو إعادة كتابته. لذا انشرها على خطوتين. أرسل السياسة أولًا بصيغة Content-Security-Policy-Report-Only: لا يُحجب شيء، ويظهر كل انتهاك في الكونسول، ومع عنوان report-to أو report-uri في تقاريرك. أصلح ما تُظهره التقارير أو اسمح به، ثم أرسل السياسة نفسها بصيغة Content-Security-Policy.
السياسة أدناه صارمة لكنها مقروءة. للسكربتات المضمَّنة التي لا تستطيع إزالتها، ولّد nonce عشوائيًّا لكل استجابة وضعه في السياسة وفي وسم <script> معًا. ومع 'strict-dynamic' تصبح السكربتات التي يحمّلها سكربت موثوق موثوقة هي أيضًا، فيعمل مدير الوسوم دون سرد كل نطاق يلمسه. وتجنّب 'unsafe-inline' للسكربتات: فهي تطفئ معظم الحماية التي وُجدت السياسة من أجلها.
سياسة بداية صارمة بوضع report-only
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'self'; upgrade-insecure-requests
قيم آمنة جاهزة للنسخ
تستطيع معظم المواقع البدء بهذه المجموعة وتعديل مصادر CSP وقائمة الأذونات فقط. الترتيب لا يهم؛ المهم أن تظهر كل ترويسة مرة واحدة.
غياب X-XSS-Protection مقصود. كانت تتحكم في مرشّح أزالته المتصفحات الحالية، وفي المتصفحات القديمة كان المرشّح نفسه قابلًا لإساءة الاستخدام؛ لا ترسل شيئًا أو أرسل X-XSS-Protection: 0. وExpect-CT متقادمة لسبب مشابه ويمكن حذفها أيضًا.
ترويسات الاستجابة لصفحة HTML
Strict-Transport-Security: max-age=31536000
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Content-Security-Policy-Report-Only: default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'
ضبطها على CDN.com.tr
لـHSTS إعداد جاهز خاص بها، كما ورد أعلاه. أما بقية الترويسات ذات القيمة الواحدة فتوضع في قاعدة توصيل: في قواعد التسليم عدّل القاعدة التي تقدّم صفحاتك، وهي عادةً /، وأضفها سطرًا سطرًا في حقل الرؤوس المخصصة بصيغة Header-Name value (في صفحة القواعد ذات التبويبات: الرؤوس ← إضافة رؤوس للاستجابة). القيمة التي تحتوي على مسافات توضع بين علامتي تنصيص مزدوجتين.
لا يمكن وضع Content-Security-Policy كاملة هناك. توجيهاتها مفصولة بفواصل منقوطة، واللوحة والحافة ترفضان ; في سطر الترويسة، لأن الفاصلة المنقوطة تُنهي توجيه الإعداد الخاص بالحافة نفسها. التوجيه الواحد لا فاصلة منقوطة فيه، لذا تعمل frame-ancestors وحدها على الحافة. أما السياسة الكاملة فمكانها خادم الأصل، في خادم الويب أو التطبيق، حيث يمكنها أيضًا حمل nonce لكل طلب. ويعمل وسم HTML <meta http-equiv="Content-Security-Policy"> كذلك، باستثناء frame-ancestors وreport-uri وsandbox التي تتجاهلها المتصفحات في وسم meta.
الترويسات التي تضيفها القاعدة تُطبَّق على الاستجابات الناجحة واستجابات إعادة التوجيه (2xx و3xx)، بما فيها ما يُقدَّم من الذاكرة المؤقتة، فور نشر القاعدة؛ والترويسة التي يجب أن تظهر في صفحات الأخطاء أيضًا مكانها خادم الأصل. والترويسات التي يرسلها خادم الأصل تُحفظ مع كل نسخة مخزنة مؤقتًا، لذا بعد تغييرها أفرغ ذاكرة CDN المؤقتة للصفحات المتأثرة. وإذا كان خادم الأصل يرسل إحدى هذه الترويسات أصلًا، فاخترها في إخفاء الرؤوس ضمن القاعدة نفسها، وإلا وصلت إلى الزوار نسختان.
الرؤوس المخصصة في القاعدة التي تقدّم صفحاتك
X-Content-Type-Options nosniff
X-Frame-Options SAMEORIGIN
Referrer-Policy strict-origin-when-cross-origin
Permissions-Policy "camera=(), microphone=(), geolocation=()"
Content-Security-Policy "frame-ancestors 'self'"
كيف تختبرها
ابدأ بـcurl، فهو يُظهر بالضبط ما يرسله الخادم. افحص صفحة وملفًّا ثابتًا وصفحة غير موجودة: الترويسات المضبوطة في مكان واحد كثيرًا ما تغيب عن المكانين الآخرين.
ثم افتح أدوات المطوّر في المتصفح. يعرض تبويب Network الترويسات كما استلمها المتصفح، ويبلّغ الكونسول عن كل انتهاك لـCSP وكل إطار مرفوض، مع التوجيه الذي تسبب فيه. وأدوات الفحص عبر الإنترنت مثل HTTP Observatory من Mozilla تقيّم المجموعة كلها وتشرح كل ملاحظة، وهو رأي ثانٍ مفيد.
وأخيرًا، اختبر السلوك لا مجرد الوجود: ضمّن الصفحة في iframe على أصل آخر وتأكد أن المتصفح يرفضها، وراقب الكونسول بضعة أيام مع سياسة report-only قبل فرضها.
curl -sI https://www.example.com/ | grep -i -E \
'strict-transport|x-content-type|x-frame|referrer-policy|permissions-policy|content-security'
# a static file and a missing page, too
curl -sI https://www.example.com/assets/app.css | grep -i x-content-type
curl -sI https://www.example.com/no-such-page | grep -i -E 'x-frame|content-security'
أسئلة شائعة حول ترويسات الأمان
ما ترويسات الأمان التي ينبغي لكل موقع إرسالها؟
HSTS بعد أن يعمل الموقع كله عبر HTTPS؛ وX-Content-Type-Options: nosniff؛ وX-Frame-Options: SAMEORIGIN أو frame-ancestors في CSP؛ وReferrer-Policy: strict-origin-when-cross-origin؛ وPermissions-Policy تطفئ الميزات التي لا تستخدمها. وأضف Content-Security-Policy بعد تجربة بوضع report-only.
هل X-Frame-Options متقادمة؟
تجاوزها ما هو أفضل أكثر من كونها أُلغيت. تؤدي frame-ancestors في CSP العمل نفسه بتحكم أكبر، والمتصفحات التي تدعمها تتجاهل X-Frame-Options إذا وصلت الاثنتان. وإرسال SAMEORIGIN أو DENY إلى جانبها لا يزال يحمي المتصفحات القديمة؛ الميتة فقط هي ALLOW-FROM.
هل أواصل إرسال X-XSS-Protection؟
لا. المرشّح الذي كانت تتحكم فيه أُزيل من المتصفحات الحالية، وفي القديمة كان يمكن استغلاله ضد الصفحة. لا ترسلها أو أرسل 0، واعتمد بدلًا منها على Content-Security-Policy.
هل يمكنني ضبط Content-Security-Policy عبر CDN.com.tr؟
التوجيه الواحد نعم: مثل frame-ancestors 'self' في الرؤوس المخصصة لقاعدة توصيل. أما السياسة الكاملة فتحتاج فواصل منقوطة بين توجيهاتها، وقواعد الحافة لا تقبلها، فاضبطها في خادم الويب أو التطبيق، أو في وسم meta لكل شيء عدا frame-ancestors وreport-uri وsandbox.
هل تؤثر ترويسات الأمان في SEO أو في السرعة؟
ليس بشكل ملموس. تضيف بضع مئات من البايتات، وHTTP/2 وHTTP/3 يضغطان الترويسات المتكررة. وليست عاملًا موثقًا في الترتيب. الخطر الوحيد على SEO هو CSP تحجب سكربتاتك أنت فتكسر طريقة عرض الصفحة، وخطوة report-only تكشف ذلك.
هل تحتاج الصور وملفات CSS وJavaScript هذه الترويسات أيضًا؟
nosniff وHSTS مفيدتان في كل استجابة. أما البقية، أي CSP وحماية الإطارات وReferrer-Policy وPermissions-Policy، فتعمل على المستندات، فالمهم صفحات HTML. وإرسالها مع كل شيء لا يضر.