~4 دقیقه مطالعه • بروزرسانی ۲۰ آذر ۱۴۰۴
چرا Content Security Policy مهم است؟
CSP از اپلیکیشن شما در برابر حملاتی مانند XSS، کلیکجکینگ و تزریق کد محافظت میکند. با محدود کردن منابع مجاز برای بارگذاری محتوا، اسکریپت، استایل، فونت، مدیا و iframeها، امنیت اپلیکیشن افزایش مییابد.
Nonce چیست؟
Nonce یک رشتهٔ تصادفی و یکتا است که در هر درخواست تولید میشود. با استفاده از nonce میتوان اجرای اسکریپتهای خاص را مجاز کرد، بدون اینکه CSP کلی اجازهٔ اجرای inline scriptها را بدهد.
افزودن nonce با Proxy
در فایل proxy.ts میتوان nonce تولید کرد و در هدر CSP قرار داد:
export function proxy(request: NextRequest) {
const nonce = Buffer.from(crypto.randomUUID()).toString('base64')
const cspHeader = `
default-src 'self';
script-src 'self' 'nonce-${nonce}' 'strict-dynamic';
style-src 'self' 'nonce-${nonce}';
img-src 'self' blob: data:;
font-src 'self';
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
upgrade-insecure-requests;
`.replace(/\s{2,}/g, ' ').trim()
const requestHeaders = new Headers(request.headers)
requestHeaders.set('x-nonce', nonce)
requestHeaders.set('Content-Security-Policy', cspHeader)
const response = NextResponse.next({ request: { headers: requestHeaders } })
response.headers.set('Content-Security-Policy', cspHeader)
return response
}تنظیم matcher برای Proxy
برای جلوگیری از اعمال CSP روی فایلهای استاتیک یا درخواستهای prefetch:
export const config = {
matcher: [
{
source: '/((?!api|_next/static|_next/image|favicon.ico).*)',
missing: [
{ type: 'header', key: 'next-router-prefetch' },
{ type: 'header', key: 'purpose', value: 'prefetch' },
],
},
],
}نحوهٔ کار nonce در Next.js
- Proxy nonce را تولید کرده و در هدر CSP و
x-nonceقرار میدهد - Next.js nonce را از هدر CSP استخراج میکند
- Nonce بهصورت خودکار به موارد زیر اعمال میشود:
- اسکریپتهای React و Next.js
- باندلهای جاوااسکریپت صفحه
- استایلها و اسکریپتهای inline تولیدشده توسط Next.js
- کامپوننتهای
<Script>با prop nonce
فعالسازی رندرینگ پویا
برای پشتیبانی از nonce، صفحات باید بهصورت پویا رندر شوند. از connection() استفاده کنید:
import { connection } from 'next/server'
export default async function Page() {
await connection()
// محتوای صفحه
}خواندن nonce در Server Component
از headers() برای دریافت nonce استفاده کنید:
import { headers } from 'next/headers'
import Script from 'next/script'
export default async function Page() {
const nonce = (await headers()).get('x-nonce')
return (
<Script
src="https://www.googletagmanager.com/gtag/js"
strategy="afterInteractive"
nonce={nonce}
/>
)
}رندرینگ استاتیک در برابر پویا با CSP
استفاده از nonce نیازمند رندرینگ پویا است. این یعنی:
- غیرفعال شدن بهینهسازی استاتیک
- غیرفعال شدن ISR
- عدم کش شدن توسط CDN
- ناسازگاری با PPR
تأثیر بر عملکرد
- کندتر شدن بارگذاری اولیه صفحات
- افزایش بار سرور
- هزینهٔ بیشتر میزبانی
چه زمانی از nonce استفاده کنیم؟
- اگر سیاست امنیتی شما
'unsafe-inline'را ممنوع کرده - اگر اپلیکیشن دادههای حساس را مدیریت میکند
- اگر نیاز به اجرای اسکریپتهای خاص دارید
- اگر الزامات قانونی یا امنیتی دارید
جمعبندی
استفاده از CSP با nonce در Next.js امنیت اپلیکیشن را بهطور چشمگیری افزایش میدهد. اگرچه نیازمند رندرینگ پویا و منابع بیشتر است، برای اپلیکیشنهایی با حساسیت بالا یا الزامات امنیتی، یک انتخاب ضروری است.
نوشته و پژوهش شده توسط دکتر شاهین صیامی