프록시 서버 및 부하 분산 장치를 사용하도록 ASP.NET Core 구성
참고 항목
이 문서의 최신 버전은 아닙니다. 현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.
Important
이 정보는 상업적으로 출시되기 전에 실질적으로 수정될 수 있는 시험판 제품과 관련이 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적, 또는 묵시적인 보증을 하지 않습니다.
현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.
작성자: Chris Ross
ASP.NET Core 권장 구성에서 앱은 IIS용 ANCM(ASP.NET Core 모듈), Nginx 또는 Apache를 사용하여 호스트됩니다. 프록시 서버, 부하 분산 장치 및 기타 네트워크 어플라이언스는 종종 앱에 도달하기 전에 요청에 대한 정보를 숨깁니다.
- HTTPS 요청이 HTTP를 통해 프록시된 경우 원래 스키마(HTTPS)가 손실되므로 헤더에서 전달되어야 합니다.
- 앱은 프록시에서 요청을 수신하고 인터넷 또는 회사 네트워크의 실제 소스를 수신하는 것이 아니므로 원래 클라이언트 IP 주소도 헤더에서 전달되어야 합니다.
이 정보는 요청 처리 시 중요할 수 있습니다(예: 리디렉션, 인증, 링크 생성, 정책 평가 및 클라이언트 지리적 위치).
웹 팜에서 실행하려는 앱은 웹 팜의 Host ASP.NET Core를 읽어야 합니다.
전달된 헤더
규칙에 따라 프록시는 HTTP 헤더에서 정보를 전달합니다.
헤더 | 설명 |
---|---|
X-Forwarded-For (XFF) |
요청 및 프록시 체인의 후속 프록시를 시작한 클라이언트에 대한 정보를 포함합니다. 이 매개 변수에는 IP 주소(및 선택적으로 포트 번호)가 포함될 수 있습니다. 프록시 서버의 체인에서 첫 번째 매개 변수는 요청이 처음 만들어진 클라이언트를 나타냅니다. 그 뒤에 후속 프록시 식별자가 추가됩니다. 체인의 마지막 프록시는 매개 변수 목록에 없습니다. 마지막 프록시의 IP 주소 및 선택적으로 포트 번호는 전송 계층에서 원격 IP 주소로 사용할 수 있습니다. |
X-Forwarded-Proto (XFP) |
원래 체계의 값입니다(HTTP 또는 HTTPS). 요청이 여러 프록시를 트래버스한 경우에는 값이 체계 목록일 수도 있습니다. |
X-Forwarded-Host (XFH) |
호스트 헤더 필드의 원래 값입니다. 일반적으로 프록시는 호스트 헤더를 수정하지 않습니다. 프록시가 호스트 헤더를 유효성 검사하거나 알려진 정상 값으로 제한하지 않는 시스템에 영향을 미치는 권한 상승 취약성에 대한 자세한 내용은 Microsoft 보안 공지 CVE-2018-0787을 참조하세요. |
X-Forwarded-Prefix |
클라이언트에서 요청한 원래 기본 경로입니다. 이 헤더는 애플리케이션이 URL, 리디렉션 또는 다시 클라이언트에 대한 링크를 올바르게 생성하는 데 유용할 수 있습니다. |
전달된 헤더 미들웨어(ForwardedHeadersMiddleware)는 이러한 헤더를 읽고 HttpContext의 연결된 필드를 채웁니다.
미들웨어가 다음을 업데이트합니다.
HttpContext.Connection.RemoteIpAddress
: 헤더 값을 사용하여X-Forwarded-For
설정합니다. 추가 설정은 미들웨어가RemoteIpAddress
를 설정하는 방법에 영향을 줍니다. 자세한 내용은 전달된 헤더 미들웨어 옵션을 참조하세요. 사용된 값은 제거X-Forwarded-For
되고 이전 값HttpContext.Connection.RemoteIpAddress
은 에X-Original-For
유지됩니다. 참고: 이 프로세스는 여러 값이 있는X-Forwarded-For/Proto/Host/Prefix
경우 여러 번 반복되어 원래RemoteIpAddress/Host/Scheme/PathBase
값을 포함하여 여러 값이 이동X-Original-*
될 수 있습니다.HttpContext.Request.Scheme
: 헤더 값을 사용하여X-Forwarded-Proto
설정합니다. 사용된 값이 제거되고X-Forwarded-Proto
이전 값HttpContext.Request.Scheme
이 유지됩니다X-Original-Proto
.HttpContext.Request.Host
: 헤더 값을 사용하여X-Forwarded-Host
설정합니다. 사용된 값이 제거되고X-Forwarded-Host
이전 값HttpContext.Request.Host
이 유지됩니다X-Original-Host
.HttpContext.Request.PathBase
: 헤더 값을 사용하여X-Forwarded-Prefix
설정합니다. 사용된 값이 제거되고X-Forwarded-Prefix
이전 값HttpContext.Request.PathBase
이 유지됩니다X-Original-Prefix
.
이전 내용에 대한 자세한 정보는 이 GitHub 문제를 참조하세요.
전달된 헤더 미들웨어 기본 설정을 구성할 수 있습니다. 기본 설정의 경우:
- 앱과 요청 소스 사이에는 하나의 프록시만 있습니다.
- 알려진 프록시 및 알려진 네트워크의 경우 루프백 주소만 구성됩니다.
- 전달된 헤더의 이름은
X-Forwarded-For
< a0/X-Forwarded-Host
X-Forwarded-Proto
>입니다X-Forwarded-Prefix
. ForwardedHeaders
값이ForwardedHeaders.None
인 경우 미들웨어를 사용하도록 설정하려면 여기에서 원하는 전달자를 설정해야 합니다.
일부 네트워크 어플라이언스는 X-Forwarded-For
및 X-Forwarded-Proto
헤더를 추가하려면 추가 구성이 필요합니다. 프록시된 요청이 앱에 도달할 때 이러한 헤더를 포함하지 않는 경우에는 어플라이언스 제조업체의 지침을 참조하세요. 어플라이언스가 X-Forwarded-For
및 X-Forwarded-Proto
와는 다른 헤더 이름을 사용하는 경우 ForwardedForHeaderName 및 ForwardedProtoHeaderName 옵션을 어플라이언스에서 사용하는 헤더 이름과 일치하도록 설정합니다. 자세한 내용은 전달된 헤더 미들웨어 옵션 및 다른 헤더 이름을 사용하는 프록시 구성을 참조하세요.
IIS/IIS Express 및 ASP.NET Core 모듈
앱이 IIS 및 IIS용 ANCM(ASP.NET Core 모듈) 뒤에서 호스트되는 Out of Process인 경우 전달된 헤더 미들웨어가 IIS 통합 미들웨어에 의해 기본적으로 사용하도록 설정됩니다. 전달된 헤더 미들웨어는 ASP.NET Core 모듈에 고유한 제한된 구성으로 미들웨어 파이프라인에서 먼저 실행되도록 활성화됩니다. 제한된 구성은 전달된 헤더(예: IP 스푸핑)의 신뢰 문제로 인해 발생합니다. 미들웨어는 X-Forwarded-For
및 X-Forwarded-Proto
헤더를 전달하도록 구성되고 단일 localhost 프록시로 제한됩니다. 추가 구성이 필요한 경우 전달된 헤더 미들웨어 옵션을 참조하세요.
기타 프록시 서버 및 부하 분산 장치 시나리오
Out of Process 호스트할 때 IIS 통합 사용 외에는 전달된 헤더 미들웨어가 기본적으로 사용하도록 설정되지 않습니다. 앱에서 UseForwardedHeaders를 사용하여 전달된 헤더를 처리하려면 전달된 헤더 미들웨어를 사용하도록 설정해야 합니다. 미들웨어를 사용하도록 설정한 후 미들웨어에 ForwardedHeadersOptions를 지정하지 않은 경우 기본 ForwardedHeadersOptions.ForwardedHeaders는 ForwardedHeaders.None입니다.
ForwardedHeadersOptions를 사용하여 X-Forwarded-For
및 X-Forwarded-Proto
헤더를 전달하도록 미들웨어를 구성합니다.
전달된 헤더 미들웨어 순서
전달된 헤더 미들웨어는 다른 미들웨어보다 먼저 실행해야 합니다. 이 순서를 지정하면 전달된 헤더 정보에 따라 달라지는 미들웨어는 처리하기 위해 헤더 값을 사용할 수 있습니다. 전달된 헤더 미들웨어는 진단 및 오류 처리 뒤에 실행될 수 있지만 UseHsts를 호출하기 전에 실행되어야 합니다.
using Microsoft.AspNetCore.HttpOverrides;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseForwardedHeaders();
app.UseHsts();
}
else
{
app.UseDeveloperExceptionPage();
app.UseForwardedHeaders();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
또는 진단 전에 UseForwardedHeaders
를 호출합니다.
using Microsoft.AspNetCore.HttpOverrides;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
var app = builder.Build();
app.UseForwardedHeaders();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
참고 항목
ForwardedHeadersOptions를 지정하지 않거나 UseForwardedHeaders를 사용하여 확장 메서드에 직접 적용하지 않은 경우 전달할 기본 헤더는 ForwardedHeaders.None입니다. 전달할 헤더를 사용하여 ForwardedHeaders 속성을 구성해야 합니다.
Nginx 구성
X-Forwarded-For
및 X-Forwarded-Proto
헤더를 전달하려면 Nginx를 사용하여 Linux에서 ASP.NET Core 호스트를 참조하세요. 자세한 내용은 NGINX: 전달된 헤더 사용을 참조하세요.
Apache 구성
X-Forwarded-For
가 자동으로 추가됩니다. 자세한 내용은 Apache 모듈 mod_proxy: 역방향 프록시 요청 헤더를 참조하세요.
전달된 헤더 미들웨어 옵션
ForwardedHeadersOptions는 전달된 헤더 미들웨어의 동작을 제어합니다. 다음 예제에서는 기본값을 변경합니다.
- 전달된 헤더의 항목 수를
2
로 제한합니다. 127.0.10.1
의 알려진 프록시 주소를 추가합니다.- 전달된 헤더 이름을 기본값
X-Forwarded-For
에서X-Forwarded-For-My-Custom-Header-Name
으로 변경합니다.
using System.Net;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardLimit = 2;
options.KnownProxies.Add(IPAddress.Parse("127.0.10.1"));
options.ForwardedForHeaderName = "X-Forwarded-For-My-Custom-Header-Name";
});
var app = builder.Build();
app.UseForwardedHeaders();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
옵션 | 설명 |
---|---|
AllowedHosts | X-Forwarded-Host 헤더에 의한 호스트를 제공된 값으로 제한합니다.
IList<string> 입니다. |
ForwardedForHeaderName | ForwardedHeadersDefaults.XForwardedForHeaderName에서 지정된 헤더 대신 이 속성에서 지정된 헤더를 사용합니다. 이 옵션은 프록시/전달자가 X-Forwarded-For 헤더를 사용하지 않고 일부 다른 헤더를 사용하여 정보를 전달할 때 사용됩니다.기본값은 X-Forwarded-For 입니다. |
ForwardedHeaders | 처리해야 할 전달자를 알려줍니다. 적용되는 필드 목록은 ForwardedHeaders 열거형을 참조하세요. 이 속성에 할당된 일반적인 값은 ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto 입니다.기본값은 ForwardedHeaders.None입니다. |
ForwardedHostHeaderName | ForwardedHeadersDefaults.XForwardedHostHeaderName에서 지정된 헤더 대신 이 속성에서 지정된 헤더를 사용합니다. 이 옵션은 프록시/전달자가 X-Forwarded-Host 헤더를 사용하지 않고 일부 다른 헤더를 사용하여 정보를 전달할 때 사용됩니다.기본값은 X-Forwarded-Host 입니다. |
ForwardedProtoHeaderName | ForwardedHeadersDefaults.XForwardedProtoHeaderName에서 지정된 헤더 대신 이 속성에서 지정된 헤더를 사용합니다. 이 옵션은 프록시/전달자가 X-Forwarded-Proto 헤더를 사용하지 않고 일부 다른 헤더를 사용하여 정보를 전달할 때 사용됩니다.기본값은 X-Forwarded-Proto 입니다. |
ForwardLimit | 처리되는 헤더의 항목 수를 제한합니다. 제한을 사용하지 않도록 null 로 설정하지만, KnownProxies 또는 KnownNetworks 가 구성된 경우에만 사용해야 합니다. 비값null 설정은 네트워크의 사이드 채널에서 도착하는 잘못 구성된 프록시 및 악의적인 요청으로부터 보호하기 위한 예방 조치(보장은 아님)입니다.전달된 헤더 미들웨어는 헤더를 역순으로 오른쪽에서 왼쪽으로 처리합니다. 기본값( 1 )만 사용된다면 ForwardLimit 의 값을 늘리지 않는 한, 헤더에서 맨 오른쪽 값만 처리됩니다.기본값은 1 입니다. |
KnownNetworks | 전달된 헤더를 허용하기 위한 알려진 네트워크의 주소 범위입니다. CIDR(Classless Interdomain Routing) 표기법을 사용하여 IP 범위를 제공합니다. 서버에서 이중 모드 소켓을 사용하는 경우 IPv4 주소가 IPv6 형식(예: IPv4에서 10.0.0.1 은 IPv6에서 ::ffff:10.0.0.1 로 표시됨)으로 제공됩니다. IPAddress.MapToIPv6를 참조하세요. HttpContext.Connection.RemoteIpAddress를 참조하여 이 형식이 필요한지 확인하세요.기본값은 new IPNetwork(IPAddress.Loopback, 8) 에 대한 단일 항목을 포함하는 IList <IPNetwork>입니다. |
KnownProxies | 전달된 헤더를 허용하기 위한 알려진 프록시의 주소입니다. KnownProxies 를 사용하여 정확한 IP 주소 일치 항목을 지정합니다.서버에서 이중 모드 소켓을 사용하는 경우 IPv4 주소가 IPv6 형식(예: IPv4에서 10.0.0.1 은 IPv6에서 ::ffff:10.0.0.1 로 표시됨)으로 제공됩니다. IPAddress.MapToIPv6를 참조하세요. HttpContext.Connection.RemoteIpAddress를 참조하여 이 형식이 필요한지 확인하세요.기본값은 IPAddress.IPv6Loopback 에 대한 단일 항목을 포함하는 IList <IPAddress>입니다. |
OriginalForHeaderName | ForwardedHeadersDefaults.XOriginalForHeaderName에서 지정된 헤더 대신 이 속성에서 지정된 헤더를 사용합니다. 기본값은 X-Original-For 입니다. |
OriginalHostHeaderName | ForwardedHeadersDefaults.XOriginalHostHeaderName에서 지정된 헤더 대신 이 속성에서 지정된 헤더를 사용합니다. 기본값은 X-Original-Host 입니다. |
OriginalProtoHeaderName | ForwardedHeadersDefaults.XOriginalProtoHeaderName에서 지정된 헤더 대신 이 속성에서 지정된 헤더를 사용합니다. 기본값은 X-Original-Proto 입니다. |
RequireHeaderSymmetry | 처리 중인 ForwardedHeadersOptions.ForwardedHeaders 간에 동기화할 헤더 값 수가 필요합니다. ASP.NET Core 1.x의 기본값은 true 입니다. ASP.NET Core 2.0 이상의 기본값은 false 입니다. |
시나리오 및 사용 사례
전달된 헤더를 추가할 수 없고 모든 요청이 안전한 경우
일부 경우에는 앱으로 프록시된 요청에 전달된 헤더를 추가할 수 없습니다. 모든 공용 외부 요청이 HTTPS가 되도록 프록시가 적용되는 경우 미들웨어를 사용하기 전에 체계를 수동으로 설정할 수 있습니다.
using Microsoft.AspNetCore.HttpOverrides;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
var app = builder.Build();
app.Use((context, next) =>
{
context.Request.Scheme = "https";
return next(context);
});
app.UseForwardedHeaders();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
이 코드는 개발 또는 스테이징 환경에서 환경 변수 또는 기타 구성 설정을 통해 사용하지 않도록 설정될 수 있습니다.
using Microsoft.AspNetCore.HttpOverrides;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
var app = builder.Build();
if (!app.Environment.IsProduction())
{
app.Use((context, next) =>
{
context.Request.Scheme = "https";
return next(context);
});
}
app.UseForwardedHeaders();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
요청 경로를 변경하는 경로 기준 및 프록시 작업
일부 프록시는 경로를 그대로 전달하지만 라우팅이 제대로 작동하도록 제거해야 하는 앱 기본 경로를 포함합니다. UsePathBaseExtensions.UsePathBase 미들웨어는 경로를 HttpRequest.Path로 분할하고 앱 기본 경로를 HttpRequest.PathBase로 분할합니다.
/foo
가 /foo/api/1
로 전달되는 프록시 경로의 앱 기본 경로인 경우 미들웨어는 다음 명령을 사용하여 Request.PathBase
를 /foo
로 설정하고 Request.Path
를 /api/1
로 설정합니다.
app.UsePathBase("/foo");
// ...
app.UseRouting();
참고 항목
WebApplication(ASP.NET Core 5.0에서 6.0으로 마이그레이션 참조)을 사용할 때 라우팅 미들웨어가 경로 일치 전에 수정된 경로를 관찰할 수 있도록 UsePathBase
이후 app.UseRouting
을 호출해야 합니다. 그렇지 않은 경우 미들웨어 순서 지정 및 라우팅 문서에서 설명하는 것과 같이 UsePathBase
에서 경로를 다시 작성하기 전에 경로가 일치합니다.
미들웨어가 역방향으로 다시 호출되면 원래 경로 및 경로 기준이 다시 적용됩니다. 미들웨어 순서 처리에 대한 자세한 내용은 ASP.NET Core 미들웨어를 참조하세요.
프록시가 경로를 자르는 경우(예: /foo/api/1
을 /api/1
에 전달) 요청의 PathBase 속성을 설정하여 리디렉션 및 링크를 수정합니다.
app.Use((context, next) =>
{
context.Request.PathBase = new PathString("/foo");
return next(context);
});
프록시가 경로 데이터를 추가하는 경우 경로의 일부를 삭제한 다음, StartsWithSegments를 사용하고 Path 속성에 할당하여 리디렉션 및 링크를 수정합니다.
app.Use((context, next) =>
{
if (context.Request.Path.StartsWithSegments("/foo", out var remainder))
{
context.Request.Path = remainder;
}
return next(context);
});
다른 헤더 이름을 사용하는 프록시에 대한 구성
프록시가 X-Forwarded-For
및 X-Forwarded-Proto
라는 헤더를 사용하여 프록시 주소/포트 및 원래 체계 정보를 전달하지 않는 경우, ForwardedForHeaderName 및 ForwardedProtoHeaderName 옵션을 프록시에서 사용하는 헤더 이름과 일치하도록 설정합니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedForHeaderName = "HeaderNamUsedByProxy_X-Forwarded-For_Header";
options.ForwardedProtoHeaderName = "HeaderNamUsedByProxy_X-Forwarded-Proto_Header";
});
var app = builder.Build();
app.UseForwardedHeaders();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
Linux용 스키마 및 비 IIS 역방향 프록시 전달
UseHttpsRedirection 및 UseHsts을(를) 호출하는 앱은 Azure Linux App Service, Azure Linux VM(가상 머신) 또는 IIS 이외의 다른 역방향 프록시 뒤에 배포된 경우 사이트를 무한 루프에 배치합니다. TLS는 역방향 프록시에 의해 종료되며, Kestrel은 올바른 요청 체계를 인식하지 못합니다. OAuth 및 OIDC도 잘못된 리디렉션을 생성하므로 이 구성에서 실패합니다. UseIISIntegration은 IIS 뒤에서 실행되는 경우 전달된 헤더 미들웨어를 추가하고 구성하지만 Linux에 대한 일치하는 자동 구성이 없습니다(Apache 또는 Nginx 통합).
비 IIS 시나리오에서 프록시의 스키마를 전달하려면, ASPNETCORE_FORWARDEDHEADERS_ENABLED
를 true
로 설정하여 전달된 헤더 미들웨어를 사용하도록 설정합니다. 경고: 이 플래그는 클라우드 환경용으로 설계된 설정을 사용하며, 허용되는 IP 전달자를 제한하기 위해 KnownProxies option
등의 기능을 사용하도록 설정하지 않습니다.
인증서 전달
Azure
인증서 전달에 대한 Azure App Service를 구성하려면 Azure App Service에 대한 TLS 상호 인증 구성을 참조하세요. 다음 지침은 ASP.NET Core 앱 구성과 관련됩니다.
- 인증서 전달 미들웨어를 구성하여 Azure를 사용하는 헤더 이름을 지정합니다. 다음 코드를 추가하여 미들웨어가 인증서를 빌드하는 헤더를 구성합니다.
- UseAuthentication을 호출하기 전에 UseCertificateForwarding을 호출합니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddCertificateForwarding(options =>
options.CertificateHeader = "X-ARR-ClientCert");
var app = builder.Build();
app.UseCertificateForwarding();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthorization();
app.UseAuthentication();
app.MapRazorPages();
app.Run();
다른 웹 프록시
IIS 또는 Azure App Service의 ARR(애플리케이션 요청 라우팅)이 아닌 프록시를 사용하는 경우 HTTP 헤더에서 받은 인증서를 전달하도록 프록시를 구성합니다.
- 인증서 전달 미들웨어를 구성하여 헤더 이름을 지정합니다. 다음 코드를 추가하여 미들웨어가 인증서를 빌드하는 헤더를 구성합니다.
- UseAuthentication을 호출하기 전에 UseCertificateForwarding을 호출합니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddCertificateForwarding(options =>
options.CertificateHeader = "YOUR_CERTIFICATE_HEADER_NAME");
var app = builder.Build();
app.UseCertificateForwarding();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthorization();
app.UseAuthentication();
app.MapRazorPages();
app.Run();
프록시가 Nginx에서와 같이 인증서를 base64 인코딩하지 않는 경우 HeaderConverter
옵션을 설정합니다. 다음 예시를 참조하세요.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddCertificateForwarding(options =>
{
options.CertificateHeader = "YOUR_CUSTOM_HEADER_NAME";
options.HeaderConverter = (headerValue) =>
{
// Conversion logic to create an X509Certificate2.
var clientCertificate = ConversionLogic.CreateAnX509Certificate2();
return clientCertificate;
};
});
var app = builder.Build();
app.UseCertificateForwarding();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthorization();
app.UseAuthentication();
app.MapRazorPages();
app.Run();
문제 해결
헤더가 예상대로 전달되지 않으면 debug
수준 로깅 및 HTTP 요청 로깅을 사용하도록 설정합니다. UseHttpLogging은 UseForwardedHeaders 이후에 호출해야 합니다.
using Microsoft.AspNetCore.HttpLogging;
using Microsoft.AspNetCore.HttpOverrides;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddHttpLogging(options =>
{
options.LoggingFields = HttpLoggingFields.RequestPropertiesAndHeaders;
});
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
var app = builder.Build();
app.UseForwardedHeaders();
app.UseHttpLogging();
app.Use(async (context, next) =>
{
// Connection: RemoteIp
app.Logger.LogInformation("Request RemoteIp: {RemoteIpAddress}",
context.Connection.RemoteIpAddress);
await next(context);
});
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
제공된 헤더에 여러 값이 있는 경우 전달된 헤더 미들웨어는 오른쪽에서 왼쪽으로 역순으로 헤더를 처리합니다. 기본 ForwardLimit
는 1
(일)이므로 ForwardLimit
의 값을 늘리지 않는 한, 헤더에서 맨 오른쪽 값만 처리됩니다.
요청의 원래 원격 IP는 전달된 헤더가 처리되기 전에 KnownProxies 또는 KnownNetworks 목록의 항목과 일치해야 합니다. 이렇게 하면 신뢰할 수 없는 프록시에서 전달자가 허용되지 않아 헤더 스푸핑이 제한됩니다. 알 수 없는 프록시가 검색되면 로그에 프록시 주소가 기록됩니다.
September 20th 2018, 15:49:44.168 Unknown proxy: 10.0.0.100:54321
앞의 예제에서 10.0.0.100은 프록시 서버입니다. 서버가 신뢰할 수 있는 프록시인 경우 서버의 IP 주소를 KnownProxies
에 추가합니다. 또는 신뢰할 수 있는 네트워크를 KnownNetworks
에 추가합니다. 자세한 내용은 전달된 헤더 미들웨어 옵션 섹션을 참조하세요.
using Microsoft.AspNetCore.HttpOverrides;
using System.Net;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
options.KnownProxies.Add(IPAddress.Parse("10.0.0.100"));
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseForwardedHeaders();
app.UseHsts();
}
else
{
app.UseDeveloperExceptionPage();
app.UseForwardedHeaders();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
로그를 표시하기 위해 "Microsoft.AspNetCore.HttpLogging": "Information"
을 appsettings.Development.json
파일에 추가합니다.
{
"DetailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.AspNetCore.HttpLogging": "Information"
}
}
}
Important
신뢰할 수 있는 프록시 및 네트워크만 헤더를 전달할 수 있습니다. 그렇지 않을 경우 IP 스푸핑 공격이 가능합니다.
추가 리소스
- 웹 팜에서 ASP.NET Core 호스트
- Microsoft Security Advisory CVE-2018-0787: ASP.NET Core Elevation Of Privilege Vulnerability(Microsoft 보안 공지 CVE-2018-0787: ASP.NET Core 권한 상승 취약성)
- YARP: 또 다른 역방향 프록시
ASP.NET Core의 권장 구성에서 앱은 IIS/ASP.NET Core 모듈, Nginx 또는 Apache를 사용하여 호스트됩니다. 프록시 서버, 부하 분산 장치 및 기타 네트워크 어플라이언스는 종종 앱에 도달하기 전에 요청에 대한 정보를 숨깁니다.
- HTTPS 요청이 HTTP를 통해 프록시된 경우 원래 스키마(HTTPS)가 손실되므로 헤더에서 전달되어야 합니다.
- 앱은 프록시에서 요청을 수신하고 인터넷 또는 회사 네트워크의 실제 소스를 수신하는 것이 아니므로 원래 클라이언트 IP 주소도 헤더에서 전달되어야 합니다.
이 정보는 요청 처리 시 중요할 수 있습니다(예: 리디렉션, 인증, 링크 생성, 정책 평가 및 클라이언트 지리적 위치).
전달된 헤더
규칙에 따라 프록시는 HTTP 헤더에서 정보를 전달합니다.
헤더 | 설명 |
---|---|
X-Forwarded-For | 요청 및 프록시 체인의 후속 프록시를 시작한 클라이언트에 대한 정보를 포함합니다. 이 매개 변수에는 IP 주소(및 선택적으로 포트 번호)가 포함될 수 있습니다. 프록시 서버의 체인에서 첫 번째 매개 변수는 요청이 처음 만들어진 클라이언트를 나타냅니다. 그 뒤에 후속 프록시 식별자가 추가됩니다. 체인의 마지막 프록시는 매개 변수 목록에 없습니다. 마지막 프록시의 IP 주소 및 선택적으로 포트 번호는 전송 계층에서 원격 IP 주소로 사용할 수 있습니다. |
X-Forwarded-Proto | 원래 체계(HTTP/HTTPS)의 값입니다. 요청이 여러 프록시를 트래버스한 경우에는 값이 체계 목록일 수도 있습니다. |
X-Forwarded-Host | 호스트 헤더 필드의 원래 값입니다. 일반적으로 프록시는 호스트 헤더를 수정하지 않습니다. 프록시가 호스트 헤더를 유효성 검사하거나 알려진 정상 값으로 제한하지 않는 시스템에 영향을 미치는 권한 상승 취약성에 대한 자세한 내용은 Microsoft 보안 공지 CVE-2018-0787을 참조하세요. |
전달된 헤더 미들웨어(ForwardedHeadersMiddleware)는 헤더를 읽고 HttpContext의 관련 필드를 채웁니다.
미들웨어가 다음을 업데이트합니다.
- HttpContext.Connection.RemoteIpAddress:
X-Forwarded-For
헤더 값을 사용하여 설정합니다. 추가 설정은 미들웨어가RemoteIpAddress
를 설정하는 방법에 영향을 줍니다. 자세한 내용은 전달된 헤더 미들웨어 옵션을 참조하세요. 사용된 값은X-Forwarded-For
에서 제거되고 이전 값은X-Original-For
에 유지됩니다. 동일한 패턴이 다른 헤더Host
및Proto
에 적용됩니다. - HttpContext.Request.Scheme:
X-Forwarded-Proto
헤더 값을 사용하여 설정합니다. - HttpContext.Request.Host:
X-Forwarded-Host
헤더 값을 사용하여 설정합니다.
이전 내용에 대한 자세한 정보는 이 GitHub 문제를 참조하세요.
전달된 헤더 미들웨어 기본 설정을 구성할 수 있습니다. 기본 설정의 경우:
- 앱과 요청 소스 사이에는 하나의 프록시만 있습니다.
- 알려진 프록시 및 알려진 네트워크의 경우 루프백 주소만 구성됩니다.
- 전달된 헤더의 이름은
X-Forwarded-For
및X-Forwarded-Proto
입니다. ForwardedHeaders
값이ForwardedHeaders.None
인 경우 미들웨어를 사용하도록 설정하려면 여기에서 원하는 전달자를 설정해야 합니다.
일부 네트워크 어플라이언스는 X-Forwarded-For
및 X-Forwarded-Proto
헤더를 추가하려면 추가 구성이 필요합니다. 프록시된 요청이 앱에 도달할 때 이러한 헤더를 포함하지 않는 경우에는 어플라이언스 제조업체의 지침을 참조하세요. 어플라이언스가 X-Forwarded-For
및 X-Forwarded-Proto
와는 다른 헤더 이름을 사용하는 경우 ForwardedForHeaderName 및 ForwardedProtoHeaderName 옵션을 어플라이언스에서 사용하는 헤더 이름과 일치하도록 설정합니다. 자세한 내용은 전달된 헤더 미들웨어 옵션 및 다른 헤더 이름을 사용하는 프록시 구성을 참조하세요.
IIS/IIS Express 및 ASP.NET Core 모듈
앱이 IIS 및 ASP.NET Core 모듈 뒤에서 호스트되는 Out of Process인 경우 전달된 헤더 미들웨어가 IIS 통합 미들웨어에 의해 기본적으로 사용하도록 설정됩니다. 전달된 헤더 미들웨어는 전달된 헤더 관련 신뢰 문제(예: IP 스푸핑)로 인해 ASP.NET Core 모듈에 특정한 제한된 구성을 사용하여 미들웨어 파이프라인에서 첫 번째로 실행될 수 있도록 활성화됩니다. 미들웨어는 X-Forwarded-For
및 X-Forwarded-Proto
헤더를 전달하도록 구성되고 단일 localhost 프록시로 제한됩니다. 추가 구성이 필요한 경우 전달된 헤더 미들웨어 옵션을 참조하세요.
기타 프록시 서버 및 부하 분산 장치 시나리오
Out of Process를 호스트할 때 IIS 통합 사용 외에는 전달된 헤더 미들웨어가 기본적으로 사용하도록 설정되지 않습니다. 앱에서 UseForwardedHeaders를 사용하여 전달된 헤더를 처리하려면 전달된 헤더 미들웨어를 사용하도록 설정해야 합니다. 미들웨어를 사용하도록 설정한 후 미들웨어에 ForwardedHeadersOptions를 지정하지 않은 경우 기본 ForwardedHeadersOptions.ForwardedHeaders는 ForwardedHeaders.None입니다.
ForwardedHeadersOptions를 사용하여 Startup.ConfigureServices
의 X-Forwarded-For
및 X-Forwarded-Proto
헤더를 전달하도록 미들웨어를 구성합니다.
전달된 헤더 미들웨어 순서
전달된 헤더 미들웨어는 다른 미들웨어보다 먼저 실행해야 합니다. 이 순서를 지정하면 전달된 헤더 정보에 따라 달라지는 미들웨어는 처리하기 위해 헤더 값을 사용할 수 있습니다. 전달된 헤더 미들웨어는 진단 및 오류 처리 뒤에 실행될 수 있지만 UseHsts
를 호출하기 전에 실행되어야 합니다.
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseForwardedHeaders();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseForwardedHeaders();
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
또는 진단 전에 UseForwardedHeaders
를 호출합니다.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseForwardedHeaders();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
참고 항목
Startup.ConfigureServices
에서 ForwardedHeadersOptions를 지정하지 않거나 UseForwardedHeaders를 사용하여 확장 메서드에 직접 지정하지 않은 경우 전달할 기본 헤더는 ForwardedHeaders.None입니다. 전달할 헤더를 사용하여 ForwardedHeaders 속성을 구성해야 합니다.
Nginx 구성
X-Forwarded-For
및 X-Forwarded-Proto
헤더를 전달하려면 Nginx를 사용하여 Linux에서 ASP.NET Core 호스트를 참조하세요. 자세한 내용은 NGINX: 전달된 헤더 사용을 참조하세요.
Apache 구성
X-Forwarded-For
가 자동으로 추가됩니다( Apache 모듈 mod_proxy: 역방향 프록시 요청 헤더 참조).
전달된 헤더 미들웨어 옵션
ForwardedHeadersOptions는 전달된 헤더 미들웨어의 동작을 제어합니다. 다음 예제에서는 기본값을 변경합니다.
- 전달된 헤더의 항목 수를
2
로 제한합니다. 127.0.10.1
의 알려진 프록시 주소를 추가합니다.- 전달된 헤더 이름을 기본값
X-Forwarded-For
에서X-Forwarded-For-My-Custom-Header-Name
으로 변경합니다.
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardLimit = 2;
options.KnownProxies.Add(IPAddress.Parse("127.0.10.1"));
options.ForwardedForHeaderName = "X-Forwarded-For-My-Custom-Header-Name";
});
옵션 | 설명 |
---|---|
AllowedHosts | X-Forwarded-Host 헤더에 의한 호스트를 제공된 값으로 제한합니다.
IList<string> 입니다. |
ForwardedHeaders | 처리해야 할 전달자를 알려줍니다. 적용되는 필드 목록은 ForwardedHeaders 열거형을 참조하세요. 이 속성에 할당된 일반적인 값은 ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto 입니다.기본값은 ForwardedHeaders.None입니다. |
ForwardedForHeaderName | ForwardedHeadersDefaults.XForwardedForHeaderName에서 지정된 헤더 대신 이 속성에서 지정된 헤더를 사용합니다. 이 옵션은 프록시/전달자가 X-Forwarded-For 헤더를 사용하지 않고 일부 다른 헤더를 사용하여 정보를 전달할 때 사용됩니다.기본값은 X-Forwarded-For 입니다. |
ForwardedHostHeaderName | ForwardedHeadersDefaults.XForwardedHostHeaderName에서 지정된 헤더 대신 이 속성에서 지정된 헤더를 사용합니다. 이 옵션은 프록시/전달자가 X-Forwarded-Host 헤더를 사용하지 않고 일부 다른 헤더를 사용하여 정보를 전달할 때 사용됩니다.기본값은 X-Forwarded-Host 입니다. |
ForwardedProtoHeaderName | ForwardedHeadersDefaults.XForwardedProtoHeaderName에서 지정된 헤더 대신 이 속성에서 지정된 헤더를 사용합니다. 이 옵션은 프록시/전달자가 X-Forwarded-Proto 헤더를 사용하지 않고 일부 다른 헤더를 사용하여 정보를 전달할 때 사용됩니다.기본값은 X-Forwarded-Proto 입니다. |
ForwardedPrefixHeaderName | ForwardedHeadersDefaults.XForwardedPrefixHeaderName에서 지정한 헤더 대신 이 속성에 지정된 헤더를 사용합니다. 이 옵션은 프록시/전달자가 X-Forwarded-Prefix 헤더를 사용하지 않고 일부 다른 헤더를 사용하여 정보를 전달할 때 사용됩니다.기본값은 X-Forwarded-Prefix 입니다. |
ForwardLimit | 처리되는 헤더의 항목 수를 제한합니다. 제한을 사용하지 않도록 null 로 설정하지만, KnownProxies 또는 KnownNetworks 가 구성된 경우에만 사용해야 합니다. 비값null 설정은 네트워크의 사이드 채널에서 도착하는 잘못 구성된 프록시 및 악의적인 요청으로부터 보호하기 위한 예방 조치(보장은 아님)입니다.전달된 헤더 미들웨어는 헤더를 역순으로 오른쪽에서 왼쪽으로 처리합니다. 기본값( 1 )만 사용된다면 ForwardLimit 의 값을 늘리지 않는 한, 헤더에서 맨 오른쪽 값만 처리됩니다.기본값은 1 입니다. |
KnownNetworks | 전달된 헤더를 허용하기 위한 알려진 네트워크의 주소 범위입니다. CIDR(Classless Interdomain Routing) 표기법을 사용하여 IP 범위를 제공합니다. 서버에서 이중 모드 소켓을 사용하는 경우 IPv4 주소가 IPv6 형식(예: IPv4에서 10.0.0.1 은 IPv6에서 ::ffff:10.0.0.1 로 표시됨)으로 제공됩니다. IPAddress.MapToIPv6를 참조하세요. HttpContext.Connection.RemoteIpAddress를 참조하여 이 형식이 필요한지 확인하세요.기본값은 new IPNetwork(IPAddress.Loopback, 8) 에 대한 단일 항목을 포함하는 IList <IPNetwork>입니다. |
KnownProxies | 전달된 헤더를 허용하기 위한 알려진 프록시의 주소입니다. KnownProxies 를 사용하여 정확한 IP 주소 일치 항목을 지정합니다.서버에서 이중 모드 소켓을 사용하는 경우 IPv4 주소가 IPv6 형식(예: IPv4에서 10.0.0.1 은 IPv6에서 ::ffff:10.0.0.1 로 표시됨)으로 제공됩니다. IPAddress.MapToIPv6를 참조하세요. HttpContext.Connection.RemoteIpAddress를 참조하여 이 형식이 필요한지 확인하세요.기본값은 IPAddress.IPv6Loopback 에 대한 단일 항목을 포함하는 IList <IPAddress>입니다. |
OriginalForHeaderName | ForwardedHeadersDefaults.XOriginalForHeaderName에서 지정된 헤더 대신 이 속성에서 지정된 헤더를 사용합니다. 기본값은 X-Original-For 입니다. |
OriginalHostHeaderName | ForwardedHeadersDefaults.XOriginalHostHeaderName에서 지정된 헤더 대신 이 속성에서 지정된 헤더를 사용합니다. 기본값은 X-Original-Host 입니다. |
OriginalProtoHeaderName | ForwardedHeadersDefaults.XOriginalProtoHeaderName에서 지정된 헤더 대신 이 속성에서 지정된 헤더를 사용합니다. 기본값은 X-Original-Proto 입니다. |
OriginalPrefixHeaderName | ForwardedHeadersDefaults.XOriginalPrefixHeaderName으로 지정된 헤더 대신 이 속성에 지정된 헤더를 사용합니다. 기본값은 X-Original-Prefix 입니다. |
RequireHeaderSymmetry | 처리 중인 ForwardedHeadersOptions.ForwardedHeaders 간에 동기화할 헤더 값 수가 필요합니다. ASP.NET Core 1.x의 기본값은 true 입니다. ASP.NET Core 2.0 이상의 기본값은 false 입니다. |
시나리오 및 사용 사례
전달된 헤더를 추가할 수 없고 모든 요청이 안전한 경우
일부 경우에는 앱으로 프록시된 요청에 전달된 헤더를 추가할 수 없습니다. 모든 공용 외부 요청이 HTTPS가 되도록 프록시가 적용되는 경우 미들웨어를 사용하기 전에 Startup.Configure
에서 체계를 수동으로 설정할 수 있습니다.
app.Use((context, next) =>
{
context.Request.Scheme = "https";
return next();
});
이 코드는 개발 또는 스테이징 환경에서 환경 변수 또는 기타 구성 설정을 통해 사용하지 않도록 설정될 수 있습니다.
요청 경로를 변경하는 프록시 및 경로 기준을 처리합니다.
일부 프록시는 경로를 그대로 전달하지만 라우팅이 제대로 작동하도록 제거해야 하는 앱 기본 경로를 포함합니다. UsePathBaseExtensions.UsePathBase 미들웨어는 경로를 HttpRequest.Path로 분할하고 앱 기본 경로를 HttpRequest.PathBase로 분할합니다.
/foo
가 /foo/api/1
로 전달되는 프록시 경로의 앱 기본 경로인 경우 미들웨어는 다음 명령을 사용하여 Request.PathBase
를 /foo
로 설정하고 Request.Path
를 /api/1
로 설정합니다.
app.UsePathBase("/foo");
미들웨어가 역방향으로 다시 호출되면 원래 경로 및 경로 기준이 다시 적용됩니다. 미들웨어 순서 처리에 대한 자세한 내용은 ASP.NET Core 미들웨어를 참조하세요.
프록시가 경로를 자르는 경우(예: /foo/api/1
을 /api/1
에 전달) 요청의 PathBase 속성을 설정하여 리디렉션 및 링크를 수정합니다.
app.Use((context, next) =>
{
context.Request.PathBase = new PathString("/foo");
return next();
});
프록시가 경로 데이터를 추가하는 경우 경로의 일부를 삭제한 다음, StartsWithSegments를 사용하고 Path 속성에 할당하여 리디렉션 및 링크를 수정합니다.
app.Use((context, next) =>
{
if (context.Request.Path.StartsWithSegments("/foo", out var remainder))
{
context.Request.Path = remainder;
}
return next();
});
다른 헤더 이름을 사용하는 프록시에 대한 구성
프록시가 X-Forwarded-For
및 X-Forwarded-Proto
라는 헤더를 사용하여 프록시 주소/포트 및 원래 체계 정보를 전달하지 않는 경우, ForwardedForHeaderName 및 ForwardedProtoHeaderName 옵션을 프록시에서 사용하는 헤더 이름과 일치하도록 설정합니다.
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedForHeaderName = "Header_Name_Used_By_Proxy_For_X-Forwarded-For_Header";
options.ForwardedProtoHeaderName = "Header_Name_Used_By_Proxy_For_X-Forwarded-Proto_Header";
});
Linux용 스키마 및 비 IIS 역방향 프록시 전달
UseHttpsRedirection 및 UseHsts을(를) 호출하는 앱은 Azure Linux App Service, Azure Linux VM(가상 머신) 또는 IIS 이외의 다른 역방향 프록시 뒤에 배포된 경우 사이트를 무한 루프에 배치합니다. TLS는 역방향 프록시에 의해 종료되며, Kestrel은 올바른 요청 체계를 인식하지 못합니다. OAuth 및 OIDC도 잘못된 리디렉션을 생성하므로 이 구성에서 실패합니다. UseIISIntegration은 IIS 뒤에서 실행되는 경우 전달된 헤더 미들웨어를 추가하고 구성하지만 Linux에 대한 일치하는 자동 구성이 없습니다(Apache 또는 Nginx 통합).
비 IIS 시나리오에서 프록시의 스키마를 전달하려면 전달된 헤더 미들웨어를 추가하고 구성합니다. Startup.ConfigureServices
에서 다음 코드를 사용합니다.
// using Microsoft.AspNetCore.HttpOverrides;
if (string.Equals(
Environment.GetEnvironmentVariable("ASPNETCORE_FORWARDEDHEADERS_ENABLED"),
"true", StringComparison.OrdinalIgnoreCase))
{
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
ForwardedHeaders.XForwardedProto;
// Only loopback proxies are allowed by default.
// Clear that restriction because forwarders are enabled by explicit
// configuration.
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
}
인증서 전달
Azure
인증서 전달에 대한 Azure App Service를 구성하려면 Azure App Service에 대한 TLS 상호 인증 구성을 참조하세요. 다음 지침은 ASP.NET Core 앱 구성과 관련됩니다.
Startup.Configure
에서 app.UseAuthentication();
호출 앞에 다음 코드를 추가합니다.
app.UseCertificateForwarding();
인증서 전달 미들웨어를 구성하여 Azure를 사용하는 헤더 이름을 지정합니다. Startup.ConfigureServices
에서 다음 코드를 추가하여 미들웨어가 인증서를 빌드하는 헤더를 구성합니다.
services.AddCertificateForwarding(options =>
options.CertificateHeader = "X-ARR-ClientCert");
다른 웹 프록시
IIS 또는 Azure App Service의 ARR(애플리케이션 요청 라우팅)이 아닌 프록시를 사용하는 경우 HTTP 헤더에서 받은 인증서를 전달하도록 프록시를 구성합니다. Startup.Configure
에서 app.UseAuthentication();
호출 앞에 다음 코드를 추가합니다.
app.UseCertificateForwarding();
인증서 전달 미들웨어를 구성하여 헤더 이름을 지정합니다. Startup.ConfigureServices
에서 다음 코드를 추가하여 미들웨어가 인증서를 빌드하는 헤더를 구성합니다.
services.AddCertificateForwarding(options =>
options.CertificateHeader = "YOUR_CERTIFICATE_HEADER_NAME");
프록시가 Nginx에서와 같이 인증서를 base64 인코딩하지 않는 경우 HeaderConverter
옵션을 설정합니다. Startup.ConfigureServices
에서 다음 예제를 참조하세요.
services.AddCertificateForwarding(options =>
{
options.CertificateHeader = "YOUR_CUSTOM_HEADER_NAME";
options.HeaderConverter = (headerValue) =>
{
var clientCertificate =
/* some conversion logic to create an X509Certificate2 */
return clientCertificate;
}
});
문제 해결
헤더가 예상대로 전달되지 않으면 로깅을 사용하도록 설정합니다. 로그가 문제를 해결하기에 충분한 정보를 제공하지 않으면 서버가 수신하는 요청 헤더를 열거합니다. 인라인 미들웨어를 사용하여 앱 응답에 요청 헤더를 쓰거나 헤더를 기록합니다.
앱 응답에 헤더를 기록하려면 Startup.Configure
에서 UseForwardedHeaders 호출 바로 뒤에 다음 터미널 인라인 미들웨어를 넣습니다.
app.Run(async (context) =>
{
context.Response.ContentType = "text/plain";
// Request method, scheme, and path
await context.Response.WriteAsync(
$"Request Method: {context.Request.Method}{Environment.NewLine}");
await context.Response.WriteAsync(
$"Request Scheme: {context.Request.Scheme}{Environment.NewLine}");
await context.Response.WriteAsync(
$"Request Path: {context.Request.Path}{Environment.NewLine}");
// Headers
await context.Response.WriteAsync($"Request Headers:{Environment.NewLine}");
foreach (var header in context.Request.Headers)
{
await context.Response.WriteAsync($"{header.Key}: " +
$"{header.Value}{Environment.NewLine}");
}
await context.Response.WriteAsync(Environment.NewLine);
// Connection: RemoteIp
await context.Response.WriteAsync(
$"Request RemoteIp: {context.Connection.RemoteIpAddress}");
});
응답 본문 대신 로그에 기록할 수 있습니다. 로그에 기록하면 디버깅 중 사이트가 정상적으로 작동할 수 있습니다.
응답 본문이 아닌 로그를 기록하려면:
- 시작 시 로그 만들기에 설명된 대로
ILogger<Startup>
을Startup
클래스에 삽입합니다. Startup.Configure
에서 UseForwardedHeaders 호출 바로 뒤에 다음 인라인 미들웨어를 넣습니다.
app.Use(async (context, next) =>
{
// Request method, scheme, path, and base path
_logger.LogDebug("Request Method: {Method}", context.Request.Method);
_logger.LogDebug("Request Scheme: {Scheme}", context.Request.Scheme);
_logger.LogDebug("Request Path: {Path}", context.Request.Path);
_logger.LogDebug("Request Path Base: {PathBase}", context.Request.PathBase);
// Headers
foreach (var header in context.Request.Headers)
{
_logger.LogDebug("Header: {Key}: {Value}", header.Key, header.Value);
}
// Connection: RemoteIp
_logger.LogDebug("Request RemoteIp: {RemoteIpAddress}",
context.Connection.RemoteIpAddress);
await next();
});
처리 시 X-Forwarded-{For|Proto|Host|Prefix}
값이 X-Original-{For|Proto|Host|Prefix}
로 이동됩니다. 제공된 헤더에 여러 값이 있는 경우 전달된 헤더 미들웨어는 오른쪽에서 왼쪽으로 역순으로 헤더를 처리합니다. 기본 ForwardLimit
는 1
(일)이므로 ForwardLimit
의 값을 늘리지 않는 한, 헤더에서 맨 오른쪽 값만 처리됩니다.
요청의 원래 원격 IP는 전달된 헤더가 처리되기 전에 KnownProxies
또는 KnownNetworks
목록의 항목과 일치해야 합니다. 이렇게 하면 신뢰할 수 없는 프록시에서 전달자가 허용되지 않아 헤더 스푸핑이 제한됩니다. 알 수 없는 프록시가 검색되면 로그에 프록시 주소가 기록됩니다.
September 20th 2018, 15:49:44.168 Unknown proxy: 10.0.0.100:54321
앞의 예제에서 10.0.0.100은 프록시 서버입니다. 서버가 신뢰할 수 있는 프록시인 경우 서버의 IP 주소를 Startup.ConfigureServices
의 KnownProxies
에 추가합니다(또는 신뢰할 수 있는 네트워크를 KnownNetworks
에 추가). 자세한 내용은 전달된 헤더 미들웨어 옵션 섹션을 참조하세요.
services.Configure<ForwardedHeadersOptions>(options =>
{
options.KnownProxies.Add(IPAddress.Parse("10.0.0.100"));
});
Important
신뢰할 수 있는 프록시 및 네트워크만 헤더를 전달할 수 있습니다. 그렇지 않을 경우 IP 스푸핑 공격이 가능합니다.
추가 리소스
- 웹 팜에서 ASP.NET Core 호스트
- Microsoft Security Advisory CVE-2018-0787: ASP.NET Core Elevation Of Privilege Vulnerability(Microsoft 보안 공지 CVE-2018-0787: ASP.NET Core 권한 상승 취약성)
- YARP: 또 다른 역방향 프록시
ASP.NET Core