nibtime / next-safe-middleware

Strict CSP (Content-Security-Policy) for Next.js hybrid apps https://web.dev/strict-csp/
https://next-safe-middleware.vercel.app
MIT License
79 stars 20 forks source link

Middleware error #87

Open pinktonio opened 1 year ago

pinktonio commented 1 year ago

When following the Getting Started guide on a fresh next@12.3.4 version I always get the following error on a local build: Error [TypeError]: fetch failed. It works fine on the development server but once I build locally every page throws a 500 error. This seems related to the middleware implementation as it works fine without it.

jcarenza commented 1 year ago

I'm getting a similar error on next@13.1.2 (running prod build locally):

Error [TypeError]: fetch failed
    at Object.processResponse (evalmachine.<anonymous>:7941:27)
    at <unknown> (evalmachine.<anonymous>:8271:42)
    at <unknown> (node:internal/process/task_queues:140:7)
    at AsyncResource.runInAsyncScope (node:async_hooks:202:9)
    at AsyncResource.runMicrotask (node:internal/process/task_queues:137:8)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

Followed the basic setup examples from the doc site, but it seems related to the use of strictDynamic(). When I remove it, I no longer get the error.

Any suggestions would be greatly appreciated!

demetris-manikas commented 1 year ago

@jcarenza Same here for next@12.3.4

sebkasanzew commented 1 year ago

After some trial and error I found out that this issue got resolved for me after downgrading to Node v16.19.1. I had the fetch failed error with Node v18.15.0, next@13.2.3 and @next-safe/middleware@0.10.0.

LuizPelegrini commented 1 year ago

@nibtime Same it's happening to me, downgrading node is not an option in my case :/

@next-safe/middleware@0.10.0 next@13.2.4 node v18.13.0

Any suggestions on why this is happening and possible solutions?

Jokinen commented 1 year ago

TL;DR Newer node version will attempt to connect to the IPv6 address when it is available. By default next dev will listen to ::1 (localhost in IPv6), but next start does not. The internal logic of this package ends up calling localhost when it is run locally with next start which will fail because those requests won't be received by the nextjs server.

⚠️ The failed fetch should contain a cause field that has more details about the failure. It could be worth finding out whether this field could be printed. It contains details that could have made debugging this issue easier.

Also getting this error.

"next": "^13.1.6",
"@next-safe/middleware": "^0.10.0",

node@v18.9.1

I searched around for this particular error message as it gives the impression of being a platform error. I found a few sources of which most end up mentioning this issue: https://github.com/nodejs/undici/issues/1248

In this issue one possible cause is presented that has to do with DNS: https://github.com/nodejs/undici/issues/1248#issuecomment-1214773044

Unlike in older node versions, in newer versions IPv6 address is used first.

This means that in newer node, ::1 is fetched first if it has been configured for localhost. This isn't available with next start by default.

One suggested workaround is to comment out the line ::1 localhost from your hosts file: https://github.com/nodejs/undici/issues/1248#issuecomment-1054467140

On some platforms this will result in localhost only having an IPv4 address which will avoid the issue with the ::1 address. This is an invasive change so it'll likely only be useful for finding out whether this is the issue that is impacting you.

Another suggested option is to use 127.0.0.1 instead of localhost as a hostname in order to force the use of IPv4. However, I was unable to configure next in a way which resulted in this behaviour. Even if I start with -H 127.0.0.1 (with some other app specific configs) this following file will be loaded in the middleware:

http://localhost:3000/_next/static/~csp/csp-manifest.json

(Based on the error message we were able to find out that a fetch fails in fetchCspManifest and to the best of our knowledge it's this url that causes the failure)

Another possible workaround is to configure node >=18 to behave like older node versions, by setting:

import dns from 'node:dns';
dns.setDefaultResultOrder('ipv4first');

https://stackoverflow.com/a/72416352/599991 (found through this comment)

I tested this approach and it seemed like it worked.

A possible underlying detail which explains the inconsistency between the dev and start experience is that next does not listen to IPv6 with start, but it does so with dev.

https://github.com/vercel/next.js/issues/46090

Using next start -H :: to start the local production instance should result in the creation of a listener for the IPv6 address. However, I haven't tested this approach.