ASP.NET Core + Antiforgery + jQuery Ajax POST + Nginx - 400 错误请求
ASP.NET Core + Antiforgery + jQuery Ajax POST + Nginx - 400 Bad Request
该主题有很多类似 的问题,但其中 none 解决了我今天面临的具体问题。
受影响的环境是:
- ASP.NET 核心 3.1 网络应用程序(v3.1.9 运行时)
- Ubuntu 服务器 v20.04 Focal
- Nginx 网络服务器 (v1.18.0) 配置为 Kestrel 的代理通行证
使用 jQuery 发出 Ajax POST 时会出现此问题(其他 JS 框架也会失败),会出现 400 - 由于 Antiforgerytoken 未被正确验证而导致的错误请求.
此问题与缺少防伪令牌无关,因为它已正确添加到 Ajax 调用 header 字段 and/or以适当的方式形成字段:
@inject IAntiforgery antiforgery
@{
var tokenSet = antiforgery.GetAndStoreTokens(Context);
}
[...]
$.ajax({
headers: {
"@tokenSet.HeaderName": "@tokenSet.RequestToken"
},
data: {
"@tokenSet.FormFieldName": "@tokenSet.RequestToken"
},
[...]
});
上述设置防伪令牌的模式被证明工作正常,以至于当直接访问 Kestrel 时调用在开发中甚至在生产中都被接受(如果不涉及 Nginx 则不会出现 400 错误)。
事实上,这个问题似乎与这个特定的 Nginx 问题有关:
在第一个线程中还有一个解决方法,它依赖于以下 Nginx 设置:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
不幸的是,建议的解决方法对我不起作用。
有什么线索吗?
更新:我最终设法解决了这个问题。问题与我在 header 名称和 cookie 名称中的一个点有关:
services.AddAntiforgery(options => {
options.Cookie.Name = "X-CSRF-TOKEN-MyApp.Namespace";
options.HeaderName = "X-CSRF-TOKEN-MyApp.Namespace";
});
足以摧毁一切。感谢 Mike Bogolepov 的回答,问题不是他建议的下划线,但该建议仍然足以为我指明正确的方向:谢谢!
根据我遇到同样问题的经验,我想假设:
首先,您的应用程序是否使用 Aspnet Core DataProtection? https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/introduction?view=aspnetcore-3.1。错误的验证可能与它有关。
其次,我们有一个带下划线的 header 并且 nginx 将其从请求切到 Kestrel。 http://nginx.org/en/docs/http/ngx_http_core_module.html#underscores_in_headers. If you use k8s with ingress in your production: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#enable-underscores-in-headers.
您是否覆盖 header 名称或在 Startup.cs(AddAntiforgery()
方法)中将其置空?
该主题有很多类似 的问题,但其中 none 解决了我今天面临的具体问题。
受影响的环境是:
- ASP.NET 核心 3.1 网络应用程序(v3.1.9 运行时)
- Ubuntu 服务器 v20.04 Focal
- Nginx 网络服务器 (v1.18.0) 配置为 Kestrel 的代理通行证
使用 jQuery 发出 Ajax POST 时会出现此问题(其他 JS 框架也会失败),会出现 400 - 由于 Antiforgerytoken 未被正确验证而导致的错误请求.
此问题与缺少防伪令牌无关,因为它已正确添加到 Ajax 调用 header 字段 and/or以适当的方式形成字段:
@inject IAntiforgery antiforgery
@{
var tokenSet = antiforgery.GetAndStoreTokens(Context);
}
[...]
$.ajax({
headers: {
"@tokenSet.HeaderName": "@tokenSet.RequestToken"
},
data: {
"@tokenSet.FormFieldName": "@tokenSet.RequestToken"
},
[...]
});
上述设置防伪令牌的模式被证明工作正常,以至于当直接访问 Kestrel 时调用在开发中甚至在生产中都被接受(如果不涉及 Nginx 则不会出现 400 错误)。
事实上,这个问题似乎与这个特定的 Nginx 问题有关:
在第一个线程中还有一个解决方法,它依赖于以下 Nginx 设置:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
不幸的是,建议的解决方法对我不起作用。
有什么线索吗?
更新:我最终设法解决了这个问题。问题与我在 header 名称和 cookie 名称中的一个点有关:
services.AddAntiforgery(options => {
options.Cookie.Name = "X-CSRF-TOKEN-MyApp.Namespace";
options.HeaderName = "X-CSRF-TOKEN-MyApp.Namespace";
});
足以摧毁一切。感谢 Mike Bogolepov 的回答,问题不是他建议的下划线,但该建议仍然足以为我指明正确的方向:谢谢!
根据我遇到同样问题的经验,我想假设:
首先,您的应用程序是否使用 Aspnet Core DataProtection? https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/introduction?view=aspnetcore-3.1。错误的验证可能与它有关。
其次,我们有一个带下划线的 header 并且 nginx 将其从请求切到 Kestrel。 http://nginx.org/en/docs/http/ngx_http_core_module.html#underscores_in_headers. If you use k8s with ingress in your production: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#enable-underscores-in-headers.
您是否覆盖 header 名称或在 Startup.cs(AddAntiforgery()
方法)中将其置空?