Политика безопасности контента
Политика безопасности контента (CSP) важна для защиты вашего приложения Next.js от различных угроз безопасности, таких как межсайтовый скриптинг (XSS), кликджекинг и другие атаки с внедрением кода.
Используя CSP, разработчики могут указать, какие источники допустимы для контента, скриптов, стилей, изображений, шрифтов, объектов, медиа (аудио, видео), фреймов и других элементов.
Примеры
Nonces
Nonce — это уникальная, случайная строка символов, созданная для одноразового использования. Она используется совместно с CSP для выборочного разрешения выполнения определённых встроенных скриптов или стилей, обойдя строгие директивы CSP.
Зачем использовать nonce?
Хотя CSP разработаны для блокировки вредоносных скриптов, существуют законные сценарии, где встроенные скрипты необходимы. В таких случаях nonces предоставляют способ разрешить выполнение этих скриптов, если у них есть правильный nonce.
Добавление nonce с помощью Middleware
Middleware позволяет добавлять заголовки и генерировать nonces до отрисовки страницы.
Каждый раз при просмотре страницы должен генерироваться новый nonce. Это означает, что необходимо использовать динамическую отрисовку для добавления nonces.
Например:
import { NextRequest, NextResponse } from 'next/server'
export function middleware(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 newline characters and spaces
const contentSecurityPolicyHeaderValue = cspHeader
.replace(/\s{2,}/g, ' ')
.trim()
const requestHeaders = new Headers(request.headers)
requestHeaders.set('x-nonce', nonce)
requestHeaders.set(
'Content-Security-Policy',
contentSecurityPolicyHeaderValue
)
const response = NextResponse.next({
request: {
headers: requestHeaders,
},
})
response.headers.set(
'Content-Security-Policy',
contentSecurityPolicyHeaderValue
)
return response
}По умолчанию Middleware выполняется для всех запросов. Можно фильтровать Middleware для выполнения на определённых путях, используя matcher.
Рекомендуется игнорировать совпадения с предварительными загрузками (из next/link) и статические ресурсы, которым не нужен заголовок CSP.
export const config = {
matcher: [
/*
* Match all request paths except for the ones starting with:
* - api (API routes)
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico (favicon file)
*/
{
source: '/((?!api|_next/static|_next/image|favicon.ico).*)',
missing: [
{ type: 'header', key: 'next-router-prefetch' },
{ type: 'header', key: 'purpose', value: 'prefetch' },
],
},
],
}Чтение nonce
Теперь вы можете прочитать nonce из Server Component, используя headers:
import { headers } from 'next/headers'
import Script from 'next/script'
export default function Page() {
const nonce = headers().get('x-nonce')
return (
<Script
src="https://www.googletagmanager.com/gtag/js"
strategy="afterInteractive"
nonce={nonce}
/>
)
}Без Nonces
Для приложений, которым не нужны nonces, вы можете установить заголовок CSP напрямую в файле next.config.js:
const cspHeader = `
default-src 'self';
script-src 'self' 'unsafe-eval' 'unsafe-inline';
style-src 'self' 'unsafe-inline';
img-src 'self' blob: data:;
font-src 'self';
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
upgrade-insecure-requests;
`
module.exports = {
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'Content-Security-Policy',
value: cspHeader.replace(/\n/g, ''),
},
],
},
]
},
}История версий
Рекомендуется использовать v13.4.20+ версии Next.js для правильной обработки и применения nonces.
© 2024 Vercel, Inc.
Licensed under the MIT License.
https://nextjs.org/docs/app/building-your-application/configuring/content-security-policy