Skip to content

Commit 6f83cf4

Browse files
committed
switch development origin verification to be opt-in rather than opt-out
1 parent 5c5207d commit 6f83cf4

File tree

4 files changed

+63
-30
lines changed

4 files changed

+63
-30
lines changed

docs/01-app/04-api-reference/05-config/01-next-config-js/allowedDevOrigins.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ description: Use `allowedDevOrigins` to configure additional origins that can re
55

66
{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
77

8+
Next.js does not automatically block cross-origin requests during development, but will block by default in a future major version of Next.js to prevent unauthorized requesting of internal assets/endpoints that are available in development mode.
9+
810
To configure a Next.js application to allow requests from origins other than the hostname the server was initialized with (`localhost` by default) you can use the `allowedDevOrigins` config option.
911

1012
`allowedDevOrigins` allows you to set additional origins that can be used in development mode. For example, to use `local-origin.dev` instead of only `localhost`, open `next.config.js` and add the `allowedDevOrigins` config:
@@ -14,5 +16,3 @@ module.exports = {
1416
allowedDevOrigins: ['local-origin.dev', '*.local-origin.dev'],
1517
}
1618
```
17-
18-
Cross-origin requests are blocked by default to prevent unauthorized requesting of internal assets/endpoints which are available in development mode. This behavior is similar to other dev servers like `webpack-dev-middleware` to ensure the same protection.

packages/next/src/server/config-shared.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1144,7 +1144,7 @@ export const defaultConfig: NextConfig = {
11441144
output: !!process.env.NEXT_PRIVATE_STANDALONE ? 'standalone' : undefined,
11451145
modularizeImports: undefined,
11461146
outputFileTracingRoot: process.env.NEXT_PRIVATE_OUTPUT_TRACE_ROOT || '',
1147-
allowedDevOrigins: [],
1147+
allowedDevOrigins: undefined,
11481148
experimental: {
11491149
nodeMiddleware: false,
11501150
cacheLife: {

packages/next/src/server/lib/router-server.ts

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -172,15 +172,6 @@ export async function initialize(opts: {
172172
;(globalThis as any)[Symbol.for('@next/middleware-subrequest-id')] =
173173
middlewareSubrequestId
174174

175-
const allowedOrigins = [
176-
'*.localhost',
177-
'localhost',
178-
...(config.allowedDevOrigins || []),
179-
]
180-
if (opts.hostname) {
181-
allowedOrigins.push(opts.hostname)
182-
}
183-
184175
const requestHandlerImpl: WorkerRequestHandler = async (req, res) => {
185176
// internal headers should not be honored by the request handler
186177
if (!process.env.NEXT_PRIVATE_TEST_HEADERS) {
@@ -332,7 +323,15 @@ export async function initialize(opts: {
332323

333324
// handle hot-reloader first
334325
if (developmentBundler) {
335-
if (blockCrossSite(req, res, allowedOrigins, `${opts.port}`)) {
326+
if (
327+
blockCrossSite(
328+
req,
329+
res,
330+
config.allowedDevOrigins,
331+
opts.hostname,
332+
`${opts.port}`
333+
)
334+
) {
336335
return
337336
}
338337
const origUrl = req.url || '/'
@@ -698,7 +697,15 @@ export async function initialize(opts: {
698697
})
699698

700699
if (opts.dev && developmentBundler && req.url) {
701-
if (blockCrossSite(req, socket, allowedOrigins, `${opts.port}`)) {
700+
if (
701+
blockCrossSite(
702+
req,
703+
socket,
704+
config.allowedDevOrigins,
705+
opts.hostname,
706+
`${opts.port}`
707+
)
708+
) {
702709
return
703710
}
704711
const { basePath, assetPrefix } = config

packages/next/src/server/lib/router-utils/block-cross-site.ts

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,51 @@ import net from 'net'
55
import { warnOnce } from '../../../build/output/log'
66
import { isCsrfOriginAllowed } from '../../app-render/csrf-protection'
77

8+
function warnOrBlockRequest(
9+
res: ServerResponse | Duplex,
10+
requestPath: string,
11+
mode: 'warn' | 'block'
12+
) {
13+
if (mode === 'warn') {
14+
warnOnce(
15+
`Cross origin request detected from ${requestPath}. In a future major version of Next.js, you will need to explicitly configure "allowedDevOrigins" in next.config to allow this.\nRead more: https://nextjs.org/docs/app/api-reference/config/next-config-js/allowedDevOrigins`
16+
)
17+
18+
return
19+
}
20+
21+
warnOnce(
22+
`Blocked cross-origin request from ${requestPath}. To allow this, configure "allowedDevOrigins" in next.config\nRead more: https://nextjs.org/docs/app/api-reference/config/next-config-js/allowedDevOrigins`
23+
)
24+
25+
if ('statusCode' in res) {
26+
res.statusCode = 403
27+
}
28+
29+
res.end('Unauthorized')
30+
}
31+
832
export const blockCrossSite = (
933
req: IncomingMessage,
1034
res: ServerResponse | Duplex,
11-
allowedOrigins: string[],
35+
allowedDevOrigins: string[] | undefined,
36+
hostname: string | undefined,
1237
activePort: string
1338
): boolean => {
14-
// only process _next URLs
39+
// in the future, these will be blocked by default when allowed origins aren't configured.
40+
// for now, we warn when allowed origins aren't configured
41+
const mode = typeof allowedDevOrigins === 'undefined' ? 'warn' : 'block'
42+
43+
const allowedOrigins = [
44+
'*.localhost',
45+
'localhost',
46+
...(allowedDevOrigins || []),
47+
]
48+
if (hostname) {
49+
allowedOrigins.push(hostname)
50+
}
51+
52+
// only process _next URLs when
1553
if (!req.url?.includes('/_next')) {
1654
return false
1755
}
@@ -21,13 +59,7 @@ export const blockCrossSite = (
2159
req.headers['sec-fetch-mode'] === 'no-cors' &&
2260
req.headers['sec-fetch-site'] === 'cross-site'
2361
) {
24-
if ('statusCode' in res) {
25-
res.statusCode = 403
26-
}
27-
res.end('Unauthorized')
28-
warnOnce(
29-
`Blocked cross-origin request to /_next/*. Cross-site requests are blocked in "no-cors" mode.`
30-
)
62+
warnOrBlockRequest(res, ' /_next/*', mode)
3163
return true
3264
}
3365

@@ -49,13 +81,7 @@ export const blockCrossSite = (
4981
!(isIpRequest && isMatchingPort) &&
5082
!isCsrfOriginAllowed(originLowerCase, allowedOrigins)
5183
) {
52-
if ('statusCode' in res) {
53-
res.statusCode = 403
54-
}
55-
res.end('Unauthorized')
56-
warnOnce(
57-
`Blocked cross-origin request from ${originLowerCase}. To allow this, configure "allowedDevOrigins" in next.config\nRead more: https://nextjs.org/docs/app/api-reference/config/next-config-js/allowedDevOrigins`
58-
)
84+
warnOrBlockRequest(res, originLowerCase, mode)
5985
return true
6086
}
6187
}

0 commit comments

Comments
 (0)