Zabezpieczanie mikrousług platformy .NET i aplikacji internetowych

Porada

Ta zawartość jest fragmentem książki eBook, architektury mikrousług platformy .NET dla konteneryzowanych aplikacji platformy .NET, dostępnej na platformie .NET Docs lub jako bezpłatnego pliku PDF z możliwością pobrania, który można odczytać w trybie offline.

.NET Microservices Architecture for Containerized .NET Applications eBook cover thumbnail.

Istnieje tak wiele aspektów zabezpieczeń w mikrousługach i aplikacjach internetowych, że temat może łatwo wziąć kilka książek takich jak ten. W tej sekcji skupimy się na uwierzytelnianiu, autoryzacji i wpisach tajnych aplikacji.

Implementowanie uwierzytelniania w mikrousługach platformy .NET i aplikacjach internetowych

Często konieczne jest, aby zasoby i interfejsy API opublikowane przez usługę ograniczały się do niektórych zaufanych użytkowników lub klientów. Pierwszym krokiem do podejmowania tego rodzaju decyzji dotyczących zaufania na poziomie interfejsu API jest uwierzytelnianie. Uwierzytelnianie to proces niezawodnego weryfikowania tożsamości użytkownika.

W scenariuszach mikrousług uwierzytelnianie jest zwykle obsługiwane centralnie. Jeśli używasz bramy interfejsu API Gateway, brama jest dobrym miejscem do uwierzytelnienia, jak pokazano na rysunku 9-1. Jeśli używasz tego podejścia, upewnij się, że nie można uzyskać bezpośredniego dostępu do poszczególnych mikrousług (bez bramy interfejsu API), chyba że istnieje dodatkowe zabezpieczenia w celu uwierzytelnienia komunikatów pochodzących z bramy, czy nie.

Diagram showing how the client mobile app interacts with the backend.

Rysunek 9–1. Scentralizowane uwierzytelnianie za pomocą bramy interfejsu API

Gdy usługa API Gateway scentralizuje uwierzytelnianie, dodaje informacje o użytkowniku podczas przekazywania żądań do mikrousług. Jeśli dostęp do usług można uzyskać bezpośrednio, można użyć usługi uwierzytelniania, takiej jak Azure Active Directory lub dedykowanej mikrousługi uwierzytelniania działającej jako usługa tokenu zabezpieczającego (STS) do uwierzytelniania użytkowników. Decyzje o zaufaniu są współużytkowane między usługami z tokenami zabezpieczającymi lub plikami cookie. (Te tokeny można udostępniać między aplikacjami ASP.NET Core w razie potrzeby, implementując udostępnianie plików cookie). Ten wzorzec jest pokazany na rysunku 9-2.

Diagram showing authentication through backend microservices.

Rysunek 9–2. Uwierzytelnianie według mikrousługi tożsamości; zaufanie jest udostępniane przy użyciu tokenu autoryzacji

Gdy dostęp do mikrousług jest uzyskiwany bezpośrednio, zaufanie, które obejmuje uwierzytelnianie i autoryzację, jest obsługiwane przez token zabezpieczający wystawiony przez dedykowaną mikrousługę współużytkowaną między mikrousługami.

Uwierzytelnianie przy użyciu tożsamości ASP.NET Core

Podstawowym mechanizmem w ASP.NET Core identyfikacji użytkowników aplikacji jest ASP.NET Core System członkostwa tożsamości. ASP.NET Core Identity przechowuje informacje o użytkowniku (w tym informacje o logowaniu, rolach i oświadczeniach) w magazynie danych skonfigurowanym przez dewelopera. Zazwyczaj magazyn danych ASP.NET Core Identity jest magazynem programu Entity Framework podanym w pakiecieMicrosoft.AspNetCore.Identity.EntityFrameworkCore. Jednak magazyny niestandardowe lub inne pakiety innych firm mogą służyć do przechowywania informacji o tożsamości w usłudze Azure Table Storage, CosmosDB lub innych lokalizacjach.

Porada

ASP.NET Core 2.1 i nowszych udostępnia ASP.NET Core Identity jako bibliotekę klas Razor, więc nie będzie widocznych wielu niezbędnych kodu w projekcie, podobnie jak w przypadku poprzednich wersji. Aby uzyskać szczegółowe informacje na temat dostosowywania kodu tożsamości zgodnie z potrzebami, zobacz Tworzenie szkieletu tożsamości w projektach ASP.NET Core.

Poniższy kod jest pobierany z szablonu projektu ASP.NET Core Web Application MVC 3.1 z wybranym indywidualnym uwierzytelnianiem konta użytkownika. Pokazano w nim, jak skonfigurować tożsamość ASP.NET Core przy użyciu programu Entity Framework Core w metodzie Startup.ConfigureServices .

public void ConfigureServices(IServiceCollection services)
{
    //...
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));

    services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>();

    services.AddRazorPages();
    //...
}

Po skonfigurowaniu ASP.NET Core Identity można ją włączyć, dodając element app.UseAuthentication() iendpoints.MapRazorPages(), jak pokazano w poniższym kodzie w metodzie usługiStartup.Configure:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    //...
    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
    //...
}

Ważne

Wiersze w poprzednim kodzie MUSZĄ BYĆ W KOLEJNOŚCI POKAZANEJ , aby tożsamość działała prawidłowo.

Korzystanie z usługi ASP.NET Core Identity umożliwia korzystanie z kilku scenariuszy:

  • Utwórz nowe informacje o użytkowniku przy użyciu typu UserManager (userManager.CreateAsync).

  • Uwierzytelnianie użytkowników przy użyciu typu SignInManager. Możesz użyć signInManager.SignInAsync polecenia , aby zalogować się bezpośrednio lub signInManager.PasswordSignInAsync potwierdzić, że hasło użytkownika jest poprawne, a następnie zaloguj się.

  • Zidentyfikuj użytkownika na podstawie informacji przechowywanych w pliku cookie (odczytanym przez oprogramowanie pośredniczące ASP.NET Core Identity), aby kolejne żądania z przeglądarki zawierały tożsamość i oświadczenia zalogowanego użytkownika.

usługa ASP.NET Core Identity obsługuje również uwierzytelnianie dwuskładnikowe.

W przypadku scenariuszy uwierzytelniania korzystających z lokalnego magazynu danych użytkownika i utrwalania tożsamości między żądaniami przy użyciu plików cookie (co jest typowe w przypadku aplikacji internetowych MVC), ASP.NET Core Identity jest zalecanym rozwiązaniem.

Uwierzytelnianie za pomocą dostawców zewnętrznych

ASP.NET Core obsługuje również używanie zewnętrznych dostawców uwierzytelniania, aby umożliwić użytkownikom logowanie się za pośrednictwem przepływów protokołu OAuth 2.0. Oznacza to, że użytkownicy mogą logować się przy użyciu istniejących procesów uwierzytelniania od dostawców, takich jak Microsoft, Google, Facebook lub Twitter, i skojarzyć te tożsamości z tożsamością ASP.NET Core w aplikacji.

Aby użyć uwierzytelniania zewnętrznego, oprócz uwierzytelniania oprogramowania pośredniczącego, jak wspomniano wcześniej, przy użyciu app.UseAuthentication() metody należy również zarejestrować dostawcę zewnętrznego, Startup jak pokazano w poniższym przykładzie:

public void ConfigureServices(IServiceCollection services)
{
    //...
    services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>();

    services.AddAuthentication()
        .AddMicrosoftAccount(microsoftOptions =>
        {
            microsoftOptions.ClientId = Configuration["Authentication:Microsoft:ClientId"];
            microsoftOptions.ClientSecret = Configuration["Authentication:Microsoft:ClientSecret"];
        })
        .AddGoogle(googleOptions => { ... })
        .AddTwitter(twitterOptions => { ... })
        .AddFacebook(facebookOptions => { ... });
    //...
}

W poniższej tabeli przedstawiono popularnych dostawców uwierzytelniania zewnętrznego i skojarzonych z nimi pakietów NuGet:

Dostawca Pakiet
Microsoft Microsoft.AspNetCore.Authentication.MicrosoftAccount
Google Microsoft.AspNetCore.Authentication.Google
Facebook Microsoft.AspNetCore.Authentication.Facebook
Twitter Microsoft.AspNetCore.Authentication.Twitter

We wszystkich przypadkach należy wykonać procedurę rejestracji aplikacji, która jest zależna od dostawcy i zwykle obejmuje:

  1. Pobieranie identyfikatora aplikacji klienckiej.
  2. Pobieranie wpisu tajnego aplikacji klienckiej.
  3. Konfigurowanie adresu URL przekierowania obsługiwanego przez oprogramowanie pośredniczące autoryzacji i zarejestrowanego dostawcę
  4. Opcjonalnie skonfigurowanie adresu URL wylogowywania w celu prawidłowego obsługi wylogowania w scenariuszu logowania jednokrotnego.

Aby uzyskać szczegółowe informacje na temat konfigurowania aplikacji dla dostawcy zewnętrznego, zobacz uwierzytelnianie dostawcy zewnętrznego w dokumentacji ASP.NET Core).

Porada

Wszystkie szczegóły są obsługiwane przez wcześniej wymienione oprogramowanie pośredniczące autoryzacji i usługi. Dlatego wystarczy wybrać opcję uwierzytelniania indywidualnego konta użytkownika podczas tworzenia projektu aplikacji internetowej ASP.NET Core w Visual Studio, jak pokazano na rysunku 9–3, oprócz rejestrowania wcześniej wymienionych dostawców uwierzytelniania.

Screenshot of the New ASP.NET Core Web Application dialog.

Rysunek 9–3. Wybranie opcji Indywidualne konta użytkowników na potrzeby korzystania z uwierzytelniania zewnętrznego podczas tworzenia projektu aplikacji internetowej w Visual Studio 2019 r.

Oprócz wymienionych wcześniej zewnętrznych dostawców uwierzytelniania dostępne są pakiety innych firm, które zapewniają oprogramowanie pośredniczące do korzystania z wielu innych dostawców uwierzytelniania zewnętrznego. Aby uzyskać listę, zobacz repozytorium AspNet.Security.OAuth.Providers w witrynie GitHub.

Możesz również utworzyć własne oprogramowanie pośredniczące uwierzytelniania zewnętrznego, aby rozwiązać pewne specjalne potrzeby.

Uwierzytelnianie przy użyciu tokenów elementu nośnego

Uwierzytelnianie za pomocą usługi ASP.NET Core Identity (lub Identity plus zewnętrzni dostawcy uwierzytelniania) działa dobrze w przypadku wielu scenariuszy aplikacji internetowych, w których przechowywanie informacji o użytkowniku w pliku cookie jest odpowiednie. W innych scenariuszach pliki cookie nie są jednak naturalnym środkiem utrwalania i przesyłania danych.

Na przykład w interfejsie API sieci Web ASP.NET Core, który uwidacznia punkty końcowe RESTful, do których mogą uzyskiwać dostęp aplikacje jednostronicowe (SPA), klienci natywni, a nawet inne interfejsy API sieci Web, zazwyczaj chcesz użyć uwierzytelniania tokenu elementu nośnego. Te typy aplikacji nie działają z plikami cookie, ale można łatwo pobrać token elementu nośnego i dołączyć go do nagłówka autoryzacji kolejnych żądań. Aby włączyć uwierzytelnianie tokenu, ASP.NET Core obsługuje kilka opcji używania protokołu OAuth 2.0 i openID Połączenie.

Uwierzytelnianie za pomocą dostawcy tożsamości openID Połączenie lub OAuth 2.0

Jeśli informacje o użytkowniku są przechowywane w Azure Active Directory lub innym rozwiązaniu do obsługi identyfikatorów OpenID Połączenie lub OAuth 2.0, możesz użyć pakietu Microsoft.AspNetCore.Authentication.OpenIdConnect do uwierzytelniania przy użyciu przepływu pracy openID Połączenie. Aby na przykład uwierzytelnić się w mikrousłudze Identity.Api w aplikacji eShopOnContainers, aplikacja internetowa ASP.NET Core może używać oprogramowania pośredniczącego z tego pakietu, jak pokazano w poniższym uproszczonym przykładzie w Startup.csartykule :

// Startup.cs

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    //…
    app.UseAuthentication();
    //…
    app.UseEndpoints(endpoints =>
    {
        //...
    });
}

public void ConfigureServices(IServiceCollection services)
{
    var identityUrl = Configuration.GetValue<string>("IdentityUrl");
    var callBackUrl = Configuration.GetValue<string>("CallBackUrl");
    var sessionCookieLifetime = Configuration.GetValue("SessionCookieLifetimeMinutes", 60);

    // Add Authentication services

    services.AddAuthentication(options =>
    {
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddCookie(setup => setup.ExpireTimeSpan = TimeSpan.FromMinutes(sessionCookieLifetime))
    .AddOpenIdConnect(options =>
    {
        options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.Authority = identityUrl.ToString();
        options.SignedOutRedirectUri = callBackUrl.ToString();
        options.ClientId = useLoadTest ? "mvctest" : "mvc";
        options.ClientSecret = "secret";
        options.ResponseType = useLoadTest ? "code id_token token" : "code id_token";
        options.SaveTokens = true;
        options.GetClaimsFromUserInfoEndpoint = true;
        options.RequireHttpsMetadata = false;
        options.Scope.Add("openid");
        options.Scope.Add("profile");
        options.Scope.Add("orders");
        options.Scope.Add("basket");
        options.Scope.Add("marketing");
        options.Scope.Add("locations");
        options.Scope.Add("webshoppingagg");
        options.Scope.Add("orders.signalrhub");
    });
}

W przypadku korzystania z tego przepływu pracy oprogramowanie pośredniczące ASP.NET Core Identity nie jest potrzebne, ponieważ wszystkie magazyny informacji o użytkownikach i uwierzytelnianie są obsługiwane przez usługę Tożsamości.

Wystawianie tokenów zabezpieczających z usługi ASP.NET Core

Jeśli wolisz wystawiać tokeny zabezpieczające dla lokalnych użytkowników usługi ASP.NET Core Identity zamiast korzystać z zewnętrznego dostawcy tożsamości, możesz skorzystać z niektórych dobrych bibliotek innych firm.

IdentityServer4 i OpenIddict to dostawcy Połączenie OpenID, którzy łatwo integrują się z tożsamością ASP.NET Core, aby umożliwić wystawianie tokenów zabezpieczających z usługi ASP.NET Core. Dokumentacja identityServer4 zawiera szczegółowe instrukcje dotyczące korzystania z biblioteki. Jednak podstawowe kroki używania serwera IdentityServer4 do wystawiania tokenów są następujące.

  1. Wywołujesz aplikację. UseIdentityServer w metodzie Startup.Configure, aby dodać serwer IdentityServer4 do potoku przetwarzania żądań HTTP aplikacji. Umożliwia to bibliotece obsługę żądań dla punktów końcowych openID Połączenie i OAuth2, takich jak /connect/token.

  2. Serwer IdentityServer4 można skonfigurować w pliku Startup.ConfigureServices przez wywołanie usług. AddIdentityServer.

  3. Serwer tożsamości można skonfigurować, ustawiając następujące dane:

    • Poświadczenia do użycia do podpisywania.

    • Zasoby tożsamości i interfejsu API, do których użytkownicy mogą żądać dostępu:

      • Zasoby interfejsu API reprezentują chronione dane lub funkcje, do których użytkownik może uzyskać dostęp za pomocą tokenu dostępu. Przykładem zasobu interfejsu API będzie internetowy interfejs API (lub zestaw interfejsów API), który wymaga autoryzacji.

      • Zasoby tożsamości reprezentują informacje (oświadczenia), które są przekazywane klientowi w celu zidentyfikowania użytkownika. Oświadczenia mogą zawierać nazwę użytkownika, adres e-mail itd.

    • Klienci, którzy będą łączyć się w celu żądania tokenów.

    • Mechanizm przechowywania informacji o użytkowniku, taki jak ASP.NET Core Tożsamość lub alternatywa.

Po określeniu klientów i zasobów dla serwera IdentityServer4 do użycia można przekazać IEnumerable<T> kolekcję odpowiedniego typu do metod, które przyjmują klienta lub magazyny zasobów w pamięci. Lub w przypadku bardziej złożonych scenariuszy można podać typy klientów lub dostawców zasobów za pośrednictwem wstrzykiwania zależności.

Przykładowa konfiguracja usługi IdentityServer4 do używania zasobów w pamięci i klientów dostarczonych przez niestandardowy typ IClientStore może wyglądać podobnie do następującego przykładu:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    //...
    services.AddSingleton<IClientStore, CustomClientStore>();
    services.AddIdentityServer()
        .AddSigningCredential("CN=sts")
        .AddInMemoryApiResources(MyApiResourceProvider.GetAllResources())
        .AddAspNetIdentity<ApplicationUser>();
    //...
}

Korzystanie z tokenów zabezpieczających

Uwierzytelnianie względem punktu końcowego Połączenie OpenID lub wystawianie własnych tokenów zabezpieczających obejmuje niektóre scenariusze. Ale co z usługą, która po prostu musi ograniczyć dostęp do tych użytkowników, którzy mają prawidłowe tokeny zabezpieczające, które zostały dostarczone przez inną usługę?

W tym scenariuszu oprogramowanie pośredniczące uwierzytelniania obsługujące tokeny JWT jest dostępne w pakiecie Microsoft.AspNetCore.Authentication.JwtBearer . JWT oznacza "JSON Web Token" i jest typowym formatem tokenu zabezpieczającego (zdefiniowanym przez RFC 7519) do komunikowania oświadczeń zabezpieczeń. Uproszczony przykład użycia oprogramowania pośredniczącego do korzystania z takich tokenów może wyglądać jak ten fragment kodu, pobrany z mikrousługi Ordering.Api eShopOnContainers.

// Startup.cs

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    //…
    // Configure the pipeline to use authentication
    app.UseAuthentication();
    //…
    app.UseEndpoints(endpoints =>
    {
        //...
    });
}

public void ConfigureServices(IServiceCollection services)
{
    var identityUrl = Configuration.GetValue<string>("IdentityUrl");

    // Add Authentication services

    services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = AspNetCore.Authentication.JwtBearer.JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = AspNetCore.Authentication.JwtBearer.JwtBearerDefaults.AuthenticationScheme;

    }).AddJwtBearer(options =>
    {
        options.Authority = identityUrl;
        options.RequireHttpsMetadata = false;
        options.Audience = "orders";
    });
}

Parametry w tym użyciu to:

  • Audience reprezentuje odbiornik tokenu przychodzącego lub zasób, do którego token udziela dostępu. Jeśli wartość określona w tym parametrze nie jest zgodna z parametrem w tokenie, token zostanie odrzucony.

  • Authority to adres serwera uwierzytelniania wystawiającego tokeny. Oprogramowanie pośredniczące uwierzytelniania elementu nośnego JWT używa tego identyfikatora URI do pobrania klucza publicznego, którego można użyć do zweryfikowania podpisu tokenu. Oprogramowanie pośredniczące potwierdza również, że iss parametr w tokenie jest zgodny z tym identyfikatorem URI.

Inny parametr, RequireHttpsMetadata, jest przydatny do celów testowych. Ten parametr jest ustawiany na wartość false, aby można było testować w środowiskach, w których nie masz certyfikatów. W rzeczywistych wdrożeniach tokeny elementu nośnego JWT powinny być zawsze przekazywane tylko za pośrednictwem protokołu HTTPS.

Dzięki temu programowi pośredniczącego tokeny JWT są automatycznie wyodrębniane z nagłówków autoryzacji. Następnie są deserializowane, weryfikowane (przy użyciu wartości w Audience parametrach i Authority ) i przechowywane jako informacje o użytkowniku, do których mają się odwoływać później akcje MVC lub filtry autoryzacji.

Oprogramowanie pośredniczące uwierzytelniania elementu nośnego JWT może również obsługiwać bardziej zaawansowane scenariusze, takie jak używanie certyfikatu lokalnego do sprawdzania poprawności tokenu, jeśli urząd jest niedostępny. W tym scenariuszu JwtBearerOptions można określić TokenValidationParameters obiekt w obiekcie.

Dodatkowe zasoby