英文:
"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-proto
和x-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表单提交被禁止"。有没有其他我可以尝试的想法?
如果有人想查看或运行代码:
- https://gitlab.com/cedricvanrompay/mazette/-/commit/bfa59261b8e5e5c95ac0bec37524a878cd815e91
docker-compose up --build
以启动Nginxcd web-app; npm run dev
以运行SvelteKit应用程序(可能需要首先运行npm install
)- 在Mac上,由于docker主机网络模式在Mac上不起作用,您将不得不撤消此提交:https://gitlab.com/cedricvanrompay/mazette/-/commit/fee6fcd753b2844de307feb8acefd2898bb6efcd
英文:
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:
- https://gitlab.com/cedricvanrompay/mazette/-/commit/bfa59261b8e5e5c95ac0bec37524a878cd815e91
docker-compose up --build
to launch Nginxcd web-app; npm run dev
to run the SvelteKit app (may require anpm install
first)- on Mac you will have to revert this commit due to docker host network mode not working on Mac: https://gitlab.com/cedricvanrompay/mazette/-/commit/fee6fcd753b2844de307feb8acefd2898bb6efcd
答案1
得分: 6
这个问题出现是因为我处于开发模式 (npm run dev
),而在 https://kit.svelte.dev/docs/adapter-node#environment-variables 中记录的 PROTOCOL_HEADER
、HOST_HEADER
和 ORIGIN
环境变量适用于 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_HEADER
、HOST_HEADER
和 ORIGIN
环境变量,但这些只被 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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论