سایت باز میشود، صفحه لود میشود، اما کنسول مرورگر پر از خطای قرمز است و دکمهای که باید کار کند، کار نمیکند. یا بدتر: همهچیز روی دسکتاپ درست است و روی موبایل، بخشی از صفحه سفید میماند. در نُه مورد از ده موردی که این علامت را دیدهام، کسی یک هدر امنیتی را با مقدار سختگیرانه فعال کرده و بعد فراموش کرده که آن هدر، دامنهٔ خودش را هم محدود میکند. هدر امنیتی ابزار خوبی است، ولی مثل ترمز ABS است: اگر بلد نباشی کجا بزنی، خودش باعث تصادف میشود.
قبل از هر چیز، ببینیم الان چه چیزی روی سرور ست شده. یک دستور ساده کافی است:
curl -sI https://example.com | grep -iE 'strict-transport|content-security|x-frame|x-content-type|referrer-policy|permissions-policy'
اگر خروجی خالی بود، یعنی هیچ هدر امنیتیای نداری. اگر پر بود، اول باید بفهمی هر کدام دقیقاً چه کاری میکند، چون ترتیب فعالسازی مهمتر از خودِ فعالسازی است.
هر هدر امنیتی چه حملهای را میبندد
هدرها را میشود به دو دسته تقسیم کرد: آنهایی که جلوی مرورگر را میگیرند، و آنهایی که جلوی مهاجم را. دستهٔ اول سریع اثر میکند و ریسکش پایین است. دستهٔ دوم اثرش عمیقتر است ولی اگر اشتباه ست شود، سایت را از دسترس کاربر میاندازد.
| هدر | حملهای که میبندد | ریسک اشتباه |
|---|---|---|
X-Content-Type-Options: nosniff | MIME sniffing و اجرای فایل آپلودی بهعنوان اسکریپت | تقریباً صفر |
X-Frame-Options: DENY | Clickjacking | پایین، مگر اینکه سایت را داخل iframe جاسازی کنی |
Referrer-Policy | نشت URL داخلی به سایتهای بیرونی | پایین |
Strict-Transport-Security | SSL stripping و downgrade به HTTP | بالا اگر preload کنی |
Content-Security-Policy | XSS، تزریق اسکریپت، دزدی داده | بالا اگر سختگیرانه شروع کنی |
دو هدر آخر هستند که همه را به دردسر میاندازند. بقیه را میتوانی همین امروز با خیال راحت اضافه کنی.
X-Content-Type-Options و Referrer-Policy: از اینجا شروع کن
این دو خط را در کانفیگ وبسرور بگذار و برو سراغ کار بعدی:
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-Frame-Options "SAMEORIGIN" always;
کلمهٔ always در Nginx مهم است. اگر نگذاری، این هدرها روی پاسخهای خطا مثل 404 و 500 اعمال نمیشوند و همان صفحات خطا میشوند نقطهٔ ورود. این را در بازبینیهای امنیتی زیاد دیدهام.
HSTS: چرا preload تله است
هدر Strict-Transport-Security به مرورگر میگوید تا مدت مشخصی، این دامنه را فقط با HTTPS باز کن. ساده است:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
عدد 31536000 یعنی یک سال، بر حسب ثانیه. حالا تله: includeSubDomains را وقتی بگذار که مطمئنی همهٔ زیردامنههایت HTTPS معتبر دارند. اگر یک زیردامنهٔ قدیمی داری که فقط HTTP است، از لحظهای که مرورگر این هدر را دید، آن زیردامنه برای همهٔ کاربرانی که قبلاً سایت را باز کردهاند غیرقابلدسترس میشود. نه با پاک کردن کش، نه با تغییر DNS. باید صبر کنی تا max-age تمام شود.
و بعد preload. preload یعنی دامنهات را در لیست سختی که داخل خود مرورگر کامپایل شده ثبت میکنی. از آن لحظه، حتی اولین بازدید هم مجبور به HTTPS است و دیگر راه برگشتی نداری. من preload را فقط برای دامنهای توصیه میکنم که حداقل شش ماه با HSTS بدون مشکل کار کرده، همهٔ زیردامنههایش HTTPS دارند، و برنامهای برای مهاجرت به دامنهٔ دیگر ندارد. برای بقیه، همان max-age یکساله کافی است.
اگر هنوز روی سرور گواهی معتبر نداری، اول آن را درست کن؛ راهنمای خطای SSL و روش تشخیص آن نقطهٔ شروع خوبی است. HSTS روی HTTPS شکسته، فقط شکست را سریعتر میکند.
CSP: مؤثرترین هدر امنیتی و پرخطرترین
Content-Security-Policy تنها هدری است که واقعاً جلوی XSS را میگیرد. بقیه هدرها لایهٔ دفاعیاند؛ CSP دیوار اصلی است. ولی همین CSP است که سایتها را سفید میکند.
اشتباه رایج این است که آدم از یک راهنمای اینترنتی کپی میکند و این را میگذارد:
add_header Content-Security-Policy "default-src 'self'; script-src 'self'" always;
و بعد سایتش پر از اسکریپت inline میشود که هیچکدام اجرا نمیشوند. دکمهٔ منو کار نمیکند، فرم تماس ارسال نمیشود، و چون خطا در کنسول است نه در لاگ سرور، ساعتها دنبال باگ در کد میگردد.
با Report-Only شروع کن، نه با enforce
ترتیب درست این است. اول با حالت گزارشدهی فعال کن:
add_header Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self' https://cdn.example.com; report-uri /csp-report" always;
مرورگر هیچچیز را بلاک نمیکند، ولی هر چیزی که نقض میشود را به آن آدرس میفرستد. یک هفته لاگ جمع کن. آنوقت میفهمی واقعاً به چه دامنههایی نیاز داری، نه آنهایی که فکر میکردی. بعد از یک هفته، همان policy را بدون -Report-Only بگذار.
نکتهٔ عملی: اگر سایتت وردپرس است، CSP سختگیرانه تقریباً همیشه پلاگینها را میشکند، چون خیلی از آنها اسکریپت inline تزریق میکنند. قبل از دستزدن به CSP، اول پلاگینهای اضافی را حذف کن؛ راهنمای امنیت وردپرس از wp-config تا افزونهها همین کار را مرحلهبهمرحله توضیح میدهد. اگر REST API سایتت باز است، آن هم مسیر نشت اطلاعات است و بستن راه نشت کاربران از REST API را جدا باید انجام دهی.
nonce و hash: راه درست برای اسکریپت inline
بهجای 'unsafe-inline' که کل CSP را بیاثر میکند، از nonce استفاده کن. وبسرور برای هر پاسخ یک مقدار تصادفی میسازد و در هدر میگذارد:
script-src 'nonce-rAnd0m123' 'strict-dynamic';
و همان مقدار را در تگ اسکریپت میگذاری: <script nonce="rAnd0m123">. کار دارد، ولی تنها راهی است که هم CSP واقعی داشته باشی و هم اسکریپتهای inline کار کنند. اگر سایت ایستا است، از hash استفاده کن که سادهتر است.
ترتیبی که واقعاً جواب میدهد
X-Content-Type-OptionsوReferrer-PolicyوX-Frame-Optionsرا همین امروز اضافه کن. ریسک صفر.- HTTPS را روی همهٔ زیردامنهها درست کن و ریدایرکت 301 از HTTP بگذار.
- HSTS را با
max-age=300شروع کن. یک هفته صبر کن. بعد به یک سال برسان. - CSP را با
-Report-Onlyبگذار و یک هفته لاگ جمع کن. - policy نهایی را enforce کن، با nonce برای اسکریپتهای inline.
- preload را فقط اگر شش ماه بدون مشکل گذشته، در نظر بگیر.
این ترتیب را رعایت کن، چون هر مرحله فرضهای مرحلهٔ بعد را میسازد. اگر CSP را قبل از پاکسازی اسکریپتهای inline بگذاری، فقط یک هفته وقت تلف کردهای.
یک نکتهٔ زیرساختی هم هست که زیاد نادیده گرفته میشود: هدر امنیتی روی لبهٔ شبکه هم میتواند ست شود، نه فقط روی وبسرور. اگر ترافیک از یک لایهٔ محافظت در برابر DDoS رد میشود، بعضی از این هدرها را همانجا هم میشود اعمال کرد و این باعث میشود حتی اگر کسی مستقیم به IP سرور بزند، هدرها گم نشوند. برای سایتهایی که هدف حملات حجمی هستند، این لایه ارزشش را دارد.
و در آخر: هدرها را در لاگ ممیزی ثبت کن. هر بار که کسی policy را عوض میکند، باید بدانی کِی و چرا. اگر هنوز لاگ ممیزی نداری، راهنمای نگهداشتن لاگ ممیزی دستنخورده را بخوان؛ بدون آن، دیباگ کردن یک CSP شکسته در آینده تقریباً غیرممکن است.
پرسشهای پرتکرار
چرا بعد از اضافه کردن CSP، بخشی از سایت سفید شده؟
چون CSP در حالت enforce، هر منبعی که در policy نیامده باشد را بلاک میکند و مرورگر بهجای نمایش، آن را حذف میکند. اولین کاری که باید بکنی این است که کنسول مرورگر را باز کنی و خطای Refused to load یا Refused to execute inline script را ببینی. آن خطا دقیقاً میگوید کدام دامنه یا کدام اسکریپت inline بلاک شده. تا وقتی این را ندیدهای، هر تغییری در policy حدس زدن است.
آیا HSTS میتواند سایت را برای همیشه از دسترس خارج کند؟
در حالت عادی نه، چون بعد از تمام شدن max-age مرورگر دوباره اجازهٔ HTTP میدهد. ولی اگر دامنه را در لیست preload ثبت کرده باشی، بله؛ آن لیست داخل خود مرورگر است و تا وقتی نسخهٔ جدید مرورگر منتشر نشود و کاربر آپدیت نکند، پاک نمیشود. به همین دلیل preload را فقط برای دامنهای توصیه میکنم که مطمئنی سالها روی همان دامنه میماند و همهٔ زیردامنههایش HTTPS دارند.
آیا هدر امنیتی جای فایروال یا WAF را میگیرد؟
نه. هدر امنیتی در مرورگر کاربر اجرا میشود، پس فقط روی کاربرانی اثر دارد که از طریق مرورگر به سایت میآیند. حملهای که مستقیم به API میزند یا از سمت سرور به سرور است، هیچکدام از این هدرها را نمیبیند. هدرها لایهٔ دفاعی سمت کلاینتاند و باید در کنار محافظت شبکه و احراز هویت سمت سرور باشند، نه بهجای آنها.
چطور بفهمم هدرهایم درست ست شدهاند؟
با curl -sI روی دامنه، یا با ابزارهای آنلاین بررسی هدر. ولی حتماً چند مسیر مختلف را تست کن: صفحهٔ اصلی، یک صفحهٔ داخلی، یک صفحهٔ 404، و یک پاسخ API. خیلی وقتها هدرها فقط روی پاسخهای 200 اعمال شدهاند و صفحات خطا بیمحافظت ماندهاند. اگر سایتت پشت چند لایه است، از بیرون شبکه تست کن، نه از داخل سرور.
دیدگاهها ۰
هنوز دیدگاهی ثبت نشده؛ اولین نفر باشید!