ASP.NET 앱 간에 인증 cookie 공유

작성자: Rick Anderson

웹 사이트는 종종 함께 작동하는 개별 웹앱으로 구성됩니다. SSO(Single Sign-On) 환경을 제공하려면 사이트 내의 웹앱에서 인증 cookie를 공유해야 합니다. 이 시나리오를 지원하기 위해 데이터 보호 스택에서는 Katana cookie 인증 및 ASP.NET Core cookie 인증 티켓을 공유할 수 있습니다.

다음 예제에서는 다음을 수행합니다.

  • 인증 cookie 이름은 .AspNet.SharedCookie의 공통 값으로 설정됩니다.
  • AuthenticationType은 명시적으로 또는 기본적으로 Identity.Application으로 설정됩니다.
  • 일반적인 앱 이름 SharedCookieApp은 데이터 보호 시스템이 데이터 보호 키를 공유할 수 있도록 하는 데 사용됩니다.
  • Identity.Application은 인증 체계로 사용됩니다. 어떤 체계가 사용되었든 간에 기본 체계로 사용하거나 명시적으로 설정하여 공유 cookie 앱 내 또는 전체에서 일관되게 사용되어야 합니다. 체계는 cookie를 암호화하고 암호 해독할 때 사용되므로 앱 간에 일관된 체계를 사용해야 합니다.
  • 공통 데이터 보호 키 스토리지 위치가 사용됩니다.
  • DataProtectionProvider 에는 Microsoft.AspNetCore.DataProtection.Extensions NuGet 패키지가 필요합니다.
  • SetApplicationName은 일반적인 앱 이름을 설정합니다.

ASP.NET Core Identity과 인증 cookie 공유

ASP.NET Core Identity을 사용하는 경우:

  • 데이터 보호 키와 앱 이름은 앱 간에 공유되어야 합니다. 공통 키 스토리지 위치는 다음 예제에서 PersistKeysToFileSystem 메서드에 제공됩니다. SetApplicationName을 사용하여 일반적인 공유 앱 이름(다음 예제에서는 SharedCookieApp)을 구성합니다. 자세한 내용은 ASP.NET Core 데이터 보호 구성을 참조하세요.
  • ConfigureApplicationCookie 확장 메서드를 사용하여 cookie에 대한 데이터 보호 서비스를 설정합니다.
  • 기본 인증 유형은 Identity.Application입니다.

Program.cs의 경우

using Microsoft.AspNetCore.DataProtection;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"c:\PATH TO COMMON KEY RING FOLDER"))
    .SetApplicationName("SharedCookieApp");

builder.Services.ConfigureApplicationCookie(options => {
    options.Cookie.Name = ".AspNet.SharedCookie";
});

var app = builder.Build();

참고: 위의 지침은 ITicketStore(CookieAuthenticationOptions.SessionStore)에서 작동하지 않습니다. 자세한 내용은 GitHub 이슈를 참조하세요.

보안상의 이유로 인증 cookie는 ASP.NET Core에서 압축되지 않습니다. 인증 cookie를 사용하는 경우 개발자는 필요에 따라 포함된 클레임 정보 수를 최소화해야 합니다.

ASP.NET Core Identity 없이 인증 cookie 공유

ASP.NET Core Identity를 사용하지 않고 cookie를 직접 사용하는 경우 데이터 보호 및 인증을 구성합니다. 다음 예제에서 인증 유형은 Identity.Application으로 설정됩니다.

using Microsoft.AspNetCore.DataProtection;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"c:\PATH TO COMMON KEY RING FOLDER"))
    .SetApplicationName("SharedCookieApp");

builder.Services.AddAuthentication("Identity.Application")
    .AddCookie("Identity.Application", options =>
    {
        options.Cookie.Name = ".AspNet.SharedCookie";
    });

var app = builder.Build();

보안상의 이유로 인증 cookie는 ASP.NET Core에서 압축되지 않습니다. 인증 cookie를 사용하는 경우 개발자는 필요에 따라 포함된 클레임 정보 수를 최소화해야 합니다.

여러 기본 경로에서 cookie 공유

인증 cookie는 기본 Cookie.PathHttpRequest.PathBase를 사용합니다. 앱의 cookie를 서로 다른 기본 경로에서 공유해야 하는 경우 Path를 재정의해야 합니다.

using Microsoft.AspNetCore.DataProtection;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"c:\PATH TO COMMON KEY RING FOLDER"))
    .SetApplicationName("SharedCookieApp");

builder.Services.ConfigureApplicationCookie(options => {
    options.Cookie.Name = ".AspNet.SharedCookie";
    options.Cookie.Path = "/";
});

var app = builder.Build();

하위 도메인에서 cookie 공유

여러 하위 도메인에서 cookie를 공유하는 앱을 호스팅하는 경우 Cookie.Domain 속성에서 공용 도메인을 지정합니다. contoso.com에서 앱 간에 cookie를 공유하려면(예: first_subdomain.contoso.comsecond_subdomain.contoso.com) Cookie.Domain.contoso.com으로 지정합니다.

options.Cookie.Domain = ".contoso.com";

미사용 데이터 보호 키 암호화

프로덕션 배포의 경우 DPAPI 또는 X509Certificate를 사용하여 미사용 키를 암호화하도록 DataProtectionProvider를 구성합니다. 자세한 내용은 ASP.NET Core를 사용하여 Windows 및 Azure에서 미사용 키 암호화를 참조하세요. 다음 예제에서는 인증서 지문이 ProtectKeysWithCertificate에 제공됩니다.

using Microsoft.AspNetCore.DataProtection;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddDataProtection()
    .ProtectKeysWithCertificate("{CERTIFICATE THUMBPRINT}");

일반 사용자 데이터베이스 사용

앱에서 동일한 Identity 스키마(동일한 버전의 Identity)를 사용하는 경우 각 앱의 Identity 시스템이 동일한 사용자 데이터베이스를 가리키는지 확인합니다. 그렇지 않으면 ID 시스템은 해당 데이터베이스의 정보와 인증 cookie의 정보를 일치시키려고 할 때 런타임 시 오류를 생성합니다.

일반적으로 앱이 서로 다른 Identity 버전을 사용하므로 앱 간에 Identity 스키마가 다른 경우 다른 앱의 Identity 스키마에 열을 다시 매핑하고 추가하지 않고는 최신 버전의 Identity를 기반으로 공통 데이터베이스를 공유할 수 없습니다. 일반적으로 앱에서 공통 데이터베이스를 공유할 수 있도록 최신 Identity 버전을 사용하도록 다른 앱을 업그레이드하는 것이 더 효율적입니다.

애플리케이션 이름 변경

.NET 6에서는 WebApplicationBuilder가 콘텐츠 루트 경로를 정규화하여 DirectorySeparatorChar로 끝납니다. HostBuilder 또는 WebHostBuilder에서 마이그레이션하는 대부분의 앱은 정규화되지 않으므로 동일한 앱 이름을 갖지 않습니다. 자세한 내용은 SetApplicationName을 참조하세요.

ASP.NET 4.x 및 ASP.NET Core 앱 간에 인증 cookie 공유

Microsoft.Owin Cookie 인증 미들웨어를 사용하는 ASP.NET 4.x 앱은 ASP.NET Core Cookie 인증 미들웨어와 호환되는 인증 cookie를 생성하도록 구성될 수 있습니다. 이는 웹 애플리케이션이 ASP.NET 4.x 앱과 Single Sign-On 환경을 공유해야 하는 ASP.NET Core 앱으로 구성된 경우에 유용할 수 있습니다. 이러한 시나리오의 특정 예는 웹앱을 ASP.NET에서 ASP.NET Core로 점진적으로 마이그레이션하는 것입니다. 이러한 시나리오에서는 앱의 일부 부분이 원래 ASP.NET 앱에서 제공되는 반면 다른 부분은 새 ASP.NET Core 앱에서 제공하는 것이 일반적입니다. 하지만 사용자는 한 번만 로그인하면 됩니다. 이 작업은 다음 방법 중 하나를 통해 수행할 수 있습니다.

  • ASP.NET 앱을 사용하여 사용자를 로그인하는 System.Web 어댑터의 원격 인증 기능을 사용합니다.
  • 인증이 ASP.NET Core 앱과 공유되도록 CookieMicrosoft.Owin cookie 인증 미들웨어를 사용할 수 있게 ASP.NET 앱을 구성합니다.

ASP.NET Microsoft.Owin Cookie 인증 미들웨어를 ASP.NET Core 앱과 cookie를 공유하도록 구성하려면 이전 지침에 따라 특정 cookie 이름, 앱 이름을 사용하고 데이터 보호 키를 잘 알려진 위치에 유지하도록 ASP.NET Core 앱을 구성합니다. 데이터 보호 키 유지에 대한 자세한 내용은 ASP.NET Core 데이터 보호 구성을 참조하세요.

ASP.NET 앱에서 Microsoft.Owin.Security.Interop 패키지를 설치합니다.

Startup.Auth.cs에서 UseCookieAuthentication 호출을 업데이트하여 ASP.NET Core 앱의 설정과 일치하도록 AspNetTicketDataFormat을 구성합니다.

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    LoginPath = new PathString("/Account/Login"),
    Provider = new CookieAuthenticationProvider
    { 
        OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
            validateInterval: TimeSpan.FromMinutes(30),
            regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
    },

    // Settings to configure shared cookie with ASP.NET Core app
    CookieName = ".AspNet.ApplicationCookie",
    AuthenticationType = "Identity.Application",                
    TicketDataFormat = new AspNetTicketDataFormat(
        new DataProtectorShim(
            DataProtectionProvider.Create(new DirectoryInfo(@"c:\PATH TO COMMON KEY RING FOLDER"),
            builder => builder.SetApplicationName("SharedCookieApp"))
            .CreateProtector(
                "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware",
                // Must match the Scheme name used in the ASP.NET Core app, i.e. IdentityConstants.ApplicationScheme
                "Identity.Application",
                "v2"))),
    CookieManager = new ChunkingCookieManager()
});

여기에 구성된 중요한 항목은 다음과 같습니다.

  • cookie 이름은 ASP.NET Core 앱과 동일한 이름으로 설정됩니다.
  • 데이터 보호 공급업체는 동일한 키 링 경로를 사용하여 만들어집니다. 이러한 예제에서는 데이터 보호 키가 디스크에 저장되지만 다른 데이터 보호 공급업체를 사용할 수 있습니다. 예를 들어 구성이 앱 간에 일치하는 한 데이터 보호 공급업체에 Redis 또는 Azure Blob Storage를 사용할 수 있습니다. 데이터 보호 키 유지에 대한 자세한 내용은 ASP.NET Core 데이터 보호 구성을 참조하세요.
  • 앱 이름은 ASP.NET Core 앱에서 사용되는 앱 이름과 동일하게 설정됩니다.
  • 인증 유형은 ASP.NET Core 앱의 인증 체계 이름으로 설정됩니다.
  • System.Web.Helpers.AntiForgeryConfig.UniqueClaimTypeIdentifier는 사용자에게 고유한 ASP.NET Core ID의 클레임으로 설정됩니다.

인증 유형이 ASP.NET Core 앱의 인증 체계와 일치하도록 변경되었으므로 ASP.NET 앱이 동일한 이름을 사용하기 위해 새 ID를 생성하는 방법을 업데이트해야 합니다. 이 작업은 일반적으로 Models/IdentityModels.cs에서 수행됩니다.

public class ApplicationUser : IdentityUser
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, "Identity.Application");
        
        // Add custom user claims here
        return userIdentity;
    }
}

이러한 변경으로 ASP.NET 및 ASP.NET Core 앱은 동일한 인증 cookie을 사용하여 한 앱에서 로그인하거나 나가는 사용자가 다른 앱에 반영되도록 할 수 있습니다.

ASP.NET 및 ASP.NET Identity Core Identity의 데이터베이스 스키마 간에는 차이가 있으므로 사용자는 ASP.NET 또는 ASP.NET Core 앱 중 하나를 사용하여 로그인 하는 것이 좋습니다. 사용자가 로그인되면 이 섹션에 설명된 단계를 통해 두 앱에서 인증 cookie 을 사용할 수 있으며 두 앱 모두 사용자를 로그아웃할 수 있어야 합니다.

추가 리소스

다음 예제에서는 다음을 수행합니다.

  • 인증 cookie 이름은 .AspNet.SharedCookie의 공통 값으로 설정됩니다.
  • AuthenticationType은 명시적으로 또는 기본적으로 Identity.Application으로 설정됩니다.
  • 일반적인 앱 이름은 데이터 보호 시스템이 데이터 보호 키(SharedCookieApp)를 공유할 수 있도록 하는 데 사용됩니다.
  • Identity.Application은 인증 체계로 사용됩니다. 어떤 체계가 사용되었든 간에 기본 체계로 사용하거나 명시적으로 설정하여 공유 cookie 앱 내 또는 전체에서 일관되게 사용되어야 합니다. 체계는 cookie를 암호화하고 암호 해독할 때 사용되므로 앱 간에 일관된 체계를 사용해야 합니다.
  • 공통 데이터 보호 키 스토리지 위치가 사용됩니다.
  • DataProtectionProvider 에는 Microsoft.AspNetCore.DataProtection.Extensions NuGet 패키지가 필요합니다.
  • SetApplicationName은 일반적인 앱 이름을 설정합니다.

ASP.NET Core Identity과 인증 cookie 공유

ASP.NET Core Identity을 사용하는 경우:

  • 데이터 보호 키와 앱 이름은 앱 간에 공유되어야 합니다. 공통 키 스토리지 위치는 다음 예제에서 PersistKeysToFileSystem 메서드에 제공됩니다. SetApplicationName을 사용하여 일반적인 공유 앱 이름(다음 예제에서는 SharedCookieApp)을 구성합니다. 자세한 내용은 ASP.NET Core 데이터 보호 구성을 참조하세요.
  • ConfigureApplicationCookie 확장 메서드를 사용하여 cookie에 대한 데이터 보호 서비스를 설정합니다.
  • 기본 인증 유형은 Identity.Application입니다.

Startup.ConfigureServices의 경우

services.AddDataProtection()
    .PersistKeysToFileSystem("{PATH TO COMMON KEY RING FOLDER}")
    .SetApplicationName("SharedCookieApp");

services.ConfigureApplicationCookie(options => {
    options.Cookie.Name = ".AspNet.SharedCookie";
});

참고: 위의 지침은 ITicketStore(CookieAuthenticationOptions.SessionStore)에서 작동하지 않습니다. 자세한 내용은 GitHub 이슈를 참조하세요.

보안상의 이유로 인증 cookie는 ASP.NET Core에서 압축되지 않습니다. 인증 cookie를 사용하는 경우 개발자는 필요에 따라 포함된 클레임 정보 수를 최소화해야 합니다.

ASP.NET Core Identity 없이 인증 cookie 공유

ASP.NET Core Identity를 사용하지 않고 cookie를 직접 사용하는 경우 Startup.ConfigureServices에서 데이터 보호 및 인증을 구성합니다. 다음 예제에서 인증 유형은 Identity.Application으로 설정됩니다.

services.AddDataProtection()
    .PersistKeysToFileSystem("{PATH TO COMMON KEY RING FOLDER}")
    .SetApplicationName("SharedCookieApp");

services.AddAuthentication("Identity.Application")
    .AddCookie("Identity.Application", options =>
    {
        options.Cookie.Name = ".AspNet.SharedCookie";
    });

보안상의 이유로 인증 cookie는 ASP.NET Core에서 압축되지 않습니다. 인증 cookie를 사용하는 경우 개발자는 필요에 따라 포함된 클레임 정보 수를 최소화해야 합니다.

여러 기본 경로에서 cookie 공유

인증 cookie는 기본 Cookie.PathHttpRequest.PathBase를 사용합니다. 앱의 cookie를 서로 다른 기본 경로에서 공유해야 하는 경우 Path를 재정의해야 합니다.

services.AddDataProtection()
    .PersistKeysToFileSystem("{PATH TO COMMON KEY RING FOLDER}")
    .SetApplicationName("SharedCookieApp");

services.ConfigureApplicationCookie(options => {
    options.Cookie.Name = ".AspNet.SharedCookie";
    options.Cookie.Path = "/";
});

하위 도메인에서 cookie 공유

여러 하위 도메인에서 cookie를 공유하는 앱을 호스팅하는 경우 Cookie.Domain 속성에서 공용 도메인을 지정합니다. contoso.com에서 앱 간에 cookie를 공유하려면(예: first_subdomain.contoso.comsecond_subdomain.contoso.com) Cookie.Domain.contoso.com으로 지정합니다.

options.Cookie.Domain = ".contoso.com";

미사용 데이터 보호 키 암호화

프로덕션 배포의 경우 DPAPI 또는 X509Certificate를 사용하여 미사용 키를 암호화하도록 DataProtectionProvider를 구성합니다. 자세한 내용은 ASP.NET Core를 사용하여 Windows 및 Azure에서 미사용 키 암호화를 참조하세요. 다음 예제에서는 인증서 지문이 ProtectKeysWithCertificate에 제공됩니다.

services.AddDataProtection()
    .ProtectKeysWithCertificate("{CERTIFICATE THUMBPRINT}");

ASP.NET 4.x 및 ASP.NET Core 앱 간에 인증 cookie 공유

Katana Cookie 인증 미들웨어를 사용하는 ASP.NET 4.x 앱은 ASP.NET Core Cookie 인증 미들웨어와 호환되는 인증 cookie를 생성하도록 구성될 수 있습니다. 자세한 내용은 ASP.NET 4.x 및 ASP.NET Core 앱(dotnet/AspNetCore.Docs #21987) 간의 인증 cookie 공유를 참조하세요.

일반 사용자 데이터베이스 사용

앱에서 동일한 Identity 스키마(동일한 버전의 Identity)를 사용하는 경우 각 앱의 Identity 시스템이 동일한 사용자 데이터베이스를 가리키는지 확인합니다. 그렇지 않으면 ID 시스템은 해당 데이터베이스의 정보와 인증 cookie의 정보를 일치시키려고 할 때 런타임 시 오류를 생성합니다.

일반적으로 앱이 서로 다른 Identity 버전을 사용하므로 앱 간에 Identity 스키마가 다른 경우 다른 앱의 Identity 스키마에 열을 다시 매핑하고 추가하지 않고는 최신 버전의 Identity를 기반으로 공통 데이터베이스를 공유할 수 없습니다. 일반적으로 앱에서 공통 데이터베이스를 공유할 수 있도록 최신 Identity 버전을 사용하도록 다른 앱을 업그레이드하는 것이 더 효율적입니다.

추가 리소스