تسلط بر هنر امنیت برنامههای وب پیشرونده
برنامههای وب پیشرونده (PWAs) به استاندارد اصلی برای ارائه تجربهای شبیه به اپلیکیشن در وب باز تبدیل شدهاند. قدرتهای اصلی آنها — قابلیت کارآفلاین، اعلانهای پوش، و قابلیت نصب — همچنین سطحهای حمله جدیدی را معرفی میکنند که وبسایتهای سنتی به ندرت با آن مواجه میشوند. این مقاله بهعمق دورهزندگی امنیتی یک PWA میپردازد و ترکیبی از سختسازی در سطح شبکه، محافظتهای زمان اجرا و بهترین روشهای عملیاتی را ارائه میدهد. در پایان، یک چکلیست خواهید داشت که میتوانید برای هر پروژهای بهکار ببرید، چه یک خبرخوان ساده باشد و چه یک پلتفرم تجارت الکترونیک پیچیده.
TL;DR: PWA خود را با HTTPS امن کنید، CSP سختگیرانهای اعمال کنید، سرویسورکرها را در «sandbox» قرار دهید، تمام ورودیها را اعتبارسنجی کنید و روتین مانیتورینگ مداومی اتخاذ کنید.
1. لایه حملونقل – خط اول دفاع
1.1 اعمال HTTPS در همهجا
تمام مرورگرهای مدرن برای ثبت سرویسورکر HTTPS را اجباری میکنند. اما برخی داراییها (مثلاً تجزیه و تحلیلهای شخص ثالث) ممکن است هنوز از طریق HTTP بارگذاری شوند که هشدارهای محتوای ترکیبی ایجاد کرده و دروازهای برای حملات «گیرنده در میان» (MITM) میشود.
مراحل کلیدی:
- دریافت یک گواهینامه TLS معتبر (Let’s Encrypt، Cloudflare و غیره).
- تغییر مسیر تمام درخواستهای
http://بهhttps://از طریق تنظیمات سرور. - فعالسازی HSTS (HTTP Strict Transport Security) برای اجبار مرورگرها به استفاده از HTTPS به مدت زمان از پیش تعریفشده.
# Example NGINX snippet
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# TLS settings ...
}
نکته: HSTS حملات کاهش سطح را حذف میکند، اما بهدلیل اینکه یکبار تنظیم شد مرورگرها برای مدت زمان تعیینشده از HTTP خودداری میکنند، برنامهریزی دقیق لازم است.
1.2 مهرگذاری گواهینامه (اختیاری)
برای PWAs با حساسیت بالا — بانکداری، سوابق بهداشتی — میتوانید مهرگذاری گواهینامه را از طریق Public Key Pinning Extension for HTTP (HPKP) در نظر بگیرید. هرچند HPKP بهدلیل خطرات استقرار در حال منسوخ شدن است، میتوانید با هدرهای Expect‑CT که شفافیت گواهینامه را تحمیل میکند، امنیت مشابهی بهدست آورید.
Expect-CT: max-age=86400, enforce, report-uri="https://example.com/report"
2. سختسازی سرویسورکر
سرویسورکرها قلب قابلیتهای آفلاین یک PWA هستند. آنها در یک رشته پسزمینه با امتیازات بالاتر اجرا میشوند و هدف اصلی برای بهرهبرداری هستند.
2.1 محدود کردن محدوده (Scope)
در هنگام ثبت سرویسورکر، کمترین scope ممکن را تعریف کنید. این کار جلوگیری میکند تا سرویسورکر درخواستهایی را که خارج از حوزه موردنظرش هستند، رهگیری کند.
navigator.serviceWorker.register('/sw.js', { scope: '/app/' })
.then(reg => console.log('SW registered with scope:', reg.scope));
2.2 اعتبارسنجی یکپارچگی با Subresource Integrity (SRI)
اگر اسکریپت سرویسورکر را از یک CDN بارگذاری میکنید، با SRI از اینکه کد دریافتشده با هش مورد انتظار مطابقت دارد، محافظت کنید.
<script src="https://cdn.example.com/sw.js"
integrity="sha384-abc123..."
crossorigin="anonymous"></script>
2.3 Content Security Policy برای سرویسورکرها
یک CSP سختگیرانه میتواند مانع از بارگذاری اسکریپتهای مخرب یا اتصال به مبدأهای غیرمجاز توسط سرویسورکر شود.
Content-Security-Policy: script-src 'self' https://trusted.cdn.com;
connect-src 'self' https://api.example.com;
نکته: از دستور
worker-src(در مرورگرهای جدید پشتیبانی میشود) برای تعیین صریح مبدأهای اسکریپتورکر استفاده کنید.
2.4 مدیریت حالت و اعتبارسنجی کش
هرگز به ورودیهای کش بهصورت کورکوران اعتمادی نداشته باشید. همیشه تازگی پاسخهای کششده را بخصوص برای توکنهای احراز هویت یا دادههای شخصی اعتبارسنجی کنید.
self.addEventListener('fetch', event => {
const url = new URL(event.request.url);
if (url.pathname.startsWith('/api/')) {
// Bypass cache for dynamic data
event.respondWith(fetch(event.request));
return;
}
// Default cache‑first strategy for static assets
event.respondWith(
caches.match(event.request).then(cached => cached || fetch(event.request))
);
});
3. محافظتهای زمان اجرا – CSP، Permissions و Sandbox
3.1 CSP کاملویژه
یک CSP خوب ریسک Cross‑Site Scripting (XSS) و Data Injection را کاهش میدهد. در زیر یک مثال سیاست برای یک PWA معمولی آمده است:
Content-Security-Policy:
default-src 'self';
script-src 'self' 'sha256-XYZ' https://analytics.example.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.example.com wss://socket.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
script-srcشامل یک هش برای اسکریپتهای درونخطی است تا ازunsafe-inlineجلوگیری شود.frame-ancestors 'none'جلوگیری از حملات clickjacking میکند.connect-srcAPIها و نقطه انتهایی WebSocket را لیست میکند.
3.2 Permissions Policy (قالب قبلی Feature‑Policy)
ویژگیهای قدرتمند مرورگری که ممکن است بهصورت ناخواسته توسط PWAها ارثبری شوند را محدود کنید.
Permissions-Policy: geolocation=(), microphone=(), camera=(), payment=()
3.3 ویژگی Sandbox برای محتوای جاسازیشده
اگر PWA شما iframeهای شخص ثالث را میزبانی میکند، برای جلوگیری از اجرای اسکریپت و ناوبری، آنها را «sandbox» کنید.
<iframe src="https://maps.example.com"
sandbox="allow-scripts allow-same-origin"
loading="lazy"></iframe>
4. احراز هویت و دسترسی
4.1 احراز هویت مبتنی بر توکن با JWT
از JSON Web Tokens (JWT) برای احراز هویت بدون حالت استفاده کنید، اما هرگز آنها را در localStorage ذخیره نکنید — بهجای آن از کوکیهای Secure, HttpOnly برای کاهش سرقت XSS استفاده کنید.
Set-Cookie: token=eyJhbGciOi...; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=3600
4.2 چرخش توکنهای Refresh
برای محدود کردن خسارت در صورت بهدست آمدن توکن، توکنهای Refresh را چرخانده (rotate) کنید.
- کلاینت توکن Refresh میفرستد.
- سرور آن را اعتبارسنجی کرده و هم توکن دسترسی جدید و هم توکن Refresh جدید صادر میکند.
- توکن Refresh قدیمی در پایگاه داده نامعتبر میشود.
4.3 مقابله با CSRF
حتی با کوکیهای SameSite، برای درخواستهای POST که وضعیت را تغییر میدهند از توکنهای Anti‑CSRF استفاده کنید.
<input type="hidden" name="csrf_token" value="{{ .CSRFToken }}">
در سرور، توکن ارسالشده را با جلسه کاربر مقایسه کنید.
5. ذخیرهسازی ایمن دادهها
PWAs میتوانند داده را از طریق IndexedDB، Cache API و Web Storage ذخیره کنند. هر کدام ملاحظات امنیتی خاص خود را دارند.
| ذخیرهسازی | مناسب برای | نکات امنیتی |
|---|---|---|
| Cache API | داراییهای ثابت، بازگشت آفلاین | فقط منابع غیرقابل تغییر را کش کنید. از نامهای کش نسخهبندیشده برای حذف دادههای منقضی استفاده کنید. |
| IndexedDB | دادههای ساختیافته، تنظیمات کاربر | فیلدهای حساس را بهصورت کلاینت‑ساید با Web Crypto API رمزنگاری کنید. |
| LocalStorage / SessionStorage | دادههای کوچک، غیرحساس | از ذخیرهسازی رازها اجتناب کنید. این دادهها برای هر اسکریپت صفحه در دسترس هستند. |
5.1 مثال: رمزنگاری دادههای IndexedDB
async function encryptAndStore(key, value) {
const cryptoKey = await crypto.subtle.generateKey(
{ name: "AES-GCM", length: 256 },
true,
["encrypt", "decrypt"]
);
const iv = crypto.getRandomValues(new Uint8Array(12));
const encoded = new TextEncoder().encode(value);
const ciphertext = await crypto.subtle.encrypt(
{ name: "AES-GCM", iv },
cryptoKey,
encoded
);
const db = await openDB('secure-store', 1, {
upgrade(db) { db.createObjectStore('secrets'); }
});
await db.put('secrets', { iv, ciphertext }, key);
}
6. مانیتورینگ، حسابرسی و واکنش به حوادث
امنیت یک پیکربندی یکباره نیست؛ یک چرخهی پیوسته است.
6.1 اسکن خودکار
- از OWASP ZAP یا Burp Suite برای اسکن XSS، CSRF و هدرهای ناامن استفاده کنید.
- Lighthouse را در خطلوله CI/CD یکپارچه کنید تا رعایت استانداردهای PWA را تحمیل کند.
6.2 لاگگیری زمان اجرا
خطاهای سرویسورکر را جمعآوری کنید و به یک نقطه انتهایی امن برای تجزیه و تحلیل بفرستید.
self.addEventListener('error', event => {
fetch('https://logs.example.com/collect', {
method: 'POST',
body: JSON.stringify({ message: event.message, stack: event.error.stack })
});
});
6.3 دفترچه راهنمای حوادث
- تشخیص: هشدار توسط ترافیک غیرعادی یا گزارشهای نقض CSP فعال میشود.
- محافظت: JWTهای بهدستآمده را ابطال کنید، کلیدهای API را چرخانده کنید.
- از بین بردن: کد آسیبپذیر را پچ کنید، کش سرویسورکر را بهروز کنید.
- بهسازی: نسخه جدید را مستقر کنید، نظارت بر تکرار را ادامه دهید.
- پستحلیل: علت ریشهای را مستند کنید و چکلیست امنیتی را بهروزرسانی کنید.
7. نمای کلی تصویری – لایههای امنیتی در یک PWA
flowchart TB
subgraph "Transport Layer"
H["\"HTTPS\""]
S["\"HSTS\""]
end
subgraph "Service Worker"
SW["\"Scope Limitation\""]
CS["\"Cache Validation\""]
end
subgraph "Runtime"
CSP["\"Content Security Policy\""]
PP["\"Permissions Policy\""]
SAN["\"Sandboxed iFrames\""]
end
subgraph "Auth & Data"
JWT["\"Secure Cookies\""]
REF["\"Refresh Rotation\""]
ENC["\"IndexedDB Encryption\""]
end
subgraph "Monitoring"
SCAN["\"OWASP ZAP\""]
LOG["\"Runtime Logging\""]
end
H --> SW --> CSP --> JWT --> SCAN
S --> SW
CS --> PP
PP --> ENC
LOG --> SCAN
این نمودار نشان میدهد که هر کنترل امنیتی بر پایهی قبلی خود ساخته میشود و معماری دفاع در عمق را میسازد.
8. چکلیست – مرجع سریع برای یک PWA ایمن
- تمام محتوا از طریق HTTPS با HSTS فعال سرو شود.
- سرویسورکرها را با کوچکترین
scopeممکن ثبت کنید. - اگر اسکریپت سرویسورکر را از CDN میگیرید، با Subresource Integrity حفاظت کنید.
- CSP سختگیرانهای اعمال کنید، شامل
worker-srcو هشهای اسکریپت. - از Permissions‑Policy برای غیرفعالسازی ویژگیهای مرورگر که استفاده نمیشوند، استفاده کنید.
- توکنهای احراز هویت را در کوکیهای Secure, HttpOnly ذخیره کنید؛ هرگز در localStorage نگهداری نکنید.
- توکنهای Refresh را چرخانده و توکنهای CSRF را برای درخواستهای تغییر وضعیت اعتبارسنجی کنید.
- دادههای حساس را در IndexedDB رمزنگاری کنید.
- اسکن OWASP ZAP خودکار را بر روی هر Pull Request اجرا کنید.
- لاگگیری زمان واقعی خطاهای سرویسورکر را تنظیم کنید.
- یک دفترچهٔ راهنمای واکنش به حادثه داشته باشید.
9. پرسشهای متداول
س۱: آیا PWAs برای امنیت به سرویسورکر نیاز دارند؟
خیر. اقدامات امنیتی مانند HTTPS، CSP و کوکیهای ایمن بهصورت مستقل کار میکنند. اما سرویسورکر جایی است که بیشتر حملات زمان اجرا بروز مییابند، بنابراین نیاز به سختسازی بیشتری دارد.
س۲: میتوانم unsafe-inline را در CSP برای استایلها استفاده کنم؟
ترجیحاً از آن خودداری کنید. بهجای آن استایلهای درونخطی را هش یا nonce کنید یا آنها را به فایلهای CSS خارجی منتقل کنید.
س۳: هر چند یکبار باید گواهینامه TLS را تجدید کنم؟
گواهینامههای Let’s Encrypt هر ۹۰ روز صادر میشوند؛ خودکارسازی تجدید توصیه میشود. برای گواهینامههای تجاری یا خودامضا، حداکثر اعتبار ۱ سال پیشنهاد میشود.
10. جمعبندی
PWAs مرز بین تجربههای بومی و وب را مخفی میکنند و قابلیتهای قدرتمندی ارائه میدهند که سطح حمله را هم گسترش میدهند. با لایهبندی امنیت در حملونقل، محدود کردن دامنه سرویسورکر، اعمال یک Content Security Policy دقیق و اتخاذ روشهای احراز هویت مستحکم، میتوانید PWA خود را بدون قربانی کردن کارایی یا تجربه کاربری امن کنید.
به یاد داشته باشید: امنیت یک سفر است، نه یک مقصد. وابستگیهای خود را بهروز نگه دارید، کد خود را بهصورت منظم حسابرسی کنید و از تهدیدات نوظهور آگاه باشید. با پیروی از روشهای مطرح در این مقاله، PWA شما در برابر حملات رایج وب محکم خواهد شد.