【问题标题】:Remote Require HTTPS MVC 5远程需要 HTTPS MVC 5
【发布时间】:2014-11-11 07:27:39
【问题描述】:

我有以下属性来确保远程站点页面以 https 模式打开。

public class RemoteRequireHttpsAttribute : RequireHttpsAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentException("Filter Context");
            }

            if (filterContext != null && filterContext.HttpContext != null)
            {
                if (filterContext.HttpContext.Request.IsLocal)
                {
                    return;
                }
                else
                {
                    string val = ConfigurationManager.AppSettings["RequireSSL"].Trim();
                    bool requireSsl = bool.Parse(val);
                    if (!requireSsl)
                    {
                        return;
                    }
                }
            }

            base.OnAuthorization(filterContext);
        }
    }

本地开发现在可以正常工作,因为我不希望它以 https 模式打开。

开发站点以 https 模式打开页面 - 此处没有问题(单节点)。

我当前设置的生产(负载平衡 - 2 个节点)站点出现以下错误。请注意,开发和生产站点具有相同的设置和 web.config

页面未正确重定向

Firefox 检测到服务器正在以永远不会完成的方式重定向对该地址的请求。

此问题有时可能是由禁用或拒绝接受 cookie 引起的。

开发网站网址就像 http://dev.datalab.something.org

产品网站网址就像 http://datalab.something.org

这是电话

[RemoteRequireHttps]
public ActionResult Index(string returnUrl, string error)

我在这里错过了什么?

更新 1: 我的管理员已确认 SSL 终止已在 lad balancer 级别设置。我查看了 iis 站点设置,但没有看到 https 绑定。我只看到http绑定。他是否也需要设置 https 绑定?

更新 2:@AlexeiLevenkov 为我指出了正确的方向,this post 拥有我使用的代码并且它正在运行。将代码移动到单独的答案中。

【问题讨论】:

  • 您似乎没有将用户重定向回 HTTPS 连接,您只是拒绝访问?
  • 您有某种无限循环,您的页面被来回重定向。使用浏览器的调试工具来确定它在哪些页面之间跳转,然后检查这些页面的配置/代码。
  • RemoteRequireHttps 继承自 RequireHttpsAttribute。这会进行重定向。 @mason 我在开发和产品站点上都有相同的代码。开发站点以 https 模式显示页面就好了。没有重定向问题。此操作仅应用一个属性。
  • 查看 IIS 日志中的传入请求...我很有可能所有这些都是 HTTP,因为您的服务器之前的某处有 SSL termination
  • @learning ......这里的大部分答案 - “那个产品是负载平衡的。”当您检查负载平衡器是否配置为执行 SSL 终止时,其余的就会清楚了。改为阅读"x-forwarded-proto" 标题,您的生活会很美好。

标签: c# asp.net-mvc-5


【解决方案1】:

您的站点位于执行 SSL 终止的负载平衡器后面 - 因此,无论用户看到什么,到您站点的所有传入流量都是 HTTP。这会导致您的代码始终尝试重定向到 HTTPS 版本,从而导致无限循环。

修复选项:

  • 通常执行 SSL 终止的负载平衡器将通过自定义标头转发原始 IP/协议。 x-forwarded-protox-forwarded-for 是用于此目的的常用方法。如果使用了这些标头或需要一些额外的配置,您可能需要与网络管理员核实
  • 您也可以关闭 SSL 终止,但它会给您的服务器带来额外的负载。
  • 还可以配置负载平衡器,以使用与传入请求相同的协议与服务器通信。

如何调查此类问题:

  • 查看 http 调试器(如 Fiddler),看看您是否在循环中收到 30 次重定向请求。如果没有重定向 - 可能代码是错误的。
  • 如果您看到重复的重定向,这可能意味着站点没有看到实际的请求信息 - 可能是协议、路径 cookie 丢失。
  • 要继续调查,请查看用户和服务器之间的设备(CDN、代理、负载平衡器...) - 每个设备都有很好的机会释放一些日期或转换协议。

【讨论】:

    【解决方案2】:

    并不是说我反对编写好的自定义属性,也许在 web.config 中执行重定向并使用 web.config 可用的转换将下面的启用值从 false 更改为 true 以用于生产部署?

    <rewrite>
      <rules>
        <rule name="SSL_ENABLED" enabled="false" stopProcessing="true">
          <match url="(.*)" />
          <conditions>
            <add input="{HTTPS}" pattern="^OFF$" />
          </conditions>
          <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" appendQueryString="true" redirectType="Permanent" />
        </rule>
      </rules>
    </rewrite>
    

    【讨论】:

    • OP 已经获得重定向,它只是没有结束......所以 Web.Config 更改可能会表现得完全相同(也更简单一些)。
    • 我在我们的生产应用程序中使用此代码,当我们在本地工作时,我们只需将启用的值设置为 false,如上例所示,当我们部署到生产服务器时,我们只需更改值为真,然后部署。我们还在 IE、Firefox、Chrome 以及最流行的移动浏览器上对此进行了测试,它对我们来说就像一个魅力。
    • 这不是要把所有页面都变成https吗?
    • 是的——但如果你有 SSL 证书,就没有理由做非 https
    • 对于我们的要求是这种情况,但是如果您只想保护特定页面,则可以编辑匹配 url。我发现保护所有页面没有害处,客户喜欢在浏览器中看到安全图标 :)
    【解决方案3】:

    如@AlexeiLevenkov 所述,将修复程序移至单独的答案中。

    public class RemoteRequireHttpsAttribute : RequireHttpsAttribute
        {
            public override void OnAuthorization(AuthorizationContext filterContext)
            {
                if (filterContext == null)
                {
                    throw new ArgumentException("Filter Context");
                }
    
                if(filterContext.HttpContext != null)
                {
                    if (filterContext.HttpContext.Request.IsSecureConnection)
                    {
                        return;
                    }
    
                    var currentUrl = filterContext.HttpContext.Request.Url;
                    if (currentUrl.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.CurrentCultureIgnoreCase))
                    {
                        return;
                    }
    
                    if (string.Equals(filterContext.HttpContext.Request.Headers["X-Forwarded-Proto"], "https", StringComparison.InvariantCultureIgnoreCase))
                    {
                        return;
                    }
    
                    if (filterContext.HttpContext.Request.IsLocal)
                    {
                        return;
                    }
    
                    var val = ConfigurationManager.AppSettings["RequireSSL"].Trim();
                    var requireSsl = bool.Parse(val);
                    if (!requireSsl)
                    {
                        return;
                    }
                }
    
                base.OnAuthorization(filterContext);
            }
        }
    

    我也更新了 ExitHttps 属性。这有类似的问题...

    public class ExitHttpsAttribute : FilterAttribute, IAuthorizationFilter
        {
            public void OnAuthorization(AuthorizationContext filterContext)
            {
                if (filterContext == null)
                {
                    throw new ArgumentException("Filter Context");
                }
    
                if (filterContext.HttpContext == null)
                {
                    return;
                }
    
                var isSecure = filterContext.HttpContext.Request.IsSecureConnection;
    
                var currentUrl = filterContext.HttpContext.Request.Url;
                if (!isSecure && currentUrl.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.CurrentCultureIgnoreCase))
                {
                    isSecure = true;
                }
    
                if (!isSecure && string.Equals(filterContext.HttpContext.Request.Headers["X-Forwarded-Proto"], "https", StringComparison.InvariantCultureIgnoreCase))
                {
                    isSecure = true;
                }
    
                if (isSecure)
                {
                    //in these cases keep https
                    // abort if a [RequireHttps] attribute is applied to controller or action
                    if (filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof (RequireHttpsAttribute), true).Length > 0)
                    {
                        isSecure = false;
                    }
    
                    if (isSecure && filterContext.ActionDescriptor.GetCustomAttributes(typeof (RequireHttpsAttribute), true).Length > 0)
                    {
                        isSecure = false;
                    }
    
                    // abort if a [RetainHttps] attribute is applied to controller or action
                    if (isSecure && filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof (RetainHttpsAttribute), true).Length > 0)
                    {
                        isSecure = false;
                    }
    
                    if (isSecure && filterContext.ActionDescriptor.GetCustomAttributes(typeof (RetainHttpsAttribute), true).Length > 0)
                    {
                        isSecure = false;
                    }
    
                    // abort if it's not a GET request - we don't want to be redirecting on a form post
                    if (isSecure && !String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
                    {
                        isSecure = false;
                    }
                }
    
                if (!isSecure)
                {
                    return;
                }
    
                // redirect to HTTP
                var url = "http://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl;
                filterContext.Result = new RedirectResult(url);
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-11
      • 1970-01-01
      • 2015-04-22
      • 1970-01-01
      • 2013-12-28
      • 1970-01-01
      • 2015-11-29
      • 1970-01-01
      相关资源
      最近更新 更多