2019年3月3日 星期日

[ASP.Net Core] Enable HTTPS and redirection


 ASP.NET Core   HTTPS   SSL  


Introduction


Learn how to force the ASP.NET Core application to redirect requests from HTTP to HTTPS.



Environment


.NET Core 2.2.104
Visual  Studio 2017 Community



Implement


Visual Studio's template

The quickest way is enabling the option: Configure for HTTPS, while creating a new project.




Enable HTTPS manually

In Startup.cs,

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseHttpsRedirection();
   
    // ...Skip
}



(Option1) Kestrel

launchSettings.json

Update the applicationUrl to control the ports of Http and Https,

"profiles": {
    "Demo.WebApi": {
      "commandName": "Project",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "applicationUrl": "https://localhost:5001;http://localhost:5000"
    },
}



(Option2) IIS express

!! SSL Ports is limited to 44300 to 44399 in IIS Express.
(Reference: Handling URL Binding Failures in IIS Express)


launchSettings.json

Set the sslPort like following,

"iisSettings": {
  "windowsAuthentication": false,
  "anonymousAuthentication": true,
  "iisExpress": {
    "applicationUrl": "http://localhost:5000",
    "sslPort": 44301
  }
}


The settings will be mapped to .vs\config\applicationhost.config

<site name="Demo.Web" id="2">
  <application path="/" applicationPool="Demo.WebApi AppPool">
    <virtualDirectory path="/" physicalPath="D:\Works\SourceControl\...\Demo.Web" />
  </application>
  <bindings>
    <binding protocol="http" bindingInformation="*:5000:localhost" />
    <binding protocol="https" bindingInformation="*:44301:localhost" />
  </bindings>
</site>



And while you runs the application on IIS Express, the system environment variable:
ASPNETCORE_HTTPS_PORT
Will be put into WebConfig as following.

<system.webServer>
    <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="true" stdoutLogFile=".\App_Data\stdout" hostingModel="InProcess">
      <environmentVariables>    
        <environmentVariable name="ASPNETCORE_HTTPS_PORT" value="5556" />
      </environmentVariables>
    </aspNetCore>
  </system.webServer>




Http.Sys in IIS/IIS Express

Http.Sys on IIS Express will default supports Https.


launchSettings.json

Set sslPort in iisSettings.

{
  "iisSettings": {
    "windowsAuthentication": true,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:61598/",
      "sslPort": 44301
    }
  },
}



Program.cs

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .UseIISIntegration()
            // …
}


Startup.cs

public void ConfigureServices(IServiceCollection services)
{
   #region Enable Authentication by Http.Sys
   services.AddAuthentication(HttpSysDefaults.AuthenticationScheme);              
   #endregion
}




Http.Sys by self-hosting

Http.Sys by self-hosting cannot use Https directly. We have to manually bind the SSL certificate to the site.



1. First find out the hash code (Thumbprint) of the target SSL cert by certlm.msc as following.




---
Notice that the SSL cert MUST be in Local Machine level, or you will get the error message when doing netsh http add sslcert … later.

SSL Certificate add failed, Error 1312
A specified logon session does not exist. It may already have been terminated.


See reference on StackOverflow.
---


2. SSL cert binding and Url reservation

Then use the powershell command to bind the SSL cert to our host:port.

$guid = [guid]::NewGuid()
$certHash = "da787c5xxxxxxxxxxxxxxxxxxxxxxxxxx9ab3"
$ip = "0.0.0.0" # This means all IP addresses
$port = "5001" # the default HTTPS port
"http add sslcert ipport=$($ip):$port certhash=$certHash appid={$guid}" | netsh
"http add urlacl url=https://+:5001/ user=""NT AUTHORITY\NETWORK SERVICE""" | netsh



And then set the URL reservation for the specified URL namespace for the DOMAIN\user account.

"http add urlacl url=https://+:5001/ user=""NT AUTHORITY\NETWORK SERVICE""" | netsh


If you get the error:
Access is denied
When starting the Http.Sys server, try REMOVING the urlacl!


You can check the list of URL reservations(urlacl) by

"http show urlacl" | netsh


Or remove the urlacl by

"http delete urlacl url=https://+:5001/" | netsh


3.  Update code



Program.cs

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .UseHttpSys(options =>
            {
                 options.Authentication.Schemes =
                     AuthenticationSchemes.NTLM | AuthenticationSchemes.Negotiate;
                 options.Authentication.AllowAnonymous = true;
                 options.MaxConnections = null;
                 options.MaxRequestBodySize = 30000000;
                 options.UrlPrefixes.Add("http://localhost:5000");
                 options.UrlPrefixes.Add("https://localhost:5001");
             })
             // …
}



Startup.cs

public void ConfigureServices(IServiceCollection services)
{
   #region Enable Authentication by Http.Sys
  services.AddAuthentication(
   Microsoft.AspNetCore.Server.IISIntegration.IISDefaults.AuthenticationScheme);
            #endregion

}







On Production


IIS : (Option1) HTTPS Redirection Middleware

The default redirection is 307 Temporary Redirect.
If you wanna change the redirection as 308 Permanent Redirect, use AddHttpsRedirection to configure middleware options.

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    if (!this._env.IsDevelopment())
    {
        services.AddHttpsRedirection(options =>
        {
            options.RedirectStatusCode = StatusCodes.Status308PermanentRedirect;
            options.HttpsPort = 443;
        });
    }
}




Notice that using HttpsRedirectionOptions.HttpsPort will overwrite ASPNETCORE_HTTPS_PORT environment variable’s value.

Make sure one of them is set for enabling HTTPS.




Then,

1.  Set the system environment variable: ASPNETCORE_ENVIRONMENT
2.  To override the system environment variable (Reference), set it on WebConfig like following,

<aspNetCore processPath="dotnet"
      arguments=".\MyApp.dll"
      stdoutLogEnabled="false"
      stdoutLogFile=".\log\stdout"
      hostingModel="InProcess">
  <environmentVariables>
    <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Staging" />
  </environmentVariables>
</aspNetCore>


Notice that setting both System environment variable and WebConfig, will get a concat value, for example, Staging;Production.

Follow issue#6140.



3.  The value of ASPNETCORE_ENVIRONMENT in WebConfig can be set in Publish Profile (*.pubxml) as well for deployment.

<PropertyGroup>
  <EnvironmentName>Production</EnvironmentName>
</PropertyGroup>


Then we can deploy by,

$ dotnet publish --configuration Release /p:PublishProfile=Properties\PublishProfiles\FolderProfile.pubxml



IIS : (Option2) Redirect rules on WebConfig

URL Rewrite module is required.

For localhost/IP:Port

<system.webServer>
  <rewrite>
    <rules>
      <rule name="HTTP to HTTPS redirect" stopProcessing="true">
        <match url=".*" />
        <conditions>
          <add input="{HTTP_HOST}" pattern="^(.*):2222$" />
        </conditions>
        <action type="Redirect" url="https://{C:1}:2223/{R:0}" redirectType="Temporary" />
      </rule>
    </rules>
  </rewrite>
</system.webServer>


Already has a Domain name

<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" redirectType="Found" url="https://{HTTP_HOST}/{R:1}" redirectType="Temporary" />
      </rule>
    </rules>
  </rewrite>
</system.webServer>




Reference


沒有留言:

張貼留言