داشتن هدر 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 inline | Strict script policy میتواند اجرا را Block کند. | Contextual encoding، sanitize، validation |
DOM XSS در innerHTML | Script policy/Trusted Types سطح بهرهبرداری را کم میکند. | Safe DOM API و Code review |
| Script ثالث آلوده | اگر مجاز/Nonced باشد اجرا میشود. | کاهش Third-party، SRI، Vendor review |
| Clickjacking | frame-ancestors Parentهای مجاز را محدود میکند. | UX confirmation و SameSite حسب سناریو |
| Form exfiltration | form-action مقصد Submit را محدود میکند. | CSRF، validation و fraud control |
| Fetch/Image exfiltration | connect-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-src | Fallback بعضی Fetch directiveها | فرض اینکه برای همه Directiveها Fallback است. |
script-src | Script، eval و Wasm policy | Wildcard/https یا unsafe-inline |
style-src | Stylesheet و Style inline | بازکردن دائمی برای Page builder |
img-src | Image و بعضی Beaconها | * و Data exfiltration |
font-src | Font origin | فراموشی CDN/CORS |
connect-src | Fetch/XHR/WebSocket/EventSource | فراموشی Analytics/API/Realtime |
frame-src | Frameهایی که صفحه Embed میکند | اشتباه با frame-ancestors |
frame-ancestors | چه Parentی صفحه را Frame کند | حذف؛ از default-src ارث نمیبرد. |
worker-src | Worker/SharedWorker/Service Worker | Fallback و blob: بدون Scope |
object-src | Plugin/Object/Embed | قرارندادن 'none' |
base-uri | Base 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 Script | Policy و Cache سادهتر | Refactor Plugin/Theme |
| Nonce در Edge/origin بعد از Cache | Strict 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 گزارش
| فیلد/گروه | کاربرد |
|---|---|
| Disposition | Report یا Enforce |
| Effective directive | اولویت Rule شکستهشده |
| Blocked URL/inline/eval | نوع Resource یا رفتار |
| Document route/template | Owner و Blast radius |
| Release/asset version | Regression mapping |
| Browser/device | Compatibility یا Extension noise |
| Frequency/unique sessions | Severity و 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
- Routeها را جدا کنید: Home، article، search، login، account، cart، checkout، wp-admin.
- Theme/Plugin/Block/Widget/Tag/Payment/Chat را Inventory کنید.
- Report-only را در Production با Sampling جمع کنید.
- Inline handler/eval و Resource بدون Owner را حذف کنید.
- Hash/Nonce strategy را با Page cache تصمیم بگیرید.
- Checkout و Callback را با Provider واقعی تست کنید.
- Policy frontend و admin را جدا Canary کنید.
- 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
| سطح | تست |
|---|---|
| Static | Parser/Linter، Directive duplicate، wildcard و unsafe keyword |
| Browser | Console و Network روی Chrome/Firefox/Safari/WebView هدف |
| Journey | Login، Search، Form، Upload، Cart، Payment، Account |
| Third-party | Analytics، Chat، CAPTCHA، Map، Video، SSO |
| PWA | Service Worker، Worker، Offline، Update و Push |
| Attack | Inline/event/eval، injected remote script، frame، form exfil |
| Failure | ۴۰۳/۴۰۴/۵۰۰، maintenance، cache stale و rollback |
برای Service Worker و JavaScript rendering، راهنمای سئو و عملیات PWA کمک میکند Route و Cache state از قلم نیفتد.
Rollout بدون شکستن سایت
- Observe: Policy هدف در Report-only، بدون Allow خودکار.
- Classify: Required، Bug، Attack/Noise، Unknown.
- Remediate: Refactor/Nonce/Hash/Source محدود.
- Canary: Enforce روی Route/درصد کم یا Host داخلی.
- Expand: Template به Template با SLO خطا.
- Harden: حذف Transition source و unsafeها.
- 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
- آیا Enforce است یا Report-only؟
- Release/Policy/Route/Browser و Blast radius را ثبت کنید.
- Resource Blockشده Required، Attack، Extension یا Unknown است؟
- اگر Checkout/Login شکسته، Policy revision را Rollback کنید.
- Domain را بدون Root cause Allow نکنید.
- Source code/Plugin/Tag change را پیدا کنید.
- Fix، Test و Canary؛ سپس Exception موقت را حذف کنید.
برنامه ۳۰روزه CSP
| روز | کار | خروجی |
|---|---|---|
| ۱–۵ | Threat model، Route و Resource inventory | CSP manifest و Owner |
| ۶–۱۰ | Report endpoint و Policy هدف | Report-only امن |
| ۱۱–۱۵ | Triage، حذف Unknown و unsafe pattern | Remediation backlog |
| ۱۶–۲۰ | Nonce/Hash/Cache PoC و Trusted Types report | Strict policy candidate |
| ۲۱–۲۵ | Journey/Browser/Security test | Release gate |
| ۲۶–۳۰ | Canary enforce، SLO، rollback و dashboard | Production 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 از فهرست بلند دامنهها دفاع قویتری میسازد.






