【问题标题】:RequireHttps and routing to https URLRequireHttps 和路由到 https URL
【发布时间】:2013-02-13 15:22:57
【问题描述】:

我在处理登录和安全 https 页面的用户控制器中的大多数操作上都使用 RequireHttps 属性。

在我的 http 主页上,我有一个指向我的登录页面的链接,如下所示(MVC 4 Razor View):-

<a href="@Url.Action("Login", "User")">Login</a>

链接正确地转到带有 https 地址的登录页面。但是,当我查看 IIS 日志时,我看到登录 URL 有两个条目,一个在端口 80 上,一个在端口 443 上。

这是我应该关注的问题吗?

我知道我的@Url.Action 我可以强制使用 https 模式,但不确定这是否是最好的方法。另外,这会删除端口,这在 VS 2012 中使用 IIS Express 时很烦人。然后我必须进一步扩展 @Url.Action 以包含主机名:端口。

所以我只是检查 (a) 这是否应该是一个问题,以及 (b) 是否有任何其他方法可以将 URL 强制为 https。

【问题讨论】:

    标签: asp.net-mvc-4 requirehttps


    【解决方案1】:

    大多数教程都同意,通过使用混合模式站点(HTTP 和 HTTPS),您违背了 SSL 的目的(某些路径需要 SSL,然后切换回非 SSL 连接)。切换到 HTTPS 后,建议您强制用户继续使用 HTTPS 进行所有操作,至少在他们注销之前。我有一个使用 HTTPS 的站点,一旦您访问该站点,我只需使用 URL 重写规则将用户切换到 HTTPS,并且只允许使用 HTTPS。

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

    完成此操作后,还建议您将身份验证 cookie 也设置为需要 HTTPS。对于 Forms 身份验证,这就像在 web.config 中设置以下内容一样简单。

    <authentication>
        <forms requireSSL="true" />
    </authentication>
    

    我还建议查看一些可以设置以帮助浏览器正确处理站点的标头,例如使用 Strict-Transport-Security 来表示该站点需要 SSL。请记住,虽然标头是您可以采取的一种很好的补充措施,但最终它们留给浏览器执行,不应完全依赖。

    我推荐这些步骤,因为我没有遇到您描述的症状,并希望它们能帮助解决您在日志中注意到的问题。

    修正:哦,我也忘了提一下,HTTPS 比普通的旧 HTTP 建立连接更密集一些。在宏伟的计划中并不多,但它仍然是一些东西。我建议您使用HTTP Keep Alive 以减少一些开销。

    更新:通过 SSL 进行通信并不意味着您已通过身份验证。这只是意味着您正在通过安全/加密连接进行交谈。

    以您的亚马逊为例。如果您访问该站点,您会喜欢通过 HTTP 获得正常连接。您没有登录,您只是在浏览该网站。如果你愿意,你可以切换到 HTTPS,你仍然会得到相同的站点,但你还没有登录。现在,如果您尝试登录,您将被重定向,以便您通过 HTTPS 绰号所指出的 SSL(如果您还没有)进行交谈。即使在您实际登录后,您仍将通过 SSL 进行通信。 即使您尝试通过从 URL 的协议部分删除 S 来在登录时手动切换为不使用 SSL,它仍然会让您重新使用 HTTPS。这是正确的做法。 一般建议您在验证后不要返回未加密的会话。这通常是为了避免会话劫持,因为您的身份验证 cookie 永远不会通过纯 HTTP 发送。确保您在外部资源上拥有的资源位于您信任的网站上。 HTTP 连接中的外部资源访问也应该通过 SSL 连接。同样,仅仅因为您通过 SSL 进行通信并不意味着您已登录到这些来源。因为我的应用程序是通过 SSL 100% 访问的,但我在网站上也集成了谷歌分析和谷歌地图(显然两者都在我的域之外)。我只是确保我通过 SSL 与 Google 交谈。我不必真正登录谷歌就可以使用这些东西。您的外部图像也是如此。只需确保用于引用这些外部图像的 URL 是使用 HTTPS 名字对象定义的,以便它使用 SSL。

    更新:您在日志中获得两次点击的原因是因为您的登录链接是通过 HTTP 请求的,需要 HTTPS 属性点击首先意识到您没有使用SSL 并使用 HTTPS 协议将您重定向回自身。如果您更新 ActionLink URL,您可以解决这个问题,但您知道它会变得丑陋。

    Url.Action("Login", "User", null, "https", Request.Url.Host)
    

    【讨论】:

    • 感谢您的建议。这将是一个后续的单独问题,但我想 2 个站点摆脱了我最初的问题。但是:- (1) 像亚马逊这样的网站会发生什么?当您登录但在首页它知道您是谁 - 我喜欢这个功能,特别是因为我们的网站允许您选择您想要预订的项目,登录将其添加到您的购物篮,浏览网站以获取另一个要预订的项目,添加一个等。(2)我们的网站在不同的地方托管了图像。必须保持登录到 https 会给用户留下不安全的消息 - 有什么解决方案吗?
    • 我更新了我的答案,为您的问题提供了更多信息(没有足够的空间在评论中这样做)
    • 谢谢。 2 个问题 (1) 您说“即使在您实际登录后,您仍将通过 SSL 进行通信”。在亚马逊示例中,我登录(URL 为 https),搜索 Books,URL 变回 http,但顶部还显示“Hello cw_dev”。除非我误解了这个问题,否则这与您所说的相反吗? (2) 假设我的网站托管在域 A,我的图像作为域 B。域 B 没有 SSL 证书。你是说如果我尝试使用 HTTPS url 访问图像,它应该可以工作吗?我确定我之前尝试过,但没有。
    • 你说得对,我已经纠正了(在发布我的更新之前我没有尝试在登录后搜索)。尽管我觉得有趣的是,他们让您在通过身份验证后返回到不安全的会话中……通常由于会话劫持而对此不赞成。我并不是说他们容易受到这种影响,这通常是通过 SSL 登录后不返回 HTTP 的原因。不,您是正确的,使用 SSL 需要有效的 SSL 证书。在我的例子中,谷歌通过 SSL 以及普通的旧 HTTP 提供他们的服务。
    • 我们的问题通常是这样的......我们将我们的网站出售给在他们自己的 IIS 上托管它的客户。他们的生产线速度通常不是超级快。因此,为了减少服务器负载,图像托管在其他地方的通用 FTP 上。这真的很好。这给我们留下了强制整个站点进入 Https 的问题,因为站点的主要部分访问这些图像。不确定这里的最佳前进方式。是否可以使用加密欢迎消息仅将他​​们的姓名存储在单独的 cookie 中,这会被认为是错误的吗?
    【解决方案2】:

    将此添加到您的 global.ascx

    protected void Application_BeginRequest()
            {
                if (!Context.Request.IsSecureConnection)
                    Response.Redirect(Context.Request.Url.ToString().Replace
    
    ("http:", "https:"));
            }
    

    这将导致所有请求都转换为https而不是http

    【讨论】:

      【解决方案3】:

      我为 Url.Action 编写了一个扩展,它根据属性修饰生成正确的协议。我让你检查

      public static class Extensions
      {
          public static string SecuredAction(this UrlHelper helper, string action, string controller)
          {
              bool requireSSL = false;
              var route = System.Web.Routing.RouteTable.Routes.Select(r => r as System.Web.Routing.Route) .Where(r =>
                  r != null && r.Defaults != null && r.Defaults["controller"] != null && r.Defaults["controller"].ToString().Equals(controller, StringComparison.InvariantCultureIgnoreCase)
                  && r.Defaults["action"] != null && r.Defaults["action"].ToString().Equals(action, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
      
              if(route == null)
                  return helper.Action(action, controller);
      
              //Get the method and check if requiere ssl
              MemberInfo method = route.DataTokens["TargetActionMethod"] as MemberInfo;
              requireSSL = method.CustomAttributes.Any(a => a.AttributeType == typeof(RequireHttps)) || method.DeclaringType.CustomAttributes.Any(a => a.AttributeType == typeof(RequireHttps));
      
              //Return the correct protocol
              if(helper.RequestContext.HttpContext.Request.IsSecureConnection && !requireSSL)
                  return helper.Action(action, controller, null, "http");
      
              if (!helper.RequestContext.HttpContext.Request.IsSecureConnection && requireSSL)
                  return helper.Action(action, controller, null, "https");
      
              return helper.Action(action, controller);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-11-06
        • 2019-12-06
        • 2013-03-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-17
        • 2019-12-25
        相关资源
        最近更新 更多