data.mdx.frontmatter.hero_image

HTTPS w aplikacji uruchomionej na localhost

2018-07-26 | .NET, OS X | bd90

Zapewne, w 1994 roku, kiedy to w przeglądarce Netscape Navigator po raz pierwszy pojawiła się obsługa protokołu https, nikt nie spodziewał się, że stanie się on standardem. Dziś, po ponad 14 latach rozwoju specyfikacji, trudno sobie wyobrazić stronę internetową bez zielonej kłódki przy pasku adresu.

Ok, teraz zacznie się ta mniej przyjemna część. No bo szyfrowanie jest super i w ogóle, ale... Nie umiałbym zliczyć sytuacji, gdy programując w środowisku lokalnym wszystko działało bezproblemowo, jednak po wgraniu na staging wyskakiwał przepiękny komunikat:

Oj, już nie będę przytaczał słów jakie najczęściej wtedy padają. Nie mówiąc już o potrzebie robienia kolejnego deploy-a. Niby drobna zmiana, http:// na //, a wszystko trzeba wgrywać od nowa. Przynajmniej mam czas na zrobienie sobie porządnego kubka kakałka.

Do niedawna myślałem: "Zjadłbym kebsa. A i z tym protokołem to się nie da nic zrobić, wszystko manualnie trzeba działać i tyle". Akceptując rzeczywistość jaką była nie szukałem nawet rozwiązania. Na szczęście podczas jednego z moich pędów do wiedzy natchnąłem się na Let's Encrypt, open source, który pozwala na generowanie certyfikatów za darmo. Wtedy zacząłem się zastanawiać czy istnieje możliwość wygenerowania certyfikatu TLS jako self signed i podpięcie go do localhost-a.

Konfiguracja Certyfikatu

Na początku tworzymy plik, w którym będzie przechowywana konfiguracja naszego certyfikatu. Wystarczy wpisać w terminalu proste polecenie:

touch localhost.conf

Następny krok jest równie prosty. Do naszego pliku wklejamy poniższą zawartość (jak z wikipedii do pracy zaliczeniowej):

[req]
default_bits       = 2048
default_keyfile    = localhost.key
distinguished_name = req_distinguished_name
req_extensions     = req_ext
x509_extensions    = v3_ca

[req_distinguished_name\]
countryName                 = Country Name (2 letter code)
countryName_default         = US
stateOrProvinceName         = State or Province Name (full name)
stateOrProvinceName_default = New York
localityName                = Locality Name (eg, city)
localityName_default        = Rochester
organizationName            = Organization Name (eg, company)
organizationName_default    = localhost
organizationalUnitName      = organizationalunit
organizationalUnitName_default = Development
commonName                  = Common Name (e.g. server FQDN or YOUR name)
commonName_default          = localhost
commonName_max              = 64

[req_ext]
subjectAltName = @alt_names

[v3_ca]
subjectAltName = @alt_names

[alt_names]
DNS.1   = localhost
DNS.2   = 127.0.0.1

Zazwyczaj tłumaczę punkt po punkcie elementy konfiguracji. Tym razem nie. Idziemy dalej :P

Tworzenie klucza TLS

Tu się zaczyna prawdziwa magia. Wygenerowanie klucza na podstawie konfiguracji wymaga zastosowania narzędzia openssl. Nie macie go zainstalowanego? Żaden problem, wystarczy komenda:

brew install openssl

Zdecydowanie polecam posiąść openssl, nawet jeżeli nie chcecie korzystać z certyfikatów HTTPS-a dla aplikacji uruchomionych na localhost-cie. Dlaczego? Przejdźmy dalej.

Teraz wpisujemy dwie, dość skomplikowane, komendy do wygenerowania prawdziwego klucza:

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout localhost.key -out localhost.crt -config localhost.conf -passin pass:YourSecurePassword

sudo openssl pkcs12 -export -out localhost.pfx -inkey localhost.key -in localhost.crt

W naszym katalogu powinno pojawić się kilka nowych plików:

Certyfikacie, ufam Tobie!

Pozostała już tylko ostatnia kwestia - dodanie certyfikatu do systemu przez aplikację Pęk kluczy(eng keychain Access.app) (wyszukujemy ją za pomocą wyszukiwarki spotlight(⌘ + Space)). Wystarczy do niej przeciągnąć plik localhost.pfx

Klikając na nowo dodany certyfikat dwa razy przejdziemy do opcji zaufania.Z listy rozwijanej musimy wybrać opcję Zawsze ufaj.

I tak właśnie zdefiniowaliśmy nasz własny certyfikat HTTPS w systemie.

Chcąc zapewnić Wam narzędzie do sprawdzenia, czy wszystko wyszło poprawnie, napiszmy wspólnie prostą aplikacje.

Aplikacja .NET Core z certyfikatem

Kestrel (serwer na którym jest uruchamiana aplikacja .NET Core-a) dopiero od niedawna wspiera certyfikaty SSL. Wcześniej, aby mieć stronę z zieloną kłódeczką, trzeba było używać np. nginx-a z reverse proxy. Obecnie sprawa wygląda prościej. Na początku musimy nasz certyfikat (plik localhost.pfx) skopiować do katalogu głównego projektu.

Następnie dodajemy do projektu bibliotekę Microsoft.AspNetCore.Server.Kestrel.Https. Możemy to zrobić dodając poniższy kod xml-a do pliku *.csproj lub za pomocą dotnet cli.

<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https">
  <Version>2.1.2</Version>
</PackageReference>

Teraz, w pliku Program.cs, musimy wkleić następujący kod:

public class Program
{
    public static void Main(string\[\] args)
    {
        var host = new WebHostBuilder()
            .UseKestrel(options =>
            {
                options.Listen(IPAddress.Loopback, 5000, listenOptions =>
                {
                    listenOptions.UseHttps("localhost.pfx", "YourSecurePassword");
                });
            })
            .UseUrls("http://*:5000")
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseStartup<Startup>()
            .Build();
        
        host.Run();
    }
}

Muszę przyznać, że jest to kod nieco bardziej skomplikowany niż standardowy CreateDefaultWebHost, jednak dzięki wykorzystaniu wyrażenia lambda, przekazanego do metody UseKestrel, możemy dodać wygenerowany certyfikat do aplikacji. W powyższym przykładzie użyłem przeciążenia metody UseHttps, które wymaga nazwy pliku i hasła, z jakim go wygenerowaliśmy. Pełną listę przeciążeń tej metody możecie znaleźć tutaj.

Właściwie to tyle, możemy już się cieszyć zieloną kłódeczką w naszej aplikacji uruchomionej na localhost.

Musicie przyznać, że wygląda to całkiem fajnie.

Podsumowanie

Tak oto daliśmy radę uruchomić aplikację z localhost-a na protokole HTTPS. Koniec z testowaniem, czy aplikacja działa poprawnie na serwerze zewnętrznym wykorzystującym HTTPS - a. Macie problem z dodaniem certyfikatu do aplikacji napisanej w Node.js? Chętnie poruszę ten temat! Dajcie znać w komentarzach czy za pomocą zakładki kontakt.

Do Następnego!

Cześć :)

PS. Pamiętajcie o poprawnym ustawieniu cookies, jeżeli używacie aplikacji MVC wraz z .NET Core Identity.

By Bd90 | 26-07-2018 | .NET, OS X