سیاست امنیتی محتوا (CSP)؛ راهنمای Strict CSP برای WordPress

داشتن هدر CSP به‌تنهایی امنیت نیست. سیاستی مثل script-src 'self' https: ممکن است معتبر به نظر برسد، اما اگر Origin مجاز JSONP، Upload اجرایی یا Script gadget داشته باشد، مهاجم همان Allowlist را دور می‌زند. در سوی دیگر، یک Policy سخت‌گیرانه که درگاه، Checkout یا JavaScript حیاتی را می‌شکند، کنترل Production مناسبی نیست.

این راهنما Content Security Policy را به‌عنوان یک برنامهٔ مهندسی توضیح می‌دهد: Threat model، Inventory، Strict CSP با Nonce/Hash، Trusted Types، Reporting، WordPress/Cache، Third-party، Test و Rollout. CSP لایهٔ Defense in depth برای کاهش قابلیت بهره‌برداری است؛ جای Output encoding، Sanitization، Patch، Authentication یا Authorization را نمی‌گیرد. وضعیت استانداردها در ۱۵ مرداد ۱۴۰۵ / ۶ اوت ۲۰۲۶ بازبینی شده است.

پاسخ کوتاه: CSP چیست؟

CSP یک سیاست اعلانی است که مرورگر از هدر HTTP دریافت می‌کند و بر اساس Directiveها تصمیم می‌گیرد Script، Style، Image، Font، Frame، Worker، Form و Connection از کجا و با چه شرایطی مجاز باشند. Policy می‌تواند Enforce یا Report-only باشد. هدف اصلی، محدودکردن سطح اجرای کد و جریان Resource در صورت وجود Injection است.

مسیر پیشنهادی: ابتدا Resource/Inline inventory، سپس Report-only، حذف Handler و eval، انتخاب Nonce یا Hash، Canary enforce و در پایان Monitoring دائمی. Policy را از نمونهٔ اینترنت Copy نکنید؛ هر سایت Host، Plugin و Integration متفاوت دارد.

CSP می‌تواندCSP نمی‌تواند
اجرای Script بدون Trust مشخص را محدود کند.آسیب‌پذیری XSS را از Source حذف کند.
Framing را با frame-ancestors کنترل کند.Authorization یا CSRF را جایگزین کند.
Connection/Image/Frame مقصد را محدود کند.Origin مجازِ Compromised را خودکار امن کند.
Violation را گزارش و Regression را آشکار کند.هر حمله یا Leak را تضمینی ثبت کند.
Inline/eval و Sinkهای DOM را سخت‌تر کند.Logic flaw، SQL injection یا Credential theft بیرون صفحه را حل کند.

راهنمای CSP در OWASP نیز آن را Defense in depth می‌داند و می‌گوید نباید تنها دفاع XSS باشد. برای Threatهای REST/GraphQL/Webhook، راهنمای امنیت API را جدا اجرا کنید.

ابتدا Threat model، نه فهرست دامنه

سناریواثر CSPکنترل مکمل
Stored/reflected XSS با Script inlineStrict script policy می‌تواند اجرا را Block کند.Contextual encoding، sanitize، validation
DOM XSS در innerHTMLScript policy/Trusted Types سطح بهره‌برداری را کم می‌کند.Safe DOM API و Code review
Script ثالث آلودهاگر مجاز/Nonced باشد اجرا می‌شود.کاهش Third-party، SRI، Vendor review
Clickjackingframe-ancestors Parentهای مجاز را محدود می‌کند.UX confirmation و SameSite حسب سناریو
Form exfiltrationform-action مقصد Submit را محدود می‌کند.CSRF، validation و fraud control
Fetch/Image exfiltrationconnect-src/img-src مقصد را محدود می‌کنند.Data minimization و sink removal

هدر HTTP یا Meta؟

هدر HTTP انتخاب اصلی است: پیش از Parse سند اعمال می‌شود، Report-only و Directiveهای کامل را پشتیبانی می‌کند و روی پاسخ‌های مختلف Policy جدا می‌دهد. Meta فقط در محیط محدود مناسب است؛ Policy روی Resourceهای قبل از Meta اثر ندارد و Directiveهایی مانند frame-ancestors و Reporting در آن پشتیبانی نمی‌شوند. Report-only نیز با Meta ممکن نیست.

هدر را در CDN، Reverse proxy یا Origin تنظیم کنید، اما Owner واحد داشته باشید. چند CSP Enforce هم‌زمان با هم Intersect می‌شوند و نتیجه محدودتر است؛ Duplicateهای ناشناخته می‌توانند سایت را بشکنند.

نقشه Directiveهای ضروری

Directiveکنترلخطای رایج
default-srcFallback بعضی Fetch directiveهافرض اینکه برای همه Directiveها Fallback است.
script-srcScript، eval و Wasm policyWildcard/https یا unsafe-inline
style-srcStylesheet و Style inlineبازکردن دائمی برای Page builder
img-srcImage و بعضی Beaconها* و Data exfiltration
font-srcFont originفراموشی CDN/CORS
connect-srcFetch/XHR/WebSocket/EventSourceفراموشی Analytics/API/Realtime
frame-srcFrameهایی که صفحه Embed می‌کنداشتباه با frame-ancestors
frame-ancestorsچه Parentی صفحه را Frame کندحذف؛ از default-src ارث نمی‌برد.
worker-srcWorker/SharedWorker/Service WorkerFallback و blob: بدون Scope
object-srcPlugin/Object/Embedقرارندادن 'none'
base-uriBase URL سندحذف؛ از Default ارث نمی‌برد.
form-actionمقصد Form submitحذف؛ از Default ارث نمی‌برد.

Baseline محدودکننده، نه نسخهٔ آماده

Content-Security-Policy-Report-Only:
  default-src 'none';
  script-src 'self';
  style-src 'self';
  img-src 'self' data:;
  font-src 'self';
  connect-src 'self';
  frame-src 'none';
  worker-src 'self';
  object-src 'none';
  base-uri 'none';
  form-action 'self';
  frame-ancestors 'none';
  report-uri /security/csp-reports;
  report-to csp-endpoint

این فقط نقطهٔ تحلیل است و احتمالاً برای WordPress واقعی Resourceها را Report می‌کند. هر Source جدید باید Owner، Use case و Expiry داشته باشد. data:، blob: و Scheme گسترده را تنها در Directive لازم باز کنید.

Strict CSP با Nonce یا Hash

CSP Level ۳ جاری W3C در مهٔ ۲۰۲۶ Working Draft است و Strict CSP را بر Trust مبتنی بر Nonce/Hash و strict-dynamic توضیح می‌دهد. Host allowlistهای بزرگ شکننده‌اند؛ Origin مجاز ممکن است Gadget داشته باشد.

Nonce-based policy

Content-Security-Policy:
  script-src 'nonce-{RANDOM_PER_RESPONSE}' 'strict-dynamic' https:;
  object-src 'none';
  base-uri 'none';
  form-action 'self';
  frame-ancestors 'none'

Nonce باید برای هر پاسخ منحصربه‌فرد، غیرقابل‌حدس، حداقل ۱۲۸ بیت پیش از Encoding و با CSPRNG تولید شود. همان مقدار فقط به Scriptهایی داده شود که واقعاً Trust شده‌اند. تزریق خودکار Nonce به هر <script> خروجی، Script مهاجم را هم Trusted می‌کند.

Hash-based policy

برای HTML استاتیک، Hash محتوای دقیق Script مناسب است. Space، Line ending یا Minification Hash را تغییر می‌دهد. Build باید Hash را تولید و Header را Atomic منتشر کند. Hash یک Script ثالثِ متغیر را بدون Pin مدیریت نکنید.

معنای strict-dynamic

در Browser پشتیبان CSP3، Trust Script دارای Nonce/Hash به Scriptهای Non-parser-inserted که آن Load می‌کند منتقل می‌شود و Host sourceهایی مانند 'self' یا https: برای Script نادیده گرفته می‌شوند. اگر Loader URL را از دادهٔ مهاجم بسازد، همچنان Bypass دارید؛ Loader و APIهای ساخت Script باید Audit شوند.

Nonce و Full-page cache در WordPress

Nonce CSP با Cache اشتراک نام دارد اما Nonce امنیتی WordPress نیست. اگر HTML دارای Nonce در Page cache/CDN ذخیره شود، مقدار میان کاربران/درخواست‌ها تکرار می‌شود و شرط Unique-per-response از بین می‌رود.

راهمزیتهزینه
Hash-based برای Inline ثابتسازگار با HTML cacheبا تغییر Content باید Rebuild شود.
Externalize ScriptPolicy و Cache ساده‌ترRefactor Plugin/Theme
Nonce در Edge/origin بعد از CacheStrict dynamic HTMLپیچیدگی و Atomic header/body injection
Bypass cache برای Page حساسNonce صحیحهزینه Performance/Origin
Allowlist انتقالیراه‌اندازی سریع‌ترکاهش قدرت XSS و بدهی Policy

Theme، Plugin، Gutenberg، WooCommerce و Tag manager ممکن است Inline script/style یا Handler تولید کنند. آن‌ها را Inventory و به‌تدریج Externalize/Nonce/Hash کنید؛ CSP generator افزونه‌ای که فقط Domain جمع می‌کند، Strict CSP نمی‌سازد.

حذف unsafe-inline و unsafe-eval

  • onclick="..." را به addEventListener منتقل کنید.
  • Script inline پویا را Nonce کنید، نه کل DOM را.
  • Template engine و Plugin استفاده‌کننده از eval/Function را پیدا کنید.
  • Style inline را Externalize یا با Nonce/Hash محدود مدیریت کنید.
  • unsafe-hashes را فقط Bridge موقت با Scope و Expiry بدانید.
  • Policy frontend، login، checkout و wp-admin را جدا آزمایش کنید.

unsafe-inline یا unsafe-eval به معنی «CSP بی‌فایده» در همه Directiveها نیست، اما محافظت Script را به‌شدت تضعیف می‌کند. هر Exception باید Debt ticket و Removal date داشته باشد؛ راهنمای بدهی فنی برای همین Register مفید است.

WebAssembly و wasm-unsafe-eval

مستند جاری script-src در MDN می‌گوید Compile/Instantiate وب‌اسمبلی بدون مجوز مربوط Block می‌شود. wasm-unsafe-eval فقط Wasm را باز می‌کند و از unsafe-eval محدودتر است. اگر سایت Wasm دارد، Capability را صریح و روی Browser matrix تست کنید؛ unsafe-eval عمومی را صرفاً برای حل خطا اضافه نکنید.

برای معماری، Load و Security Wasm، راهنمای WebAssembly را ببینید.

Trusted Types برای DOM XSS

Trusted Types Assignment رشتهٔ خام به Injection sinkهایی مانند innerHTML را محدود می‌کند و Code را وادار می‌کند از Policy بازبینی‌شده عبور کند. MDN، trusted-types را Baseline ۲۰۲۶ می‌داند؛ Device/Browser قدیمی ممکن است حمایت نکند.

Content-Security-Policy-Report-Only:
  require-trusted-types-for 'script';
  trusted-types app-html sanitizer

ابتدا Sinkها را در Report-only پیدا کنید، Policyهای محدود و نام‌دار بسازید و Wildcard policy ندهید. Trusted Types جای Sanitizer امن یا رفع Source مهاجم نیست؛ Contract استفاده از Sink است.

Reporting درست در ۲۰۲۶

report-to از مارس ۲۰۲۶ در Browserهای جدید Baseline شده، اما برای Clientهای قدیمی هنوز Coverage یکسان نیست. راهنمای MDN توصیه می‌کند فعلاً report-uri deprecated را کنار report-to نگه دارید.

Reporting-Endpoints: csp-endpoint="https://example.ir/security/csp-reports"

Content-Security-Policy-Report-Only:
  default-src 'self';
  report-uri https://example.ir/security/csp-report-legacy;
  report-to csp-endpoint

Reporting-Endpoints جای Header قدیمی و deprecated Report-To را می‌گیرد. Reportها Delivery تضمین‌شده نیستند و دادهٔ آن‌ها مهاجم‌-کنترل است.

امن‌سازی Endpoint گزارش

  • بدون Cookie/Auth وابسته و با Rate limit دریافت کنید.
  • Content-Type و Size را محدود کنید.
  • JSON را Validate و هنگام نمایش Escape کنید.
  • URL/Referrer/Sample را PII احتمالی بدانید.
  • Deduplicate و Sample کنید؛ Loop گزارش نسازید.
  • Endpoint را خارج Policy failure path نگه دارید.
  • Retention و Access را محدود کنید.

Triage گزارش

فیلد/گروهکاربرد
DispositionReport یا Enforce
Effective directiveاولویت Rule شکسته‌شده
Blocked URL/inline/evalنوع Resource یا رفتار
Document route/templateOwner و Blast radius
Release/asset versionRegression mapping
Browser/deviceCompatibility یا Extension noise
Frequency/unique sessionsSeverity و Noise suppression

Browser extension، Antivirus injection و Translation tool Noise می‌سازند. Domain را خودکار Allow نکنید؛ ابتدا Reproduce و Owner را پیدا کنید.

Third-party، Tag manager و CSP

اجازه‌دادن یک Tag manager می‌تواند در عمل اجازهٔ Load Scriptهای بعدی باشد. CSP Governance باید Container permission، Publish role، Template، Custom HTML و Audit log را نیز پوشش دهد.

  • Vendor/Domain/Directive/Owner/Purpose/Expiry inventory؛
  • حذف Tag بدون Owner یا استفاده؛
  • Staging container و approval دو نفره؛
  • Pin/SRI برای Asset ثابتِ cross-origin در صورت امکان؛
  • Consent و Data map مستقل؛
  • Kill switch و Incident contact؛
  • ارزیابی Subdomain takeover و Broad wildcard.

برنامه CSP برای WordPress و WooCommerce

  1. Routeها را جدا کنید: Home، article، search، login، account، cart، checkout، wp-admin.
  2. Theme/Plugin/Block/Widget/Tag/Payment/Chat را Inventory کنید.
  3. Report-only را در Production با Sampling جمع کنید.
  4. Inline handler/eval و Resource بدون Owner را حذف کنید.
  5. Hash/Nonce strategy را با Page cache تصمیم بگیرید.
  6. Checkout و Callback را با Provider واقعی تست کنید.
  7. Policy frontend و admin را جدا Canary کنید.
  8. Plugin update را CSP regression gate کنید.

در Shared hosting ممکن است Header در Web server، Panel، CDN یا PHP تنظیم شود. Control plane و قابلیت always روی پاسخ خطا/Redirect را از Host بپرسید. برای مرز مسئولیت، راهنمای امنیت هاست اشتراکی را ببینید.

نمونه Header در Server

NGINX

add_header Content-Security-Policy-Report-Only
  "default-src 'self'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'; report-uri /security/csp-reports" always;

Apache

Header always set Content-Security-Policy-Report-Only \
  "default-src 'self'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'; report-uri /security/csp-reports"

این نمونه‌ها Policy کامل سایت نیستند. Syntax/Module/Proxy و Header موجود را بررسی، Config test و Rollback آماده کنید. در CDN مطمئن شوید Origin Header دوباره Append نمی‌شود.

Test matrix پیش از Enforce

سطحتست
StaticParser/Linter، Directive duplicate، wildcard و unsafe keyword
BrowserConsole و Network روی Chrome/Firefox/Safari/WebView هدف
JourneyLogin، Search، Form، Upload، Cart، Payment، Account
Third-partyAnalytics، Chat، CAPTCHA، Map، Video، SSO
PWAService Worker، Worker، Offline، Update و Push
AttackInline/event/eval، injected remote script، frame، form exfil
Failure۴۰۳/۴۰۴/۵۰۰، maintenance، cache stale و rollback

برای Service Worker و JavaScript rendering، راهنمای سئو و عملیات PWA کمک می‌کند Route و Cache state از قلم نیفتد.

Rollout بدون شکستن سایت

  1. Observe: Policy هدف در Report-only، بدون Allow خودکار.
  2. Classify: Required، Bug، Attack/Noise، Unknown.
  3. Remediate: Refactor/Nonce/Hash/Source محدود.
  4. Canary: Enforce روی Route/درصد کم یا Host داخلی.
  5. Expand: Template به Template با SLO خطا.
  6. Harden: حذف Transition source و unsafeها.
  7. Operate: Alert، Ownership، Expiry و Review دوره‌ای.

Kill switch باید Policy را به نسخهٔ قبلی بازگرداند، نه CSP را برای همیشه حذف کند. Revision policy را کنار Release application ثبت کنید.

CSP، Performance و SEO

CSP فاکتور رتبهٔ مستقیم معرفی‌شده‌ای نیست و Resource غیرضروری را به‌عنوان ابزار Performance مدیریت نکنید. Policy اشتباه می‌تواند JavaScript، Style، Font، Image یا API ضروری را Block و UX/Render را خراب کند؛ این اثر عملی مهم است.

  • Raw HTML و Rendered DOM را مقایسه کنید.
  • Canonical، Schema، Navigation و Content اصلی را بررسی کنید.
  • RUM Error و Core Web Vitals را قبل/بعد مقایسه کنید.
  • Googlebot را در Allowlist ویژه قرار ندهید؛ Resource policy صحیح بسازید.
  • URL Inspection/Render test را روی Template نمونه انجام دهید.
  • Policy را روی ۴۰۴/5xx و Redirect نیز کنترل کنید.

برای Field data و Regression، راهنمای Core Web Vitals و RUM را به Deployment متصل کنید.

ملاحظات CSP برای سایت‌های ایرانی

سرویس ثالث و تغییر دامنه

درگاه، پرداخت‌یار، نقشه، پیامک، Chat، CDN و Analytics ممکن است Domain/Redirect/Asset متغیر داشته باشند. Host را از Traffic تصادفی Allow نکنید؛ مستند Vendor، Sandbox و Journey واقعی را مبنا بگذارید. Wildcard برای راحتی، Risk را منتقل می‌کند.

شبکه و False failure

Timeout یا Block شبکه CSP violation نیست. Network error، CSP block و Vendor error را در Telemetry جدا کنید. Test از اپراتور/Browser هدف انجام شود.

میزبانی و Cache

ممکن است کنترل Header میان هاست، LiteSpeed/NGINX، Cloud/CDN و WordPress تقسیم باشد. Source of truth، Order اعمال و Purge/rollback را مستند کنید. Nonce تکراری در Full-page cache را با تست چند پاسخ پیدا کنید.

عملیات و دسترسی ابزار

به Dashboard SaaS گزارش‌گیری واحد وابسته نشوید. Endpoint داخلی/قابل‌انتقال، Export و Alert جایگزین داشته باشید. Report ممکن است URL فارسی/Query حساس داشته باشد؛ Retention و Redaction را اعمال کنید.

Runbook رخداد CSP

  1. آیا Enforce است یا Report-only؟
  2. Release/Policy/Route/Browser و Blast radius را ثبت کنید.
  3. Resource Blockشده Required، Attack، Extension یا Unknown است؟
  4. اگر Checkout/Login شکسته، Policy revision را Rollback کنید.
  5. Domain را بدون Root cause Allow نکنید.
  6. Source code/Plugin/Tag change را پیدا کنید.
  7. Fix، Test و Canary؛ سپس Exception موقت را حذف کنید.

برنامه ۳۰روزه CSP

روزکارخروجی
۱–۵Threat model، Route و Resource inventoryCSP manifest و Owner
۶–۱۰Report endpoint و Policy هدفReport-only امن
۱۱–۱۵Triage، حذف Unknown و unsafe patternRemediation backlog
۱۶–۲۰Nonce/Hash/Cache PoC و Trusted Types reportStrict policy candidate
۲۱–۲۵Journey/Browser/Security testRelease gate
۲۶–۳۰Canary enforce، SLO، rollback و dashboardProduction policy v1

چک‌لیست نهایی CSP

  • CSP به‌عنوان Defense in depth تعریف شده است.
  • Threat model، Route، Resource و Third-party inventory Owner دارند.
  • Header HTTP منبع اصلی و Meta فقط با محدودیت استفاده شده است.
  • object-src، base-uri، form-action و frame-ancestors صریح‌اند.
  • Script trust بر Nonce/Hash است، نه Allowlist گسترده.
  • Nonce حداقل ۱۲۸ بیت، CSPRNG و منحصربه‌فرد هر پاسخ است.
  • Page cache/CDN Nonce را تکرار نمی‌کند.
  • unsafe-inline/unsafe-eval حذف یا Debt زمان‌دار دارند.
  • Wasm فقط با wasm-unsafe-eval و نیاز واقعی باز شده است.
  • Trusted Types در Report-only و Progressive اجرا شده است.
  • Reporting-Endpoints، report-to و fallback قدیمی درست‌اند.
  • Report مهاجم‌-کنترل، محدود، Redact و Deduplicate می‌شود.
  • Login، Checkout، Admin، PWA و Third-party تست شده‌اند.
  • Canary، SLO، Kill switch و Policy revision وجود دارند.

سؤالات متداول CSP

آیا CSP همه حملات XSS را متوقف می‌کند؟

خیر. Strict CSP بسیاری از مسیرهای اجرای XSS را سخت یا Block می‌کند، اما Vulnerability، Trusted third-party، Logic و DOM sink را خودکار رفع نمی‌کند. Encoding، Sanitization، Safe API، Patch و Test همچنان لازم‌اند.

برای CSP از Nonce استفاده کنیم یا Hash؟

برای HTML پویا Nonce رایج‌تر است؛ باید هر پاسخ Unique باشد. Hash برای Inline ثابت و Page cache مناسب است، اما با هر تغییر محتوا عوض می‌شود. WordPress کش‌شده اغلب به Refactor/Hash یا Injection بعد از Cache نیاز دارد.

تفاوت Report-only و Enforce چیست؟

Report-only نقض Policy هدف را گزارش می‌کند اما Block نمی‌کند؛ برای کشف Dependency و Regression است. Enforce Resource/Behavior ناسازگار را Block می‌کند. Report-only پایان کار نیست و Report نیز تضمین Delivery یا حمله بودن ندارد.

آیا افزونه WordPress می‌تواند CSP را خودکار بسازد؟

افزونه می‌تواند Header یا Inventory اولیه بدهد، اما Strict trust، Cache/Nonce، Inline code، Checkout، Admin و Third-party به معماری و تست نیاز دارند. Allow خودکار هر Domain مشاهده‌شده خطرناک است.

آیا CSP به سئو آسیب می‌زند؟

خود CSP تاکتیک رتبه نیست. Policy اشتباه می‌تواند Resource حیاتی، Content یا Navigation را Block و تجربه/Render را خراب کند. Report-only، تست Render و RUM از این Regression جلوگیری می‌کنند.

جمع‌بندی

CSP سپر نفوذناپذیر نیست؛ Contract اجرای محتوا در Browser است. Policy مؤثر از Threat model و Inventory شروع می‌شود، Script را با Nonce/Hash Trust می‌کند، Report را امن تحلیل و به‌تدریج Enforce می‌شود. در WordPress، مسئلهٔ اصلی Inline code، Plugin/Tag و تکرار Nonce در Cache است. سیاست کوچک، نسخه‌دار، قابل Rollback و دارای Owner از فهرست بلند دامنه‌ها دفاع قوی‌تری می‌سازد.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *