Loading...

امنیت · 7 دقیقه مطالعه

HSTS: به مرورگر یاد بدهید هرگز با سایت شما HTTP صحبت نکند

شما یک certificate دارید، HTTP را به HTTPS ریدایرکت می‌کنید و قفل کنار آدرس هست. اما هنوز یک درخواست هست که بازدیدکننده به‌صورت متن‌ساده می‌فرستد — همان اولی — و دقیقاً همان درخواستی است که یک مهاجم روی همان شبکه منتظرش است. HSTS این را می‌بندد: یک هدر پاسخ که مرورگر را وادار می‌کند تا مدتی که شما بگویید اصلاً از HTTP برای دامنه‌تان استفاده نکند. این راهنما هدر را توضیح می‌دهد، اینکه سه تنظیم آن واقعاً شما را به چه چیزی متعهد می‌کنند، و چگونه بدون قفل‌کردن خودتان پشت در، آن را در cdn.com.tr فعال و تأیید کنید.

به‌روزرسانی

HSTS: به مرورگر یاد بدهید هرگز با سایت شما HTTP صحبت نکند

درخواستی که ریدایرکت شما هرگز نمی‌بیند

تقریباً هر سایتی که certificate دارد همین کار را می‌کند: به پورت 80 با یک 301 به آدرس https:// پاسخ می‌دهد. این کار درست است و باید آن را نگه دارید. فقط یک درخواست دیر اتفاق می‌افتد.

وقتی کسی example.com را در نوار آدرس تایپ می‌کند، لینکی از یک ایمیل قدیمی را دنبال می‌کند، یا یک بوک‌مارک چندسال‌پیش را باز می‌کند، مرورگر هیچ دلیلی برای فرض HTTPS ندارد. یک اتصال HTTP ساده باز می‌کند و صفحه را درخواست می‌کند. ریدایرکت شما پاسخ می‌دهد — اما پرسش از قبل، به‌صورت آشکار، روی هر شبکه‌ای که بازدیدکننده رویش است فرستاده شده: یک کافه، یک فرودگاه، یک هتل، یک captive portal، یک روتر خانگی که کسی به‌روزش نکرده.

هر کسی که در موقعیت خواندن آن درخواست باشد، در موقعیت پاسخ‌دادن به آن هم هست. به‌جای انتقال 301 شما، نسخهٔ خودشان از سایت شما را روی HTTP سرو می‌کنند و بی‌سروصدا همه‌چیز را از طریق HTTPS به شما proxy می‌کنند. بازدیدکننده صفحه‌ای می‌بیند که درست به نظر می‌رسد، منهای یک قفل که تقریباً هیچ‌کس چکش نمی‌کند، و رمزش را در آن تایپ می‌کند. این SSL stripping نام دارد و یک downgrade attack است که دقیقاً همان درخواستی را هدف می‌گیرد که ریدایرکت شما برای رفعش وجود دارد.

HSTS آن درخواست را از دنیا حذف می‌کند. به‌محض اینکه مرورگر هدر را دیده باشد، http://example.com/... را به‌صورت داخلی به https://... بازنویسی می‌کند، پیش از آنکه چیزی از دستگاه خارج شود. دیگر درخواست متن‌سادهٔ رهگیری‌شدنی وجود ندارد و هشدار certificateای هم نیست که بازدیدکننده بتواند از رویش رد شود.

هدر چه می‌گوید

Strict-Transport-Security: max-age=31536000 در عمل کل ماجراست. سه تنظیم می‌توانند در آن ظاهر شوند و از نظر اینکه چقدر شما را متعهد می‌کنند بسیار با هم فرق دارند.

max-age تنها موردی است که الزامی است: چند ثانیه مرورگر باید به خاطر بسپارد که این host فقط HTTPS است. 31536000 یعنی یک سال. ساعت با هر پاسخ ریست می‌شود، پس سایتی که فعالانه بازدید می‌شود همیشه یک سال کامل جلوی رویش دارد، درحالی‌که سایتی که کسی بازدیدش نمی‌کند سرانجام فراموشش می‌کند.

includeSubDomains قانون را به هر نامی زیر دامنهٔ شما گسترش می‌دهد — www، api، shop، staging، و همانی که فراموشش کرده‌اید. واقعاً قوی‌تر است، چون یک کوکی تنظیم‌شده روی دامنهٔ والد می‌تواند از طریق هر ساب‌دامنه‌ای از آن مورد حمله قرار گیرد. همچنین همان تنظیمی است که چیزها را خراب می‌کند، چون روی hostهایی اعمال می‌شود که ممکن است کنترلشان را نداشته باشید و برایشان certificate هم نداشته باشید.

preload درخواست می‌کند دامنهٔ شما مستقیماً در خود مرورگرها کامپایل شود، تا HTTPS-only پیش از آنکه بازدیدکننده اصلاً به سایت شما آمده باشد اعمال شود. به includeSubDomains و یک max-age طولانی نیاز دارد و برگرداندنش بسیار سخت است.

یک قاعده زیربنای هر سه است: هدر فقط روی یک پاسخ HTTPS شمرده می‌شود. مرورگرها عمداً آن را روی HTTP ساده نادیده می‌گیرند، چون رعایتش در آنجا به هرکسی روی شبکه اجازه می‌داد دامنه‌ای را که مالکش نیست pin کند.

چرا فقط max-age می‌فرستیم

preset در cdn.com.tr فقط max-age=31536000 می‌فرستد و چیز دیگری نه. این یک پیش‌فرض عمدی است، نه یک محدودیت، و ارزشش را دارد بفهمید آن دو تنظیم دیگر شما را به چه چیزی متعهد می‌کردند.

includeSubDomains به نام‌هایی می‌رسد که در صفحه‌ای که آن را فعال کردید جلوی چشمتان نیستند: یک host قدیمی mail. روی یک سرور کهنه، یک صفحهٔ status.، یک ابزار داخلی روی ساب‌دامنه‌ای که سال‌هاست به HTTP ساده پاسخ می‌دهد. به‌محض اینکه مرورگر قانون را داشته باشد، هرکدام از این‌ها در آن مرورگر غیرقابل‌دسترس می‌شوند — نه یک هشدار، یک شکست کامل — و حذف هدر هم آن را درست نمی‌کند، چون مرورگر از قبل قانون را نوشته است.

preload هم در همان جهت شکست می‌خورد، فقط کندتر: کنار کشیدن از آن یعنی ثبت‌نام در یک لیست شخص‌ثالث و بعد انتظار برای انتشار نسخه‌های مرورگر، که با ماه اندازه‌گیری می‌شود.

یک max-age یک‌ساله روی همان hostnameای که واقعاً سرو می‌کنید، تمام مزیت امنیتی را برای آن hostname از همان اولین بازدید به بعد در اختیارتان می‌گذارد. flagهای قوی‌تر ارزش این را دارند که بعداً، عمداً، اضافه شوند، وقتی هر نام زیر دامنه‌تان فهرست‌برداری و به HTTPS منتقل شده باشد. از جایی شروع کنید که می‌توانید مطمئن باشید، نه از جایی که می‌توانید پشیمان شوید.

چک‌لیست پیش از روشن‌کردنش

HSTS خودش ریسکی نیست. فعال‌کردنش روی سایتی که آماده نیست ریسکی است. اول این را مرور کنید.

هر صفحه از طریق HTTPS بارگذاری می‌شود. نه فقط صفحهٔ اصلی: بخش ادمین، API، endpointهای آپلود، مقصدهای webhook، URLهای قدیمی کمپین. هرچیزی که فقط روی پورت 80 کار می‌کند برای هرکسی که هدر را دیده از کار می‌افتد.

certificate معتبر است و خودش تمدید می‌شود. زیر HSTS یک certificate منقضی دیگر هشداری نیست که بازدیدکننده بتواند ردش کند — یک دیوار است. certificateها در cdn.com.tr به‌صورت خودکار صادر و تمدید می‌شوند، که دقیقاً همان خصلتی است که HSTS فرض می‌کند دارید.

mixed content از بین رفته است. اسکریپت‌ها، stylesheetها، تصاویر و iframeهایی که با http:// ارجاع داده شده‌اند باید از قبل درست شده باشند؛ HSTS فقط شکستشان را بلندتر می‌کند.

می‌دانید ساب‌دامنه‌هایتان چه می‌کنند. نه چون امروز includeSubDomains را فعال می‌کنید، بلکه چون سرانجام می‌خواهیدش، و فهرست‌برداری همان کار واقعی است.

ریدایرکت HTTP-به-HTTPS شما سرجایش می‌ماند. HSTS از مرورگرهایی محافظت می‌کند که هدر را دیده‌اند؛ ریدایرکت بقیه را می‌گیرد. این دو جایگزین هم نیستند.

روشن‌کردنش

در پنل، Delivery rules → Security presets را باز کنید. فیلد «Security setting» یک multiselect از presetهای edge است که روی حساب اعمال می‌شوند: Hsts را انتخاب کنید و ذخیره کنید. این صفحه در /management/cdn/advanced-management قرار دارد.

این تنظیم به‌ازای هر حساب است، پس hostnameای که هنوز آماده نیست می‌تواند به‌سادگی روی حساب خودش منتظر بماند به‌جای آنکه جلوی آن‌هایی را که آماده‌اند بگیرد.

پس از ذخیره، edge هدر را به پاسخ‌های HTTPS آن حساب اضافه می‌کند و فقط به پاسخ‌های HTTPS — یک درخواست HTTP ساده همچنان ریدایرکت شما را می‌گیرد، بدون هیچ هدری، که همان رفتاری است که specification لازم دارد. هیچ‌چیزی دربارهٔ origin شما تغییر نمی‌کند: هیچ هدری نیست که در nginx، Apache یا framework خودتان اضافه کنید، چون edge همان جایی است که پاسخ روبه‌روی بازدیدکننده تصمیم‌گیری می‌شود.

تأییدش در ده ثانیه

هدرها را بخواهید و دنبال همان یک خط بگردید. دو نتیجه مهم است و دومی همان چکی است که آدم‌ها ازش رد می‌شوند.

این هدر جایش روی پاسخ‌های HTTPS است و هیچ‌جای دیگر

# should print: strict-transport-security: max-age=31536000
curl -sI https://example.com/ | grep -i strict-transport

# should print nothing at all
curl -sI http://example.com/ | grep -i strict-transport

چیزی که مرورگر به خاطر می‌سپارد

خط فرمان به شما می‌گوید چه چیزی می‌فرستید. مرورگر همان جایی است که هدر واقعاً کارش را انجام می‌دهد، و ارزشش را دارد یک‌بار تأیید کنید که قانون واقعاً نشسته است.

سایت را از طریق HTTPS بازدید کنید، بعد یک تب جدید باز کنید و فقط hostname خالی را تایپ کنید. نوار آدرس باید مستقیم به https:// بپرد — بازنویسی داخل مرورگر اتفاق می‌افتد، پس هیچ درخواستی روی سیم نیست که رهگیر شود و هیچ ریدایرکتی نیست که دنبال شود. Chrome آنچه را ذخیره کرده در chrome://net-internals/#hsts نشان می‌دهد، شامل تاریخ انقضا، که وقتی دارید تست می‌کنید نه حدس می‌زنید مفید است.

دو عادت اینجا از سردرگمی نجاتتان می‌دهد. وقتی می‌خواهید رفتار اولین-بازدید را ببینید، از یک پروفایل مرورگر که هرگز سایت را بازدید نکرده تست کنید، و به یاد داشته باشید مرورگری که قانون را پیش از هر تغییری یاد گرفته همچنان طبق آن عمل می‌کند — که موضوع بخش بعدی است.

برگرداندن، و چیزی که برگرداندن نمی‌تواند بکند

Hsts را در همان multiselect از انتخاب خارج کنید و ذخیره کنید. edge بلافاصله فرستادن هدر را متوقف می‌کند، و هر مرورگری که هرگز آن را ندیده از آن پس عادی رفتار می‌کند.

چیزی که اتفاق نمی‌افتد همان بخشی است که آدم‌ها را غافلگیر می‌کند: مرورگرهایی که قانون را از قبل ثبت کرده‌اند تا پایان max-age همچنان اجرایش می‌کنند. خاموش‌کردن preset به آن‌ها دست پیدا نمی‌کند. با یک max-age یک‌ساله، بازدیدکننده‌ای که دیروز هدر را دیده تا یک سال، صرف‌نظر از اینکه سرور شما الان چه می‌گوید، HTTPS را اجبار می‌کند.

specification برای این حالت یک راه فرونشاندن دارد — سرو کردن هدر با max-age=0 به مرورگر می‌گوید دفعهٔ بعد که از طریق HTTPS بازدید کرد قانون را فراموش کند. این فقط تا وقتی کار می‌کند که سایت هنوز از طریق HTTPS در دسترس باشد، و باید تا وقتی مرورگرهایی که برایتان مهم‌اند برگردند ادامه پیدا کند، پس یک عقب‌نشینی برنامه‌ریزی‌شده است، نه یک کلید.

برای همین چک‌لیست بیشتر از برنامهٔ برگشت اهمیت دارد. شکست واقع‌بینانه هرگز «HSTS برای ما اشتباه بود» نیست؛ «یک URL فقط روی HTTP کار می‌کرد و بعداً فهمیدیم» است. درست‌کردن آن URL تقریباً همیشه سریع‌تر از برگشت است.

جایگاه HSTS در میان دیگر محافظت‌های شما

HSTS دقیقاً یک کار می‌کند: درخواست متن‌ساده را حذف می‌کند. روشن‌بودن در این باره ارزشش را دارد، چون گاهی «ما HSTS داریم» طوری گفته می‌شود که انگار سؤال امنیت الان پاسخ داده شده.

این یک certificate نیست — یک certificate معتبر را فرض می‌گیرد و یک نامعتبر را کشنده می‌کند. رمزنگاری هم نیست؛ آن کار TLS است، و HSTS فقط تضمین می‌کند TLS همان چیزی است که استفاده می‌شود. هیچ‌چیز را بازرسی نمی‌کند، پس جلوی هیچ injection، هیچ exploit و هیچ payload مخربی را نمی‌گیرد: آن کار WAF است. هیچ‌چیز را نمی‌شمارد، پس brute force و scraping همچنان کار rate limiting باقی می‌مانند. و دربارهٔ اینکه چه کسی می‌تواند به شما برسد چیزی نمی‌گوید، که آنجا مسدودسازی کشور و ASN وارد می‌شود.

چیزی که آن را ارزش پنج دقیقه می‌کند نسبتش است. یک هدر، یک تنظیم، بدون نگهداری مستمر — و یک کل دستهٔ کامل از downgrade attack علیه بازدیدکنندگان شما دیگر ممکن نیست.

پرسش‌های پرتکرار

آیا HSTS به‌تنهایی کافی است؟

نه، و قرار هم نیست باشد. HSTS تضمین می‌کند اتصال رمزنگاری‌شده است؛ دربارهٔ اینکه چه چیزی رویش جابه‌جا می‌شود چیزی نمی‌گوید. درخواستی که SQL injection حمل می‌کند دقیقاً همان‌قدر امن از طریق HTTPS می‌رسد که از طریق HTTP. جایش کنار یک certificate معتبر، یک WAF، rate limiting و قواعد دسترسی معقول است — نه به‌جای آن‌ها.

آیا HSTS جایگزین ریدایرکت HTTP به HTTPS من می‌شود؟

نه. ریدایرکت را نگه دارید. HSTS فقط بعد از اینکه مرورگر حداقل یک‌بار هدر را از طریق HTTPS دیده باشد اعمال می‌شود، پس هر بازدیدکنندهٔ اولین‌بار، هر دستگاه جدید و هر crawler همچنان روی پورت 80 می‌رسد و به 301 نیاز دارد. این دو نیمهٔ متفاوت همان یک مشکل را می‌پوشانند.

آیا ساب‌دامنه‌های من را هم پوشش می‌دهد؟

با این preset نه. فقط max-age می‌فرستد، پس قانون فقط روی همان hostname دقیقی که پاسخ را سرو کرده اعمال می‌شود. پوشش ساب‌دامنه‌ها به includeSubDomains نیاز دارد، که تعهد بسیار بزرگ‌تری است: بلافاصله در مرورگر اعمال می‌شود و از آنجا قابل پس‌گرفتن نیست، پس پیش از آنکه به آن فکر کنید هر نامی زیر دامنه‌تان باید روی HTTPS کارآمد باشد.

آیا باید دامنه‌ام را به لیست preload HSTS بفرستم؟

فقط بعد از اینکه HTTPS همه‌جا ماه‌ها بی‌دردسر بوده. Preload کردن دامنهٔ شما را داخل مرورگر می‌گذارد، پس حتی از همان اولین درخواست بازدیدکننده هم محافظت می‌کند — اما حذفش یعنی ثبت‌نام نزد یک شخص‌ثالث و انتظار برای انتشار نسخه‌های مرورگر، پس یک اشتباه مدت زیادی می‌ماند. یک max-age یک‌ساله بیشتر مزیت را می‌دهد و راه برگشت را هم باز نگه می‌دارد.

آیا HSTS از اولین بازدید مطلق کسی محافظت می‌کند؟

به‌تنهایی نه — این همان شکافی است که باقی می‌گذارد. اولین بازدید همان چیزی است که قانون را به مرورگر یاد می‌دهد، و به‌جای HSTS با ریدایرکت شما و یک certificate معتبر محافظت می‌شود. Preload کردن تنها راه بستن آن شکاف است، برای همین آن لیست وجود دارد.

آیا روی کارایی اثر می‌گذارد؟

کمی به نفع شما. هدر چند ده بایت است، و به‌محض اینکه مرورگر آن را داشته باشد، هر لینک http:// به سایت شما داخل مرورگر بازنویسی می‌شود به‌جای اینکه هزینهٔ یک رفت‌وبرگشت به ریدایرکت شما را داشته باشد. بازدیدکنندگانی که قبلاً از طریق یک 301 می‌رسیدند، آن را کاملاً حذف می‌کنند.