Go反向代理干扰.NET [Authorize]特性致401错误问题排查
问题背景
当前部署一套前端采用Vue.js框架的ASP.NET MVC Web应用,访问控制层使用Go语言编写的零信任反向代理pritunl-zero。
本地运行环境下开启匿名认证时应用可正常工作,但部署上线经该反向代理防护时,所有需要鉴权的接口调用都会被IIS10 Web服务器返回401.0状态码拒绝访问;将反向代理从基础设施中移除后,应用可立即恢复正常运行。
相关代码与日志
受[Authorize]特性保护的接口示例
[Authorize] [HttpPut, Route("api/ping"), ResponseType(typeof(WorkflowDto))] public IHttpActionResult PingWorkflow(WorkflowCommentDto commentDto)
前端控制台报错日志
createError.js:16
Uncaught (in promise) Error: Request failed with status code 401
at e.exports (createError.js:16:15)
at e.exports (settle.js:17:12)
at XMLHttpRequest.O (xhr.js:66:7)
触发401响应的HTTP请求头
GET /api/workflow/ping HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate, br Accept-Language: de,de-DE;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,cy;q=0.5 Cache-Control: no-cache Connection: keep-alive Cookie: pritunl-zero=MTY1NzY5OTc0NHxEdEU... Host: workflow.host.de Pragma: no-cache Referer: https://workflow.host.de/ Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-origin User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.49 sec-ch-ua: ".Not/A)Brand";v="99", "Microsoft Edge";v="103", "Chromium";v="103" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "Windows" token: 8cf78dcd-3b17-4481-8be3-10821519c23c
可正常响应的HTTP请求头
:authority: wf.host.de :method: GET :path: /api/workflow/Ping :scheme: https accept: */* accept-encoding: gzip, deflate, br accept-language: de,de-DE;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,cy;q=0.5 cache-control: no-cache cookie: pritunl-zero=MTY1Nzc3NjkwOHxZTVRUWUF5d0s0c180aTB...; pritunl-zero=MTY1NzgwMTE3MnxlWk9vYkZ2ZGQ0TTdVZmZKODdWb19SRzFSV... pragma: no-cache referer: https://wf.host.de/ sec-ch-ua: ".Not/A)Brand";v="99", "Microsoft Edge";v="103", "Chromium";v="103" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "Windows" sec-fetch-dest: empty sec-fetch-mode: cors sec-fetch-site: same-origin token: 8cf78dcd-3b17-4481-8be3-10821519c23c user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.49
服务端正常返回的响应头
cache-control: no-cache content-length: 214 content-type: application/json; charset=utf-8 date: Thu, 14 Jul 2022 12:25:09 GMT expires: -1 pragma: no-cache server: Microsoft-IIS/10.0 strict-transport-security: max-age=0; includeSubDomains; preload x-aspnet-version: 4.0.30319 x-powered-by: ASP.NET
服务端返回401状态码的响应头
HTTP/1.1 401 Unauthorized Cache-Control: no-cache Content-Length: 61 Content-Type: application/json; charset=utf-8 Date: Wed, 13 Jul 2022 08:09:12 GMT Expires: -1 Pragma: no-cache Server: Microsoft-IIS/10.0 X-Aspnet-Version: 4.0.30319 X-Powered-By: ASP.NET
已尝试的排查操作
- 新建IIS站点与应用池,完成全新部署
- 调整web.config中多项与匿名认证相关的配置
- 尝试多种应用程序池配置方案
- 将pritunl-zero升级至最新版本
修复思路
对比两组请求的核心差异,按以下优先级逐一排查即可解决问题:
- 排查路径大小写匹配问题:失败请求路径为
/api/workflow/ping,成功请求路径为/api/workflow/Ping。虽然ASP.NET Web API路由默认大小写不敏感,但如果反向代理配置了路径重写、大小写敏感的路由匹配规则,可能将请求转发到错误的后端路径,此时IIS的认证模块会先于应用代码拦截请求,直接返回401。先在反向代理中关闭路径大小写转换规则,统一使用与后端路由定义一致的路径格式测试。 - 排查Host头透传问题:失败请求为HTTP/1.1协议携带标准
Host头,成功请求为HTTP/2协议携带:authority伪头。pritunl-zero默认会将Host头重写为上游后端的内网地址,不会保留原始请求的域名Host值,ASP.NET的身份认证、防伪校验逻辑会校验请求Host与站点绑定域名是否匹配,校验失败直接返回401。在上游服务配置中开启「保留原始Host头」选项,禁止反向代理重写Host字段。 - 排查IIS认证模块冲突:如果IIS站点同时开启了Windows认证、表单认证和匿名认证,反向代理转发请求时不会携带对应认证协议要求的握手凭证,IIS层会先于应用的[Authorize]逻辑拦截请求返回401。直接进入IIS站点的认证设置面板,仅保留匿名认证为启用状态,关闭其余所有认证方式,让应用自身的鉴权逻辑完全接管权限校验。
- 排查Cookie透传问题:失败请求仅携带1个pritunl-zero的Cookie,成功请求携带2个同名的pritunl-zero Cookie。检查反向代理是否配置了Cookie裁剪、Cookie重写规则,错误丢弃了客户端携带的部分身份凭证,导致应用拿到的凭证不完整校验失败。直接关闭反向代理上所有和Cookie修改相关的规则,全量透传客户端原始Cookie头即可。
内容的提问来源于stack exchange,提问作者mycaravam
相关产品推荐
相关产品推荐

