클라이언트와 서버가 HTTPS 연결을 협상하는 경우 먼저 TLS 연결을 설정해야 합니다. TLS 핸드셰이크의 일부로 클라이언트는 TLS 확장 중 하나에서 연결하는 서버의 도메인 이름을 보냅니다. 여러 (가상) 서버가 동일한 컴퓨터에서 호스트되는 경우 TLS 프로토콜의 이 기능을 통해 클라이언트는 연결 중인 서버를 구분하고 서버 인증서와 같은 TLS 설정을 구성할 수 있습니다.
HTTP 요청을 사용하는 HttpClient 경우 구현은 클라이언트가 연결하는 URL에 따라 SNI(서버 이름 표시) 확장에 대한 값을 자동으로 선택합니다. 확장을 더 수동으로 제어해야 하는 시나리오의 경우 다음 방법 중 하나를 사용할 수 있습니다.
호스트 헤더
호스트 HTTP 헤더는 TLS에서 SNI 확장과 유사한 함수를 수행합니다. 이를 통해 대상 서버는 단일 IP 주소에서 여러 호스트 이름에 대한 요청을 구분할 수 있습니다.
HttpClient 는 요청 URI를 사용하여 호스트 헤더를 자동으로 채웁니다. 그러나 해당 값을 수동으로 설정할 수도 있으며 HttpClient SNI 확장에서 새 값도 사용합니다. 이 효과를 사용 HttpRequestMessage.Headers.Host 하거나 HttpClient.DefaultRequestHeaders.Host 사용할 수 있습니다.
using HttpClient client = new();
client.DefaultRequestHeaders.Host = "www.microsoft.com";
using var response = await client.GetAsync("https://127.0.0.1:5001/");
System.Console.WriteLine(response);
비고
이 메서드를 사용하면 호스트 이름을 사용하여 URL에 연결할 때 SNI를 완전히 보내지 않도록 방지할 수 없습니다. 헤더가 빈 문자열 HttpClient 로 설정된 경우 URL의 호스트 이름을 대신 사용합니다.
비고
호스트 헤더를 사용자 지정하면 서버 인증서 유효성 검사에 영향을 줍니다. 기본적으로 클라이언트는 서버 인증서가 호스트 헤더의 호스트 이름과 일치해야 합니다.
ConnectCallback을 통한 수동 SslStream 인증
더 복잡하지만 더 강력한 옵션은 SocketsHttpHandler.ConnectCallback를 사용하는 것입니다. .NET 7부터 인증된 SslStream 항목을 반환하여 TLS 연결 설정 방법을 사용자 지정할 수 있습니다. 콜백 내에서 임의의 SslClientAuthenticationOptions 옵션을 사용하여 클라이언트 쪽 인증을 수행할 수 있습니다.
var handler = new SocketsHttpHandler
{
ConnectCallback = async (context, cancellationToken) =>
{
var socket = new Socket(SocketType.Stream, ProtocolType.Tcp) { NoDelay = true };
try
{
await socket.ConnectAsync(context.DnsEndPoint, cancellationToken);
var sslStream = new SslStream(new NetworkStream(socket, ownsSocket: true));
// When using HTTP/2, you must also keep in mind to set options like ApplicationProtocols
await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions
{
TargetHost = context.DnsEndPoint.Host,
}, cancellationToken);
return sslStream;
}
catch
{
socket.Dispose();
throw;
}
}
};
using HttpClient client = new(handler);
using var response = await client.GetAsync("https://www.microsoft.com");
System.Console.WriteLine(response);
.NET