Cách tốt nhất trong asp.net để buộc https cho toàn bộ trang web?


192

Khoảng 6 tháng trước, tôi đã triển khai một trang web nơi mọi yêu cầu cần phải vượt qua https. Cách duy nhất tại thời điểm tôi có thể tìm thấy để đảm bảo rằng mọi yêu cầu đến một trang đều vượt quá https là kiểm tra nó trong sự kiện tải trang. Nếu yêu cầu không kết thúc http, tôi sẽ trả lời.redirect (" https://example.com ")

Có cách nào tốt hơn - lý tưởng nhất là một số cài đặt trong web.config?


kiểm tra câu trả lời của tôi ở đây stackoverflow.com/questions/33882350/ từ
Shady Sherif

Câu trả lời:


250

Vui lòng sử dụng HSTS (HTTP Strict Transport Security)

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

Câu trả lời gốc (thay thế bằng câu trả lời trên vào ngày 4 tháng 12 năm 2015)

về cơ bản

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);
   }
}

điều đó sẽ đi trong global.asax.cs (hoặc global.asax.vb)

tôi không biết cách chỉ định nó trong web.config


7
Điều này hoạt động, nhưng nó rất nguy hiểm đối với tôi: khi tôi cố chạy cục bộ trong VS 2010 với mã này đang chạy, trang bắt đầu của tôi không bao giờ được tải; thay vào đó, tôi vừa nhận được thông báo "Trang web này không khả dụng". Để khắc phục, tôi đã thêm một điều kiện thứ hai để kiểm tra xem url có chứa chuỗi "localhost" không: nếu không, thì buộc https.
mg1075

3
Điều này mang lại cho tôi một vòng lặp chuyển hướng. Trước khi tôi thêm mã, nó hoạt động tốt. Bất kỳ đề xuất?
Joe

9
Xin lưu ý rằng điều này không cung cấp bất kỳ bảo mật hữu ích nào. Trên thực tế, nó sẽ chỉ bảo mật các kết nối từ những người dùng đã an toàn và sẽ không bảo mật những kết nối đang bị tấn công (điều này là do MITM có thể đơn giản bỏ qua chuyển hướng hoàn toàn và chuyển tiếp mọi thứ đến trang web "an toàn" của bạn). IMHO, chuyển hướng các tác nhân người dùng chỉ là bảo mật voodoo tốt, và cung cấp một ảo tưởng đôi khi nguy hiểm về an toàn. Cách duy nhất để đi là hướng dẫn các tác nhân người dùng chỉ yêu cầu tài nguyên an toàn, không chuyển hướng họ nếu họ không. Đây là những gì HSTS làm - xem câu trả lời dưới đây.
tne

2
Câu trả lời này nên được coi là "có hại" và không nên được sử dụng. Theo nhận xét của @tne ở trên.
Rosdi Kasim

2
@RosdiKasim Câu trả lời này có nên được coi là có hại kể từ lần chỉnh sửa ngày 4 tháng 12 không?
Andrew Morton

123

Một điều khác bạn có thể làm là sử dụng HSTS bằng cách trả lại tiêu đề "Strict-Transport-Security" cho trình duyệt. Trình duyệt phải hỗ trợ điều này (và hiện tại, chủ yếu là Chrome và Firefox), nhưng điều đó có nghĩa là một khi được đặt, trình duyệt sẽ không yêu cầu trang web qua HTTP và thay vào đó sẽ dịch chúng sang các yêu cầu HTTPS trước khi phát hành chúng . Hãy thử kết hợp với chuyển hướng từ 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;
  }
}

Các trình duyệt không biết HSTS sẽ chỉ bỏ qua tiêu đề nhưng vẫn sẽ bị câu lệnh chuyển đổi và gửi đến HTTPS.


6
Chưa bao giờ nghe về tiêu đề HSTS trước đây, nhưng trông khá tuyệt. Có bất kỳ lý do để sử dụng một giá trị tuổi tối đa nhỏ như vậy (5 phút)? Bài viết Wikipedia mà bạn liên kết để đề xuất đặt nó thành một giá trị lớn (6-12 tháng).
dana

5
+1. kiểm tra bài viết rất rộng rãi này trên blog của Troy, trong đó bao gồm các chi tiết về lý do tại sao chỉ sử dụng chuyển hướng có thể làm giảm bảo mật. Gợi ý: nó có thể khiến bạn dễ bị tổn thương với công cụ SSL Dải, trong số những thứ khác. troyhunt.com/2011/11/ từ
Oran Dennison

3
Cũng đáng để kiểm tra NWebsec , điều này làm cho việc này (và hơn thế nữa) rất dễ dàng.
Tieson T.

16
Bạn sẽ muốn bọc công tắc if(!Request.IsLocal)để nó không bị lỗi.
Justin J Stark

1
Câu trả lời tốt. Một sự tinh tế - Đối với các tiêu đề http ("Strict-Transport-Security"), tốt hơn là sử dụng thư viện như NWebSec vì có nhiều tùy chọn tập trung ở một nơi cấu hình thay vì trải rộng ở đây và ở đó.
Ognyan Dimitrov

89

Mô-đun IIS7 sẽ cho phép bạn chuyển hướng.

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

12
Ngoài ra, đối với IIS 7.0, bạn cần cài đặt Url Rewrite Module 2.0
Chris

Tôi thấy liên kết này đơn giản và hữu ích trong việc tạo bất kỳ trang cụ thể nào để chỉ chấp nhận các yêu cầu https - support.microsoft.com/kb/239875
Manik Arora

21

Đối với những người sử dụng ASP.NET MVC. Bạn có thể sử dụng cách sau để buộc SSL / TLS qua HTTPS trên toàn bộ trang web theo hai cách:

Con đường gian nan

1 - Thêm RequireHttpsAttribution vào các bộ lọc toàn cầu:

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

2 - Buộc mã thông báo chống giả mạo sử dụng SSL / TLS:

AntiForgeryConfig.RequireSsl = true;

3 - Yêu cầu Cookies yêu cầu HTTPS theo mặc định bằng cách thay đổi tệp Web.config:

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

4 - Sử dụng gói Nuebet của NWebSec.Owin và thêm dòng mã sau đây để bật Strict Transport Security trên trang web. Đừng quên thêm chỉ thị Tải trước bên dưới và gửi trang web của bạn đến trang web Tải trước HSTS . Thêm thông tin ở đâyở đây . Lưu ý rằng nếu bạn không sử dụng OWIN, có một phương pháp Web.config bạn có thể đọc trên trang web của NAebSec .

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

5 - Sử dụng gói Nuebet của NWebSec.Owin và thêm dòng mã sau đây để bật Ghim khóa công khai (HPKP) trên trang web. Thêm thông tin ở đâyở đây .

// 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 - Bao gồm lược đồ https trong bất kỳ URL nào được sử dụng. Chính sách bảo mật nội dung (CSP) Tiêu đề HTTP và tính toàn vẹn nguồn phụ (SRI) không hoạt động tốt khi bạn bắt chước lược đồ trong một số trình duyệt. Tốt hơn là nên nói rõ về HTTPS. ví dụ

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

Cách dễ dàng

Sử dụng mẫu dự án ASP.NET MVC Boilerplate Visual Studio để tạo một dự án với tất cả những thứ này và được tích hợp nhiều hơn nữa. Bạn cũng có thể xem mã trên GitHub .


3
Ngoài ra nếu sử dụng <authentication mode="Forms">, bên trong bạn phải có<forms requireSSL="true">
Pluto

1
@ muhammad-Rehan-saeed Tôi đang sử dụng chương trình soạn thảo mvc5 nhưng trang web không tự động chuyển hướng http sang https trên máy chủ sản xuất, vì vậy chỉ có trên localhost là tôi còn thiếu điều gì?
Diin

Đây không phải là diễn đàn phù hợp để đặt câu hỏi này. Đăng một vấn đề trên trang GitHub. Không RequireHttpsAttributechuyển hướng. Miễn là bạn có nó sẽ ổn thôi.
Muhammad Rehan Saeed

@MuhammadRehanSaeed, thích câu trả lời của bạn. Nhưng ... làm cách nào để có được hàm băm SHA256 của chứng chỉ được tạo bằng MakeCert? Tất cả những gì tôi có là một dấu vân tay SHA-1 ... Bạn có biết không?
Diana

1
@Diana liên kết này có thể chỉ cho bạn cách.
Muhammad Rehan Saeed

13

Nếu bạn không thể thiết lập điều này trong IIS vì bất kỳ lý do gì, tôi sẽ tạo một mô-đun HTTP thực hiện chuyển hướng cho bạn:

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

Sau đó, chỉ cần biên dịch nó thành một DLL, thêm nó làm tài liệu tham khảo cho dự án của bạn và đặt nó trong web.config:

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

Điều này có vẻ liên quan nhiều hơn là chỉ gắn bó nó trên toàn cầu.asax - chỉ tò mò, có lợi thế không?
Brian MacKay

1
Ưu điểm sẽ là, khi bạn không muốn sử dụng nó, chỉ cần nhận xét mô-đun trong web.config. Giải pháp này là cấu hình, trong khi giải pháp khác thì không.
Bob Yexley

2
Tôi hơi bối rối. Tôi đã mong đợi một cái gì đó giống như app.BeginRequest += new OnBeginRequest;trong Initphương thức và trong OnBeginRequestđó sẽ chứa Initphương thức hiện tại chứa gì . Bạn có chắc chắn rằng mô-đun này hoạt động như mong đợi?
Jakub turc

Nó không hoạt động. Bạn cần phải thêm sự kiện OnBeginRequest, v.v., sau đó nó hoạt động.
SnAzBaZ

Tôi sẽ chỉnh sửa mã bị lỗi này, nhưng để bảo mật, bạn cũng cần sử dụng HSTS. Chỉ cần đi với câu trả lời của Troy Hunt và biến nó thành một mô-đun; xem support.microsoft.com/en-us/kb/307996 (một người già, nhưng tốt bụng).
Marc L.

4

Những gì bạn cần làm là:

1) Thêm khóa bên trong web.config, tùy thuộc vào máy chủ sản xuất hoặc giai đoạn như bên dưới

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

2) Bên trong tệp Global.asax của bạn thêm phương thức bên dưới.

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);
            }
        }
    }
}

3

Nếu hỗ trợ SSL không thể định cấu hình trong trang web của bạn (nghĩa là có thể bật / tắt https) - bạn có thể sử dụng thuộc tính [RequireHttps] trên bất kỳ hành động điều khiển / điều khiển nào bạn muốn bảo mật.



2

Đối với @Joe ở trên, "Điều này mang lại cho tôi một vòng lặp chuyển hướng. Trước khi tôi thêm mã, nó hoạt động tốt. Có đề xuất nào không? - Joe ngày 8 tháng 11 '11 lúc 4:13"

Điều này cũng xảy ra với tôi và điều tôi tin là đã xảy ra là có một bộ cân bằng tải chấm dứt yêu cầu SSL trước máy chủ Web. Vì vậy, trang web của tôi luôn nghĩ rằng yêu cầu là "http", ngay cả khi trình duyệt ban đầu yêu cầu nó là "https".

Tôi thừa nhận đây là một chút hack, nhưng điều làm việc cho tôi là triển khai một tài sản "JustRedirected" mà tôi có thể tận dụng để tìm ra người đã được chuyển hướng một lần. Vì vậy, tôi kiểm tra các điều kiện cụ thể để đảm bảo chuyển hướng và, nếu chúng được đáp ứng, tôi đặt thuộc tính này (giá trị được lưu trữ trong phiên) trước khi chuyển hướng. Ngay cả khi các điều kiện http / https để chuyển hướng được đáp ứng lần thứ hai, tôi bỏ qua logic chuyển hướng và đặt lại giá trị phiên "JustRedirected" thành false. Bạn sẽ cần logic kiểm tra có điều kiện của riêng bạn, nhưng đây là cách triển khai đơn giản của thuộc tính:

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

            return (bool)Session[RosadaConst.JUSTREDIRECTED];
        }
        set
        {
            Session[RosadaConst.JUSTREDIRECTED] = value;
        }
    }

2

Tôi sẽ ném hai xu của mình vào. NẾU bạn có quyền truy cập vào phía máy chủ IIS, thì bạn có thể buộc HTTPS bằng cách sử dụng các ràng buộc giao thức. Ví dụ, bạn có một trang web gọi là Blah . Trong IIS, bạn sẽ thiết lập hai trang web: BlahBlah (Chuyển hướng) . Đối với Blah chỉ định cấu hình HTTPSliên kết (và FTPnếu bạn cần, hãy đảm bảo buộc nó qua kết nối an toàn). Đối với Blah (Redirect) chỉ cấu hình HTTPràng buộc. Cuối cùng, trong phần Chuyển hướng HTTP cho Blah (Chuyển hướng), hãy đảm bảo đặt chuyển hướng 301 thành https://blah.com, với đích chính xác được bật. Đảm bảo rằng mỗi trang web trong IIS đang trỏ đến nóthư mục gốc của riêng nếu không Web.configsẽ nhận được tất cả các vít lên. Ngoài ra, hãy đảm bảo đã HSTSđịnh cấu hình trên trang web HTTPSed của bạn để các yêu cầu tiếp theo của trình duyệt luôn bị ép buộc với HTTPS và không có chuyển hướng nào xảy ra.


2

Đây là câu trả lời đầy đủ hơn dựa trên @Troy Hunt. Thêm chức năng này vào WebApplicationlớp của bạn trong Global.asax.cs:

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

(Để bật SSL trên bản dựng cục bộ của bạn, hãy bật nó trong dock Thuộc tính cho dự án)


1

-> Đơn giản chỉ cần THÊM [RequireHttps] trên đầu lớp công cộng HomeContoder: Trình điều khiển.

-> Và thêm GlobalFilters.Filters.Add (new RequireHttpsAttribution ()); trong phương thức 'được bảo vệ void Application_Start ()' trong tệp Global.asax.cs.

Điều này buộc toàn bộ ứng dụng của bạn vào HTTPS.


Tôi không tin rằng điều này sẽ hoạt động cho bất kỳ trang nào được phục vụ bằng WebForms hoặc bất kỳ API nào được xây dựng bằng WebAPI. Nó sẽ chỉ bao gồm các bộ điều khiển MVC.
Marc L.

1

Đôi khi tôi đã dành thời gian để tìm kiếm thực hành tốt nhất có ý nghĩa và tìm thấy những điều sau đây hoàn hảo cho tôi. Tôi hy vọng điều này sẽ cứu bạn đôi khi.

Sử dụng tệp cấu hình (ví dụ: trang web asp.net) https://bloss.msdn.microsoft.com/kaushal/2013/05/22/http-to-https-redirects-on-iis-7-x-and- cao hơn /

hoặc trên máy chủ của riêng bạn https://www.sslshopper.com/iis7-redirect-http-to-https.html

[RÚT GỌN TRẢ LỜI] Đơn giản là mã bên dưới đi vào bên trong

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

1

Trong IIS10 (Windows 10 và Server 2016), từ phiên bản 1709 trở đi, có một tùy chọn mới, đơn giản hơn để bật HSTS cho trang web.

Microsoft mô tả các ưu điểm của cách tiếp cận mới ở đây và cung cấp nhiều ví dụ khác nhau về cách triển khai thay đổi theo chương trình hoặc bằng cách chỉnh sửa trực tiếp tệp Applicationhost.config (giống như web.config nhưng hoạt động ở cấp IIS, thay vì ở cấp trang web riêng lẻ ). Có thể tìm thấy Applicationhost.config trong C: \ Windows \ System32 \ inetsrv \ config.

Tôi đã phác thảo hai trong số các phương pháp ví dụ ở đây để tránh thối liên kết.

Phương pháp 1 - Chỉnh sửa tệp Applicationhost.config trực tiếp Giữa các <site>thẻ, thêm dòng này:

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

Phương pháp 2 - Dòng lệnh: Thực hiện các thao tác sau từ dấu nhắc lệnh nâng cao (tức là chuột phải trên CMD và chạy với tư cách quản trị viên). Hãy nhớ trao đổi Contoso với tên trang web của bạn khi nó xuất hiện trong IIS Manager.

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

Các phương pháp khác mà Microsoft cung cấp trong các bài viết đó có thể là các tùy chọn tốt hơn nếu bạn ở trong môi trường được lưu trữ nơi bạn có quyền truy cập hạn chế.

Hãy nhớ rằng IIS10 phiên bản 1709 hiện đã có sẵn trên Windows 10, nhưng đối với Windows Server 2016, nó nằm trên một bản phát hành khác và sẽ không được phát hành dưới dạng bản vá hoặc gói dịch vụ. Xem ở đây để biết chi tiết về 1709.


0

Nếu bạn đang sử dụng ASP.NET Core, bạn có thể dùng thử gói nuget SaidOut.AspNetCore.HttpsWithStrictTransportSecurity.

Sau đó, bạn chỉ cần thêm

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

Điều này cũng sẽ thêm tiêu đề HTTP StrictTransportSecurity cho tất cả các yêu cầu được thực hiện bằng cách sử dụng lược đồ https.

Mã ví dụ và tài liệu https://github.com/saidout/saidout-aspnetcore-httpswithstricttransportsecurity#example-code

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.