这是一个混合 MVC/webforms asp.net 应用程序,使用框架 4.8、表单身份验证和成员资格。我需要实现安全 cookie。该网站位于 Coyote 负载平衡器后面,我无法访问(并且永远不会访问)。
我在 web.config 中添加了以下内容:
- 身份验证表单标签中的 requireSSL="true"
- httpCookies 标签中的 requireSSL="true"
- roleManager 标记中的 cookiedRequireSSL="true"
虽然这适用于单个站点,但当我在负载均衡器后面有多个站点时它会失败,原因如下:https://www.jamescrowley.net/2014/03/07/ssl-termination-and-secure-cookiesrequiressl-with-asp-net-forms-authentication/
这是我尝试在负载均衡器后面执行安全 cookie 时收到的错误消息:
System.Web.HttpException (0x80004005): 应用程序配置为发出安全 cookie。这些 cookie 要求浏览器通过 SSL(https 协议)发出请求。但是,当前请求未通过 SSL。在 System.Web.Security.FormsAuthentication.SetAuthCookie(String userName, Boolean createPersistentCookie, String strCookiePath) 在 System.Web.UI.WebControls.Login.AttemptLogin() 在 System.Web.UI.WebControls.Login.OnBubbleEvent(Object source, EventArgs e) 在 System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) 在 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
我尝试了上述链接中 Crowley 先生描述的修复方法,使用 IIS urlRewrite 模块。这实际上将 HTTPS 服务器变量设置为“on”。与 Crowley 先生的修复方法不同,我的规则没有条件,只是将每个请求都设置为“on”HTTPS:
<rules>
<rule name="HTTPS_AlwaysOn" patternSyntax="Wildcard">
<match url="*" />
<serverVariables>
<set name="HTTPS" value="on" />
</serverVariables>
<action type="None" />
</rule>
</rules>
</rewrite>
但是,这个修复只起到了一半的作用。没有运行时错误。从跟踪中我可以看到用户成功登录并且表单身份验证 cookie 被植入,但是当用户被重定向到应用程序的主页时,安全连接丢失(HTTPS 服务器变量不再是“on”;方案是“http”而不是“https”)并且用户被重定向回登录页面。
我假设这个 http 重定向以某种方式来自负载平衡器采取的某些操作,但我不明白为什么 IIS 重写模块缺少它。
因此我尝试将其添加到我的 Global.ascx.cs。这有效:
protected void Application_BeginRequest(object sender, EventArgs e)
{
Request.ServerVariables["HTTPS"] = "on";
}
我可以登录并保留我的身份验证 cookie。太棒了!
如上所述,该网站位于负载平衡器后面。此负载平衡器不允许任何 http 请求(仅允许 https)。如果我尝试使用 http 访问我的网站,浏览器会停滞很长时间,然后显示“无法访问此网站”消息。这很好。
我有两个问题:
第一,我的修复是否会引起我需要了解的问题?我想不出任何问题,但我有一种不安的感觉,好像房间里有难闻的味道。
二、为什么我的 IIS 重写规则无法阻止 http 重定向?asp.net 是否在 IIS 之外进行重定向?
答案1
我建议使用更新的解决方案来解决这个问题。在 Startup.cs 中,配置 ForwardedHeaders 中间件以使用负载均衡器提供的 X-Forwarded-Proto 标头:
app.UseForwardedHeaders(new ForwardedHeadersOptions {
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedHost | ForwardedHeaders.XForwardedProto
});
除了您提到的代码异味之外,我认为您当前的解决方案没有任何问题。