"Cross-site POST form submissions are forbidden" error from SvelteKit in dev mode while origin and x-forwarded are used

huangapple go评论112阅读模式
英文:

"Cross-site POST form submissions are forbidden" error from SvelteKit in dev mode while origin and x-forwarded are used

问题

我有一个在本地开发时运行在http://localhost:5173的SvelteKit应用程序,前面有一个运行在http://localhost:8057的Nginx,它提供一些静态文件并代理必须由SvelteKit处理的请求。

我在http://localhost:8057/login上有一个登录表单,当我提交它时,我得到一个网页,上面只有"跨站POST表单提交被禁止"。

我尝试使用ORIGIN环境变量,如https://stackoverflow.com/q/73790956/3025740和https://kit.svelte.dev/docs/adapter-node#environment-variables所示。这是我的.env文件:

ORIGIN=http://localhost:8057

如果我在服务器端从import { env } from '$env/dynamic/private';中记录env,我可以看到这个环境变量。但我仍然得到"跨站POST表单提交被禁止"。

我还尝试在启动SvelteKit时传递环境变量(使用ORIGIN=http://localhost:8057 npm run dev),但结果相同。

因为SvelteKit在发送此错误时不会记录太多信息,所以我只能猜测SvelteKit内部发生了什么,但如果在Nginx中添加proxy_set_header Origin http://localhost:5173;,那么它可以工作,因此SvelteKit在这里期望的来源是很清楚的。但我宁愿不这样做,因为这几乎等同于禁用CSRF保护。

然后我尝试使用https://kit.svelte.dev/docs/adapter-node#environment-variables中建议的另一种方法,即使用x-forwarded-protox-forwarded-host,所以现在这是我的.env文件(再次,如果我在我的应用中记录它们,我绝对可以看到这些值):

PROTOCOL_HEADER=x-forwarded-proto
HOST_HEADER=x-forwarded-host
ORIGIN=http://localhost:8057

以及在我的Nginx配置中(替换Origin标头的相同位置将修复一切的地方):

location @sveltekit {
  proxy_pass http://localhost:5173;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto $scheme;
  proxy_set_header X-Forwarded-Host $host;
}

但我仍然得到"跨站POST表单提交被禁止"。有没有其他我可以尝试的想法?

如果有人想查看或运行代码:

英文:

I have a SvelteKit app running at http://localhost:5173 (when doing local development) with a Nginx in front of it running at http://localhost:8057, serving some static files and proxying requests that must be handled by SvelteKit.

I have a login form at http://localhost:8057/login and when I submit it I get a web page with just "Cross-site POST form submissions are forbidden".

I tried using the ORIGIN environment variable as per https://stackoverflow.com/q/73790956/3025740 and https://kit.svelte.dev/docs/adapter-node#environment-variables. Here is my .env file:

ORIGIN=http://localhost:8057

I can see this environment variable in my environment if I log env from import { env } from '$env/dynamic/private'; in the server side. But I still get "Cross-site POST form submissions are forbidden".

I also tried passing the environement variable when starting SvelteKit (with ORIGIN=http://localhost:8057 npm run dev), but same result.

Because SvelteKit does not log much when it sends this error I can just try to guess what's going on inside SvelteKit, but if in Nginx I add proxy_set_header Origin http://localhost:5173; then it works, so it's pretty clear what origin SvelteKit expects here. I'd rather not do this however because it is pretty much equivalent to disabling CSRF protection.

I then tried to use the other method suggested in https://kit.svelte.dev/docs/adapter-node#environment-variables, that is, to use x-forwarded-proto and x-forwarded-host, so now here is my .env file (and again I can definitely see these values if I log them in my app):

PROTOCOL_HEADER=x-forwarded-proto
HOST_HEADER=x-forwarded-host
ORIGIN=http://localhost:8057

and in my Nginx configuration (the same place where replacing the Origin header would fix everything):

location @sveltekit {
  proxy_pass http://localhost:5173;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto $scheme;
  proxy_set_header X-Forwarded-Host $host;
}

And I still get "Cross-site POST form submissions are forbidden". Any idea what else I could try?

In case people want to see or run the code:

答案1

得分: 6

这个问题出现是因为我处于开发模式 (npm run dev),而在 https://kit.svelte.dev/docs/adapter-node#environment-variables 中记录的 PROTOCOL_HEADERHOST_HEADERORIGIN 环境变量适用于 Node 适配器(用于在目标 NodeJS 时运行 npm run build),但不适用于 Vite 开发服务器。

"Cross-site POST form submissions are forbidden" 这条消息来自 packages/kit/src/runtime/server/respond.js,它与 Node 适配器无关,它会运行你所使用的适配器。误导的地方在于,如果你搜索这个错误消息,你只会在与 NodeJS 适配器相关的上下文中找到,比如 https://kit.svelte.dev/docs/adapter-node#environment-variables

在这个上下文中,你所读到的 "解决方案" 是使用 PROTOCOL_HEADERHOST_HEADERORIGIN 环境变量,但这些只被 Node 适配器理解。你可以在 packages/adapter-node/src/handler.js 中看到它们的使用。

当你使用 npm run dev 运行 SvelteKit 应用时,你没有使用 NodeJS 适配器。你使用的是 Vite 开发服务器,它不会读取这些环境变量。你可以在 packages/kit/src/exports/vite/dev/index.js 中看到这个开发服务器是如何设置请求的 "origin" 的。它只使用请求的 "host" 标头,而忽略任何 "x-forwarded-host" 或其他类似的标头。

一个解决方案是在开发模式下,让你的代理设置 "host" HTTP 标头。不要在生产中这样做,但在开发模式下应该是可以的。另一个解决方案是在开发模式下禁用 CSRF 保护。

关于这个问题,SvelteKit 的 GitHub 存储库中已经有一个问题报告:https://github.com/sveltejs/kit/issues/8026

英文:

The problem was coming from that I was in dev mode (npm run dev) and that the PROTOCOL_HEADER, HOST_HEADER and ORIGIN environment variables documented in https://kit.svelte.dev/docs/adapter-node#environment-variables work for the node adapter (which is used when you do npm run build when targeting NodeJS) but not for the Vite dev server.

The message "Cross-site POST form submissions are forbidden" comes from packages/kit/src/runtime/server/respond.js which is not tied to the node adapter, it runs whatever adapter you're using. What is misleading is that if you search about this error message you'll only read about it in a context that's related to the NodeJS adapter, like https://kit.svelte.dev/docs/adapter-node#environment-variables.

The "solution" you read about in this context is to use the PROTOCOL_HEADER, HOST_HEADER and ORIGIN environment variables, but these are only understood by the node adapter. You can see them being used in packages/adapter-node/src/handler.js.

When you run your SvelteKit app with npm run dev you're not using the NodeJS adapter. You are using the Vite development server, which does not read these environment variables. You can see how this development server sets the "origin" of the request in packages/kit/src/exports/vite/dev/index.js. It only uses the "host" header of the request but ignores any "x-forwarded-host" or other similar headers.

One solution is to make your proxy set the "host" HTTP header. Don't do this in production, but in dev mode this should be OK. Another is to disable CSRF protection in dev mode.

There is already an issue in SvelteKit's GitHub repository about this: https://github.com/sveltejs/kit/issues/8026

huangapple
  • 本文由 发表于 2023年4月11日 05:27:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/75980876.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定