【问题标题】:Best way in asp.net to force https for an entire site?在 asp.net 中强制整个站点使用 https 的最佳方法?
【发布时间】:2010-09-08 00:09:22
【问题描述】:

大约 6 个月前,我推出了一个网站,其中每个请求都需要通过 https。当时我能找到确保对页面的每个请求都通过 https 的唯一方法是在页面加载事件中检查它。如果请求不是通过 http 我会 response.redirect("https://example.com")

有没有更好的方法——最好是 web.config 中的一些设置?

【问题讨论】:

标签: c# asp.net vb.net webforms https


【解决方案1】:

请使用HSTS(HTTP 严格传输安全)

来自http://www.hanselman.com/blog/HowToEnableHTTPStrictTransportSecurityHSTSInIIS7.aspx

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="HTTP to HTTPS redirect" stopProcessing="true">
                    <match url="(.*)" />
                    <conditions>
                        <add input="{HTTPS}" pattern="off" ignoreCase="true" />
                    </conditions>
                    <action type="Redirect" url="https://{HTTP_HOST}/{R:1}"
                        redirectType="Permanent" />
                </rule>
            </rules>
            <outboundRules>
                <rule name="Add Strict-Transport-Security when HTTPS" enabled="true">
                    <match serverVariable="RESPONSE_Strict_Transport_Security"
                        pattern=".*" />
                    <conditions>
                        <add input="{HTTPS}" pattern="on" ignoreCase="true" />
                    </conditions>
                    <action type="Rewrite" value="max-age=31536000" />
                </rule>
            </outboundRules>
        </rewrite>
    </system.webServer>
</configuration>

原答案(2015 年 12 月 4 日替换为上述内容)

基本上

protected void Application_BeginRequest(Object sender, EventArgs e)
{
   if (HttpContext.Current.Request.IsSecureConnection.Equals(false) && HttpContext.Current.Request.IsLocal.Equals(false))
   {
    Response.Redirect("https://" + Request.ServerVariables["HTTP_HOST"]
+   HttpContext.Current.Request.RawUrl);
   }
}

这将进入 global.asax.cs(或 global.asax.vb)

我不知道如何在 web.config 中指定它

【讨论】:

  • 这可行,但对我来说很危险:当我尝试在 VS 2010 中本地运行此代码时,我的起始页从未加载;相反,我刚刚收到“此网页不可用”消息。为了解决这个问题,我添加了第二个条件来测试 url 是否包含字符串“localhost”:如果没有,则强制 https。
  • 这给了我一个重定向循环。在我添加代码之前它运行良好。有什么建议吗?
  • 请注意,这并不提供任何有用的安全性。实际上,它只会保护来自已经安全的用户的连接,而无法保护那些受到攻击的用户(这是因为 MITM 可以完全忽略重定向并将所有内容转发到您的“安全”站点)。恕我直言,重定向用户代理只是感觉良好的巫毒安全,并且有时会提供一种危险的安全错觉。唯一的方法是指示用户代理只请求安全资源,如果不请求则不重定向它们。这就是 HSTS 所做的——请参阅下面的答案。
  • 此答案应被视为“有害”,不应使用。根据上面@tne 的评论。
  • @RosdiKasim 自 2015 年 12 月 4 日编辑以来,这个答案是否仍被视为有害?
【解决方案2】:

在 IIS10(Windows 10 和 Server 2016)中,从版本 1709 开始,有一个新的、更简单的选项可以为网站启用 HSTS。

Microsoft 描述了新方法here 的优点,并提供了许多不同的示例,说明如何以编程方式或直接编辑 ApplicationHost.config 文件(类似于 web.config,但在 IIS 级别运行,而不是单个站点级别)。 ApplicationHost.config 可以在 C:\Windows\System32\inetsrv\config 中找到。

我在这里概述了两个示例方法以避免链接失效。

方法一 - 直接编辑ApplicationHost.config文件 在&lt;site&gt; 标签之间,添加这一行:

<hsts enabled="true" max-age="31536000" includeSubDomains="true" redirectHttpToHttps="true" />

方法 2 - 命令行: 从提升的命令提示符(即在 CMD 上用鼠标右键并以管理员身份运行)执行以下命令。请记住将 Contoso 替换为 IIS 管理器中显示的站点名称。

c:
cd C:\WINDOWS\system32\inetsrv\
appcmd.exe set config -section:system.applicationHost/sites "/[name='Contoso'].hsts.enabled:True" /commit:apphost
appcmd.exe set config -section:system.applicationHost/sites "/[name='Contoso'].hsts.max-age:31536000" /commit:apphost
appcmd.exe set config -section:system.applicationHost/sites "/[name='Contoso'].hsts.includeSubDomains:True" /commit:apphost
appcmd.exe set config -section:system.applicationHost/sites "/[name='Contoso'].hsts.redirectHttpToHttps:True" /commit:apphost

如果您在访问受限的托管环境中,Microsoft 在该文章中提供的其他方法可能是更好的选择。

请记住,IIS10 版本 1709 现在可在 Windows 10 上使用,但对于 Windows Server 2016,它处于不同的发布轨道,不会作为补丁或服务包发布。有关 1709 的详细信息,请参阅here。

【讨论】:

    【解决方案3】:

    我花了一些时间寻找有意义的最佳实践,并发现以下对我来说完美的方法。我希望这可以节省您的时间。

    使用 配置文件(例如 asp.net 网站) https://blogs.msdn.microsoft.com/kaushal/2013/05/22/http-to-https-redirects-on-iis-7-x-and-higher/

    或在您自己的服务器上 https://www.sslshopper.com/iis7-redirect-http-to-https.html

    [简短回答] 只需下面的代码进入

    <system.webServer> 
     <rewrite>
         <rules>
           <rule name="HTTP/S to HTTPS Redirect" enabled="true" 
               stopProcessing="true">
           <match url="(.*)" />
            <conditions logicalGrouping="MatchAny">
            <add input="{SERVER_PORT_SECURE}" pattern="^0$" />
           </conditions>
           <action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" 
            redirectType="Permanent" />
            </rule>
           </rules>
     </rewrite>
    

    【讨论】:

      【解决方案4】:

      如果您使用的是 ASP.NET Core,您可以尝试使用 nuget 包 SaidOut.AspNetCore.HttpsWithStrictTransportSecurity。

      那么你只需要添加

      app.UseHttpsWithHsts(HttpsMode.AllowedRedirectForGet, configureRoutes: routeAction);
      

      这也会将 HTTP StrictTransportSecurity 标头添加到使用 https 方案发出的所有请求中。

      示例代码和文档https://github.com/saidout/saidout-aspnetcore-httpswithstricttransportsecurity#example-code

      【讨论】:

        【解决方案5】:

        对于那些使用 ASP.NET MVC 的人。您可以使用以下两种方式在整个站点上通过 HTTPS 强制 SSL/TLS:

        艰难的道路

        1 - 将 RequireHttpsAttribute 添加到全局过滤器:

        GlobalFilters.Filters.Add(new RequireHttpsAttribute());
        

        2 - 强制防伪令牌使用 SSL/TLS:

        AntiForgeryConfig.RequireSsl = true;
        

        3 - 通过更改 Web.config 文件要求 Cookie 默认需要 HTTPS:

        <system.web>
            <httpCookies httpOnlyCookies="true" requireSSL="true" />
        </system.web>
        

        4 - 使用 NWebSec.Owin NuGet 包并添加以下代码行以启用整个站点的严格传输安全性。不要忘记在下面添加 Preload 指令并将您的网站提交到HSTS Preload site。更多信息here 和here。请注意,如果您不使用 OWIN,可以在 NWebSec 站点上阅读 Web.config 方法。

        // app is your OWIN IAppBuilder app in Startup.cs
        app.UseHsts(options => options.MaxAge(days: 30).Preload());
        

        5 - 使用 NWebSec.Owin NuGet 包并添加以下代码行以启用整个站点的公钥固定 (HPKP)。更多信息here 和here。

        // app is your OWIN IAppBuilder app in Startup.cs
        app.UseHpkp(options => options
            .Sha256Pins(
                "Base64 encoded SHA-256 hash of your first certificate e.g. cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs=",
                "Base64 encoded SHA-256 hash of your second backup certificate e.g. M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE=")
            .MaxAge(days: 30));
        

        6 - 在使用的​​任何 URL 中包含 https 方案。 Content Security Policy (CSP) HTTP 标头和Subresource Integrity (SRI) 在某些浏览器中模仿该方案时效果不佳。最好明确说明 HTTPS。例如

        <script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.4/bootstrap.min.js"></script>
        

        简单的方法

        使用ASP.NET MVC Boilerplate Visual Studio 项目模板生成一个包含所有这些以及更多内置功能的项目。您还可以在GitHub 上查看代码。

        【讨论】:

        • 另外,如果使用&lt;authentication mode="Forms"&gt;,里面必须有&lt;forms requireSSL="true"&gt;
        • @muhammad-rehan-saeed 我正在使用 mvc5 样板,但该站点不会在生产服务器上自动将 http 重定向到 https,它仅在 localhost 上这样做是我缺少的东西吗?
        • 这不是问这个问题的正确论坛。在 GitHub 站点上发布问题。 RequireHttpsAttribute 进行重定向。只要你有它应该没问题。
        • @MuhammadRehanSaeed,喜欢你的回答。但是...如何获取使用 MakeCert 创建的证书的 SHA256 哈希?我只有一个 SHA-1 指纹……你知道吗?
        • @Diana this 链接可以告诉你如何做。
        【解决方案6】:

        这是基于@Troy Hunt 的更完整的答案。将此函数添加到 Global.asax.cs 中的 WebApplication 类中:

            protected void Application_BeginRequest(Object sender, EventArgs e)
            {
                // Allow https pages in debugging
                if (Request.IsLocal)
                {
                    if (Request.Url.Scheme == "http")
                    {
                        int localSslPort = 44362; // Your local IIS port for HTTPS
        
                        var path = "https://" + Request.Url.Host + ":" + localSslPort + Request.Url.PathAndQuery;
        
                        Response.Status = "301 Moved Permanently";
                        Response.AddHeader("Location", path);
                    }
                }
                else
                {
                    switch (Request.Url.Scheme)
                    {
                        case "https":
                            Response.AddHeader("Strict-Transport-Security", "max-age=31536000");
                            break;
                        case "http":
                            var path = "https://" + Request.Url.Host + Request.Url.PathAndQuery;
                            Response.Status = "301 Moved Permanently";
                            Response.AddHeader("Location", path);
                            break;
                    }
                }
            }
        

        (要在本地构建中启用 SSL,请在项目的 Properties Dock 中启用它)

        【讨论】:

          【解决方案7】:

          -> 只需在公共类 HomeController 之上添加 [RequireHttps] :Controller。

          -> 并添加 GlobalFilters.Filters.Add(new RequireHttpsAttribute());在 Global.asax.cs 文件中的 'protected void Application_Start()' 方法中。

          这会强制您的整个应用程序使用 HTTPS。

          【讨论】:

          • 我认为这不适用于使用 WebForms 或使用 WebAPI 构建的任何 API 提供的任何页面。它只会涵盖 MVC 控制器。
          【解决方案8】:

          我将投入两分钱。如果您可以访问 IIS 服务器端,那么您可以通过使用协议绑定来强制使用 HTTPS。例如,您有一个名为 Blah 的网站。在 IIS 中,您将设置两个站点:Blah 和 Blah (Redirect)。对于 Blah,仅配置 HTTPS 绑定(如果需要,请确保通过安全连接强制绑定 FTP)。 Blah (Redirect) 只配置HTTP 绑定。最后,在 Blah (Redirect) 的 HTTP Redirect 部分中,确保将 301 重定向设置为 https://blah.com,并启用确切的目标。确保 IIS 中的每个站点都指向它的 自己的 根文件夹,否则 Web.config 将会搞砸。还要确保在您的 HTTPS 站点上配置了 HSTS,以便浏览器的后续请求始终强制使用 HTTPS,并且不会发生重定向。

          【讨论】:

            【解决方案9】:

            你需要做的是:

            1) 在 web.config 中添加一个密钥,具体取决于生产服务器或阶段服务器,如下所示

            <add key="HttpsServer" value="stage"/>
                         or
            <add key="HttpsServer" value="prod"/>
            

            2) 在 Global.asax 文件中添加以下方法。

            void Application_BeginRequest(Object sender, EventArgs e)
            {
                //if (ConfigurationManager.AppSettings["HttpsServer"].ToString() == "prod")
                if (ConfigurationManager.AppSettings["HttpsServer"].ToString() == "stage")
                {
                    if (!HttpContext.Current.Request.IsSecureConnection)
                    {
                        if (!Request.Url.GetLeftPart(UriPartial.Authority).Contains("www"))
                        {
                            HttpContext.Current.Response.Redirect(
                                Request.Url.GetLeftPart(UriPartial.Authority).Replace("http://", "https://www."), true);
                        }
                        else
                        {
                            HttpContext.Current.Response.Redirect(
                                Request.Url.GetLeftPart(UriPartial.Authority).Replace("http://", "https://"), true);
                        }
                    }
                }
            }
            

            【讨论】:

              【解决方案10】:

              如果您的站点中无法配置 SSL 支持(即应该能够打开/关闭 https) - 您可以在您希望保护的任何控制器/控制器操作上使用 [RequireHttps] 属性。

              【讨论】:

                【解决方案11】:

                对于上面的@Joe,“这给了我一个重定向循环。在我添加代码之前,它运行良好。有什么建议吗?- 2011 年 11 月 8 日,乔 4:13”

                这也发生在我身上,我相信正在发生的事情是有一个负载平衡器终止了 Web 服务器前面的 SSL 请求。所以,我的网站一直认为请求是“http”,即使原来的浏览器请求它是“https”。

                我承认这有点老套,但对我有用的是实现一个“JustRedirected”属性,我可以利用它来确定这个人已经被重定向了一次。因此,我测试了保证重定向的特定条件,如果满足,我在重定向之前设置此属性(存储在会话中的值)。即使第二次满足重定向的http/https条件,我也会绕过重定向逻辑并将“JustRedirected”会话值重置为false。您需要自己的条件测试逻辑,但这里是该属性的简单实现:

                    public bool JustRedirected
                    {
                        get
                        {
                            if (Session[RosadaConst.JUSTREDIRECTED] == null)
                                return false;
                
                            return (bool)Session[RosadaConst.JUSTREDIRECTED];
                        }
                        set
                        {
                            Session[RosadaConst.JUSTREDIRECTED] = value;
                        }
                    }
                

                【讨论】:

                  【解决方案12】:

                  这还取决于平衡器的品牌,对于 web 多路复用器,您需要查找 http 标头 X-WebMux-SSL-termination: true 来确定传入流量是 ssl。详情在这里:http://www.cainetworks.com/support/redirect2ssl.html

                  【讨论】:

                    【解决方案13】:

                    您可以做的另一件事是通过将“Strict-Transport-Security”标头返回给浏览器来使用HSTS。浏览器必须支持这一点(目前主要是 Chrome 和 Firefox 支持),但这意味着一旦设置,浏览器将不会通过 HTTP 向站点发出请求,而是在发出请求之前将它们转换为 HTTPS 请求.尝试结合来自 HTTP 的重定向:

                    protected void Application_BeginRequest(Object sender, EventArgs e)
                    {
                      switch (Request.Url.Scheme)
                      {
                        case "https":
                          Response.AddHeader("Strict-Transport-Security", "max-age=300");
                          break;
                        case "http":
                          var path = "https://" + Request.Url.Host + Request.Url.PathAndQuery;
                          Response.Status = "301 Moved Permanently";
                          Response.AddHeader("Location", path);
                          break;
                      }
                    }
                    

                    不支持 HSTS 的浏览器只会忽略标头,但仍会被 switch 语句捕获并发送到 HTTPS。

                    【讨论】:

                    • 以前从未听说过 HSTS 标头,但看起来很酷。使用这么小的 max-age 值(5 分钟)有什么理由吗?您链接到的维基百科文章建议将其设置为较大的值(6-12 个月)。
                    • +1。查看 Troy 博客上这篇非常广泛的文章,其中详细说明了为什么只使用重定向会降低安全性。提示:除其他外,它可能会让您容易受到 SSL Strip 工具的攻击。 troyhunt.com/2011/11/…
                    • 也值得一试NWebsec,这使得这(以及更多)变得非常容易。
                    • 您需要将开关包装在 if(!Request.IsLocal) 中,这样它就不会中断调试。
                    • 好答案。一个微妙之处 - 对于 Http 标头(“Strict-Transport-Security”),最好使用 NWebSec 之类的库,因为有多个选项集中在一个配置位置,而不是分散在各处。
                    【解决方案14】:

                    IIS7 模块可以让你重定向。

                        <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>
                    

                    【讨论】:

                    • 另外,对于 IIS 7.0,您需要安装 Url Rewrite Module 2.0
                    • 我发现此链接简单且有助于使任何特定页面仅接受 https 请求 - support.microsoft.com/kb/239875
                    【解决方案15】:

                    如果您出于某种原因无法在 IIS 中进行设置,我会创建一个 HTTP 模块来为您执行重定向:

                    using System;
                    using System.Web;
                    
                    namespace HttpsOnly
                    {
                        /// <summary>
                        /// Redirects the Request to HTTPS if it comes in on an insecure channel.
                        /// </summary>
                        public class HttpsOnlyModule : IHttpModule
                        {
                            public void Init(HttpApplication app)
                            {
                                // Note we cannot trust IsSecureConnection when 
                                // in a webfarm, because usually only the load balancer 
                                // will come in on a secure port the request will be then 
                                // internally redirected to local machine on a specified port.
                    
                                // Move this to a config file, if your behind a farm, 
                                // set this to the local port used internally.
                                int specialPort = 443;
                    
                                if (!app.Context.Request.IsSecureConnection 
                                   || app.Context.Request.Url.Port != specialPort)
                                {
                                   app.Context.Response.Redirect("https://" 
                                      + app.Context.Request.ServerVariables["HTTP_HOST"] 
                                      + app.Context.Request.RawUrl);    
                                }
                            }
                    
                            public void Dispose()
                            {
                                // Needed for IHttpModule
                            }
                        }
                    }
                    

                    然后只需将其编译为 DLL,将其作为对您项目的引用添加到 web.config 中:

                     <httpModules>
                          <add name="HttpsOnlyModule" type="HttpsOnly.HttpsOnlyModule, HttpsOnly" />
                     </httpModules>
                    

                    【讨论】:

                    • 这似乎比仅仅将其粘贴在 global.asax 中更复杂——只是好奇,有优势吗?
                    • 好处是,当你不想使用它时,只需在 web.config 中注释掉该模块即可。这个解决方案是可配置的,而另一个不是。
                    • 我有点困惑。我希望app.BeginRequest += new OnBeginRequest; 在Init 方法和OnBeginRequest 中包含当前Init 方法包含的内容。您确定此模块按预期工作吗?
                    • 它不起作用。您确实需要添加 OnBeginRequest 事件等,然后它才能工作。
                    • 我会编辑这个错误的代码,但为了确保安全,您还需要使用 HSTS。只需按照 Troy Hunt 的答案,将其作为一个模块即可;见support.microsoft.com/en-us/kb/307996(老歌,但很好)。
                    猜你喜欢
                    • 2015-01-08
                    • 2010-11-02
                    • 1970-01-01
                    • 1970-01-01
                    • 2013-03-06
                    • 2015-11-28
                    • 1970-01-01
                    • 2013-03-13
                    • 1970-01-01
                    相关资源
                    最近更新 更多