다음을 통해 공유


Nginx를 사용하여 Linux에서 ASP.NET Core 호스트

작성자: Sourabh Shirhatti

참고 항목

이 문서의 최신 버전은 아닙니다. 현재 릴리스는 이 문서의 .NET 9 버전을 참조 하세요.

Warning

이 버전의 ASP.NET Core는 더 이상 지원되지 않습니다. 자세한 내용은 .NET 및 .NET Core 지원 정책을 참조 하세요. 현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.

Important

이 정보는 상업적으로 출시되기 전에 실질적으로 수정될 수 있는 시험판 제품과 관련이 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적, 또는 묵시적인 보증을 하지 않습니다.

현재 릴리스는 이 문서의 .NET 9 버전을 참조 하세요.

이 가이드에서는 Ubuntu, RHEL(Red Hat Enterprise) 및 SUSE Linux Enterprise Server을 위한 프로덕션 준비 ASP.NET Core 환경 설정에 대해 설명합니다.

ASP.NET Core에서 지원하는 다른 Linux 배포에 대한 자세한 내용은 Linux에서 .NET Core의 필수 구성 요소를 참조하세요.

이 가이드의 내용:

  • 기존 ASP.NET Core 앱을 역방향 프록시 서버 뒤에 배치합니다.
  • 역방향 프록시 서버를 설정하여 Kestrel 웹 서버에 요청을 전달합니다.
  • 웹앱이 시작 시 디먼으로 실행되는지 확인합니다.
  • 웹앱 다시 시작을 지원하도록 프로세스 관리 도구를 구성합니다.

필수 조건

  • sudo 권한을 가진 표준 사용자 계정으로 Ubuntu 20.04에 액세스합니다.
  • 서버에 설치된 안정적인 최신 버전 .NET 런타임.
  • 기존 ASP.NET Core 앱입니다.

공유 프레임워크를 업그레이드한 후 나중에 언제든지 서버에서 호스트되는 ASP.NET Core 앱을 다시 시작합니다.

앱 게시 및 복사

프레임워크 종속 배포인 경우 앱을 구성합니다.

앱이 개발 환경에서 로컬로 실행되고 서버에 의해 보안 HTTPS 연결을 하도록 구성되지 않은 경우 다음 방법 중 하나를 채택합니다.

  • 보안 로컬 연결을 처리하도록 앱을 구성합니다. 자세한 내용은 HTTPS 구성 섹션을 참조하세요.

  • 안전하지 않은 엔드포인트에서 실행되도록 앱을 구성합니다.

    • 개발 환경에서 HTTPS 리디렉션 미들웨어를 사용하지 않도록 설정합니다(Program.cs).

      if (!app.Environment.IsDevelopment())
      {
          app.UseHttpsRedirection();
      }
      

      자세한 내용은 ASP.NET Core에서 여러 환경 사용을 참조하세요.

    • 파일의 속성 Properties/launchSettings.json 에서 applicationUrl 제거 https://localhost:5001 합니다(있는 경우).

환경별 구성에 대한 자세한 내용은 ASP.NET Core에서 여러 환경 사용을 참조하세요.

개발 환경에서 dotnet publish를 실행하여 서버에서 실행할 수 있는 디렉터리(예: bin/Release/{TARGET FRAMEWORK MONIKER}/publish, 여기서 {TARGET FRAMEWORK MONIKER} 자리 표시자는 TFM(대상 프레임워크 모니커))로 앱을 패키징합니다.

dotnet publish --configuration Release

.NET Core 런타임을 서버에서 유지 관리하지 않으려는 경우 앱은 자체 포함된 배포로 게시될 수도 있습니다.

조직의 워크플로에 통합된 도구(예: SCP, SFTP)를 사용하여 ASP.NET Core 앱을 서버에 복사합니다. 디렉터리 아래에 var 웹앱을 찾는 것이 일반적입니다(예: var/www/helloapp).

참고 항목

프로덕션 배포 시나리오에서 지속적인 통합 워크플로는 앱을 게시하고 자산을 서버로 복사하는 워크플로를 수행합니다.

앱을 테스트합니다.

  1. 명령줄에서 dotnet <app_assembly>.dll 앱을 실행하세요.
  2. 브라우저에서 http://<serveraddress>:<port>로 이동하여 앱이 Linux에서 로컬로 작동하는지 확인합니다.

역방향 프록시 서버 구성

역방향 프록시는 동적 웹앱을 지원하기 위한 일반적인 설정입니다. 역방향 프록시는 HTTP 요청을 종료하고 이 요청을 ASP.NET Core 앱에 전달합니다.

역방향 프록시 서버를 사용합니다.

Kestrel은 ASP.NET Core에서 동적 콘텐츠를 제공하는 데 유용합니다. 그러나 웹 지원 기능은 IIS, Apache 또는 Nginx와 같은 서버만큼 기능이 다양하지 않습니다. 역방향 프록시 서버는 정적 콘텐츠 지원, 요청 캐시, 요청 압축 및 HTTP 서버에서 HTTPS 종료 같은 작업을 오프로드할 수 있습니다. 역방향 프록시 서버는 전용 컴퓨터에 있거나 HTTP 서버와 함께 배포될 수 있습니다.

이 가이드에서는 Nginx의 단일 인스턴스가 사용됩니다. 이 인스턴스는 HTTP 서버와 함께 동일한 서버에서 실행됩니다. 요구 사항에 따라 다른 설정을 선택할 수 있습니다.

요청은 역방향 프록시로 전달되므로 패키지에서 전달된 헤더 미들웨어를 사용합니다. 이 미들웨어는 공유 프레임워크의 Microsoft.AspNetCore.App 메타패키지를 통해 ASP.NET Core 앱에 자동으로 포함됩니다.Microsoft.AspNetCore.HttpOverrides 이 미들웨어는 X-Forwarded-Proto 헤더를 사용하여 Request.Scheme을 업데이트하므로 리디렉션 URI 및 기타 보안 정책이 제대로 작동합니다.

전달된 헤더 미들웨어는 다른 미들웨어보다 먼저 실행해야 합니다. 이 순서를 지정하면 전달된 헤더 정보에 따라 달라지는 미들웨어는 처리하기 위해 헤더 값을 사용할 수 있습니다. 진단 및 오류 처리 미들웨어 다음에 전달된 헤더 미들웨어를 실행하려면 전달된 헤더 미들웨어 순서를 참조하세요.

다른 미들웨어를 UseForwardedHeaders 호출하기 전에 메서드를 호출합니다. X-Forwarded-ForX-Forwarded-Proto 헤더를 전달하도록 미들웨어를 구성합니다.

using Microsoft.AspNetCore.HttpOverrides;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication();

var app = builder.Build();

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

app.UseAuthentication();

app.MapGet("/", () => "Hello ForwardedHeadersOptions!");

app.Run();

미들웨어에 ForwardedHeadersOptions가 지정되지 않은 경우 전달할 기본 헤더는 None입니다.

표준 localhost 주소(127.0.0.1)를 포함하여 루프백 주소(127.0.0.0/8, [::1])에서 실행 중인 프록시는 기본적으로 신뢰할 수 있습니다. 조직 내의 다른 신뢰할 수 있는 프록시 또는 네트워크가 인터넷과 웹 서버 간의 요청을 처리하는 경우 ForwardedHeadersOptions를 사용하여 KnownProxies 또는 KnownNetworks 목록에 추가합니다. 다음 예제에서는 IP 주소 10.0.0.100 의 신뢰할 수 있는 프록시 서버를 전달된 헤더 미들웨어 KnownProxies에 추가합니다.

using Microsoft.AspNetCore.HttpOverrides;
using System.Net;

var builder = WebApplication.CreateBuilder(args);

// Configure forwarded headers
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.KnownProxies.Add(IPAddress.Parse("10.0.0.100"));
});

builder.Services.AddAuthentication();

var app = builder.Build();

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

app.UseAuthentication();

app.MapGet("/", () => "10.0.0.100");

app.Run();

자세한 내용은 프록시 서버 및 부하 분산 장치를 사용하도록 ASP.NET Core 구성을 참조하세요.

Nginx 설치

apt-get을 사용하여 Nginx를 설치합니다. 설치 관리자는 시스템 시작 시 Nginx를 systemd 디먼으로 실행하는 init 스크립트를 만듭니다. Nginx: 공식 Debian/Ubuntu 패키지에서 Ubuntu에 대한 설치 지침을 따르세요.

참고 항목

선택적 Nginx 모듈이 필요한 경우 소스에서 Nginx를 빌드해야 할 수 있습니다.

Nginx가 처음 설치되었으므로 다음을 실행하여 명시적으로 시작합니다.

sudo service nginx start

브라우저에 Nginx에 대한 기본 방문 페이지가 표시되는지 확인합니다. 방문 페이지는 http://<server_IP_address>/index.nginx-debian.html에 도달할 수 있습니다.

Nginx 구성

Nginx를 역방향 프록시로 구성하여 http 요청을 ASP.NET Core 앱으로 전달하려면 symlink를 수정 /etc/nginx/sites-available/default 하고 다시 만듭니다. 파일을 만든 /etc/nginx/sites-available/default 후 다음 명령을 사용하여 symlink를 만듭니다.

sudo ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default

텍스트 편집기에서 열고 /etc/nginx/sites-available/default 내용을 다음 코드 조각으로 바꿉니다.

http {
  map $http_connection $connection_upgrade {
    "~*Upgrade" $http_connection;
    default keep-alive;
  }

  server {
    listen        80;
    server_name   example.com *.example.com;
    location / {
        proxy_pass         http://127.0.0.1:5000/;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection $connection_upgrade;
        proxy_set_header   Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
  }
}

앱이 앱인 SignalR Blazor Server 경우 ASP.NET Core SignalR 프로덕션 호스팅 및 크기 조정을 참조하고 ASP.NET Core 서버 쪽 Blazor 앱을 각각 호스트 및 배포합니다.

server_name이 일치하지 않으면 Nginx는 기본 서버를 사용합니다. 기본 서버가 정의되지 않은 경우 구성 파일의 첫 번째 서버는 기본 서버입니다. 구성 파일에 있는 444 상태 코드를 반환하는 특정 기본 서버를 추가하는 것이 좋습니다. 기본 서버 구성 예제는 다음과 같습니다.

server {
    listen   80 default_server;
    # listen [::]:80 default_server deferred;
    return   444;
}

이전 구성 파일과 기본 서버를 사용하여 Nginx는 포트 80에서 호스트 헤더 example.com 또는 *.example.com가 포함된 공용 트래픽을 허용합니다. 이러한 호스트와 일치하지 않는 요청은 Kestrel로 전달되지 않습니다. Nginx는 일치하는 요청을 Kestrel의 http://127.0.0.1:5000/에 전달합니다. 자세한 내용은 Nginx가 요청을 처리하는 방법을 참조하세요. Kestrel의 IP/포트를 변경하려면 Kestrel: 엔드포인트 구성을 참조하세요.

Warning

적절한 server_name 지시문을 지정하지 않으면 앱이 보안 취약성에 노출됩니다. 전체 부모 도메인을 제어하는 경우 하위 도메인 와일드카드 바인딩(예: *.example.com)에는 이러한 보안 위험이 발생하지 않습니다(취약한 *.com과 반대임). 자세한 내용은 RFC 9110: HTTP 의미 체계(섹션 7.2: 호스트 및 :authority)를 참조하세요.

Nginx 구성이 설정되면 sudo nginx -t를 실행하여 구성 파일의 구문을 확인합니다. 구성 파일 테스트에 성공하면 sudo nginx -s reload를 실행하여 Nginx가 변경 내용을 선택하도록 합니다.

앱을 서버에서 직접 실행하려면:

  1. 앱의 디렉터리로 이동합니다.
  2. dotnet <app_assembly.dll> 앱을 실행합니다. 여기서 app_assembly.dll은 앱의 어셈블리 파일 이름입니다.

앱이 서버에서 실행되지만 인터넷을 통해 응답하지 않는 경우 서버의 방화벽을 확인하고 포트 80이 열려 있는지 확인합니다. Ubuntu Azure VM을 사용하는 경우 인바운드 포트 80 트래픽을 사용하는 NSG(네트워크 보안 그룹) 규칙을 추가합니다. 인바운드 규칙을 사용할 때 아웃바운드 트래픽이 자동으로 부여되므로 아웃바운드 포트 80 규칙을 사용하도록 설정할 필요가 없습니다.

앱 테스트를 완료한 후에 명령 프롬프트에서 Ctrl+C(Windows) 또는 +C(macOS)를 사용하여 앱을 종료합니다.

keepalive_requests 늘리기

keepalive_requests는 더 높은 성능을 위해 향상될 수 있습니다. 자세한 내용은 이 GitHub 문제를 참조하세요.

앱 모니터링

서버는 http://<serveraddress>:80에 보낸 요청을 Kestrel의 http://127.0.0.1:5000에서 실행되는 ASP.NET Core 앱에 전달하도록 설정됩니다. 그러나 Nginx는 Kestrel 프로세스를 관리하도록 설정되지 않습니다. systemd 는 기본 웹앱을 시작하고 모니터링하는 서비스 파일을 만드는 데 사용할 수 있습니다. systemd 는 프로세스를 시작, 중지 및 관리하기 위한 많은 강력한 기능을 제공하는 init 시스템입니다.

서비스 파일 만들기

서비스 정의 파일을 만듭니다.

sudo nano /etc/systemd/system/kestrel-helloapp.service

다음 예제는 앱의 .ini 서비스 파일입니다.

[Unit]
Description=Example .NET Web API App running on Linux

[Service]
WorkingDirectory=/var/www/helloapp
ExecStart=/usr/bin/dotnet /var/www/helloapp/helloapp.dll
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dotnet-example
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_NOLOGO=true

[Install]
WantedBy=multi-user.target

앞의 예제에서 서비스를 관리하는 사용자는 User 옵션으로 지정됩니다. 사용자(www-data)가 존재해야 하며 앱 파일에 대한 적절한 소유권이 있어야 합니다.

TimeoutStopSec를 사용하여 초기 인터럽트 신호를 받은 후 앱이 종료되기를 기다리는 기간을 구성합니다. 이 기간 내에 앱이 종료되지 않으면 앱을 종료하기 위해 SIGKILL이 실행됩니다. 단위 없는 초로 된 값(예: 150) 또는 시간 범위 값(예: 2min 30s)으로 값을 입력하거나, 시간 제한을 사용하지 않으려면 infinity를 입력합니다. TimeoutStopSec는 관리자 구성 파일(systemd-system.conf, system.conf.d, systemd-user.conf, user.conf.d)에서 DefaultTimeoutStopSec의 값으로 기본 설정됩니다. 대부분의 배포에서 기본 시간 제한은 90초입니다.

# The default value is 90 seconds for most distributions.
TimeoutStopSec=90

Linux에는 대/소문자를 구분하는 파일 시스템이 있습니다. ASPNETCORE_ENVIRONMENTProduction으로 설정하면 appsettings.production.json이 아니라 appsettings.Production.json구성 파일이 검색됩니다.

일부 값(예: SQL 연결 문자열)은 환경 변수를 읽기 위해 구성 공급자에 대해 이스케이프되어야 합니다. 다음 명령을 사용하여 구성 파일에서 사용할 제대로 이스케이프된 값을 생성합니다.

systemd-escape "<value-to-escape>"

콜론(:) 구분 기호는 환경 변수 이름에서 지원되지 않습니다. 콜론 대신 이중 밑줄(__)을 사용합니다. 환경 변수 구성 공급자는 환경 변수를 구성으로 읽을 때 이중 밑줄을 콜론으로 변환합니다. 다음 예제에서 연결 문자열 키 ConnectionStrings:DefaultConnection은 서비스 정의 파일에 ConnectionStrings__DefaultConnection으로 설정됩니다.

Environment=ConnectionStrings__DefaultConnection={Connection String}

파일을 저장하고 서비스를 사용하도록 설정합니다.

sudo systemctl enable kestrel-helloapp.service

서비스를 시작하고 실행 중인지 확인합니다.

sudo systemctl start kestrel-helloapp.service
sudo systemctl status kestrel-helloapp.service

◝ kestrel-helloapp.service - Example .NET Web API App running on Linux
    Loaded: loaded (/etc/systemd/system/kestrel-helloapp.service; enabled)
    Active: active (running) since Thu 2016-10-18 04:09:35 NZDT; 35s ago
Main PID: 9021 (dotnet)
    CGroup: /system.slice/kestrel-helloapp.service
            └─9021 /usr/local/bin/dotnet /var/www/helloapp/helloapp.dll

역방향 프록시를 구성하고 Kestrel를 통해 systemd을 관리하면 웹앱이 완전히 구성되고 로컬 머신(http://localhost)의 브라우저에서 웹앱에 액세스할 수 있습니다. 차단 중인 방화벽이 없다면 원격 컴퓨터에서 액세스할 수도 있습니다. 응답 헤더를 검사하는 Server 헤더는 Kestrel에서 지원하는 ASP.NET Core 앱을 보여줍니다.

HTTP/1.1 200 OK
Date: Tue, 11 Oct 2016 16:22:23 GMT
Server: Kestrel
Keep-Alive: timeout=5, max=98
Connection: Keep-Alive
Transfer-Encoding: chunked

로그 보기

Kestrel을 사용하는 웹앱은 systemd를 사용하여 관리되므로 모든 이벤트 및 프로세스가 중앙형 저널에 기록됩니다. 그러나 이 저널에는 systemd를 통해 관리하는 모든 서비스 및 프로세스에 대한 모든 항목이 포함됩니다. kestrel-helloapp.service 관련 항목을 보려면 다음 명령을 사용합니다.

sudo journalctl -fu kestrel-helloapp.service

추가 필터링을 위해 --since today, --until 1 hour ago 같은 시간 옵션을 사용하거나 이러한 옵션을 조합하여 반환되는 항목 수를 줄일 수 있습니다.

sudo journalctl -fu kestrel-helloapp.service --since "2016-10-18" --until "2016-10-18 04:00"

데이터 보호

ASP.NET Core 데이터 보호 스택은 인증 미들웨어(예: cookie 미들웨어) 및 CSRF(교차 사이트 요청 위조) 보호를 비롯한 여러 ASP.NET Core 미들웨어에 사용됩니다. 사용자 코드에서 데이터 보호 API가 호출되지 않더라도 영구적 암호화 키 저장소를 만들도록 데이터 보호를 구성해야 합니다. 데이터 보호를 구성하지 않으면 키는 메모리에 보관되고 앱이 다시 시작되면 삭제됩니다.

키 링이 메모리에 저장된 경우 앱을 다시 시작하면 다음과 같이 됩니다.

  • 모든 cookie 기반 인증 토큰이 무효화됩니다.
  • 사용자는 다음 요청에서 다시 로그인해야 합니다.
  • 키 링으로 보호된 데이터의 암호를 더 이상 해독할 수 없습니다. 여기에는 CSRF 토큰ASP.NET Core MVC TempData 쿠키가 포함될 수 있습니다.

키 링을 유지하고 암호화하도록 데이터 보호를 구성하려면 다음을 참조하십시오.

긴 요청 헤더 필드

프록시 서버 기본 설정은 일반적으로 플랫폼에 따라 요청 헤더 필드를 4K 또는 8K로 제한합니다. 앱에 기본값보다 긴 필드가 필요할 수 있습니다(예: Microsoft Entra ID를 사용하는 앱). 더 긴 필드가 필요한 경우 프록시 서버의 기본 설정을 조정해야 합니다. 적용할 값은 시나리오에 따라 달라집니다. 자세한 내용은 서버의 설명서를 참조하세요.

Warning

필요한 경우가 아니면 프록시 버퍼의 기본값을 늘리지 마세요. 이러한 값을 늘리면 악의적인 사용자의 버퍼 오버런(오버플로) 및 DoS(서비스 거부) 공격의 위험이 증가됩니다.

앱 보안 유지

AppArmor 사용

LSM(Linux Security Modules)은 Linux 2.6 이후 Linux 커널에 포함된 프레임워크입니다. LSM은 보안 모듈의 다양한 구현을 지원합니다. AppArmor는 프로그램을 제한된 리소스 세트로 한정할 수 있는 필수 Access Control 시스템을 구현하는 LSM입니다. AppArmor가 사용하도록 설정되고 제대로 구성되어 있는지 확인합니다.

방화벽 구성

사용하지 않는 모든 외부 포트를 닫습니다. 복잡하지 않은 방화벽(ufw)은 방화벽을 구성하기 위한 CLI를 제공하여 iptables에 대한 프런트 엔드를 제공합니다.

Warning

방화벽이 올바르게 구성되지 않으면 전체 시스템에 대한 액세스가 차단됩니다. 올바른 SSH 포트를 지정하지 못하면 SSH를 사용하여 시스템에 연결하는 경우 실직적으로 시스템에 액세스할 수 없게 됩니다. 기본 포트는 22입니다. 자세한 내용은 ufw 소개매뉴얼을 참조하세요.

ufw를 설치하고 필요한 모든 포트에서 트래픽을 허용하도록 구성합니다.

sudo apt-get install ufw

sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

sudo ufw enable

Nginx 보안 유지

Nginx 응답 이름 변경

편집 src/http/ngx_http_header_filter_module.c:

static char ngx_http_server_string[] = "Server: Web Server" CRLF;
static char ngx_http_server_full_string[] = "Server: Web Server" CRLF;

옵션 구성

추가 필수 모듈을 사용하여 서버를 구성합니다. ModSecurity와 같은 웹앱 방화벽을 사용하여 앱을 강화해 보세요.

HTTPS 구성

보안(HTTPS) 로컬 연결을 위해 앱 구성

dotnet run 명령은 applicationUrl 속성이 제공하는 URL에서 수신 대기하도록 앱을 구성하는 앱의 Properties/launchSettings.json 파일을 사용합니다. 예들 들어 https://localhost:5001;http://localhost:5000입니다.

다음 방법 중 하나를 사용하여 dotnet run 명령 또는 개발 환경(Visual Studio Code에서 F5 또는 Ctrl+F5)에 개발 중인 인증서를 사용하도록 앱을 구성합니다.

보안 (HTTPS) 클라이언트 연결을 위해 역방향 프록시 구성

Warning

이 섹션의 보안 구성은 추가 사용자 지정을 위한 시작 지점으로 사용할 일반 구성입니다. 타사 도구, 서버, 운영 체제에 대한 지원은 제공하지 않습니다. ‘이 섹션의 구성을 사용할 때는 주의해야 합니다.’ 자세한 내용을 보려면 다음 리소스에 액세스하세요.

  • 신뢰할 수 있는 CA(인증 기관)에서 발급된 유효한 인증서를 지정하여 포트 443에서 HTTPS 트래픽을 수신 대기하도록 서버를 구성합니다.

  • 다음 /etc/nginx/nginx.conf 파일에 설명된 일부 사례를 채택하여 보안을 강화합니다.

  • 다음 예제에서는 안전하지 않은 요청을 리디렉션하도록 서버를 구성하지 않습니다. HTTPS 리디렉션 미들웨어를 사용하는 것이 좋습니다. 자세한 내용은 ASP.NET Core에서 HTTPS 적용을 참조하세요.

    참고 항목

    서버 구성이 HTTPS 리디렉션 미들웨어 대신 보안 리디렉션을 처리하는 개발 환경인 경우 영구 리디렉션(301) 대신 임시 리디렉션(302)을 사용하는 것이 좋습니다. 링크 캐싱은 개발 환경에서 불안정한 동작을 일으킬 수 있습니다.

  • Strict-Transport-Security(HSTS) 헤더를 추가하면 클라이언트에서 만든 모든 후속 요청이 HTTPS를 통해 이루어집니다. Strict-Transport-Security 헤더 설정에 대한 지침은 ASP.NET Core에서 HTTPS 적용을 참조하세요.

  • 추후 HTTPS가 사용하지 않도록 설정될 경우 다음 방법 중 하나를 사용합니다.

    • HSTS 헤더를 추가하지 않습니다.
    • 짧은 max-age 값을 선택합니다.

/etc/nginx/proxy.conf 구성 파일을 추가합니다.

proxy_redirect          off;
proxy_set_header        Host $host;
proxy_set_header        X-Real-IP $remote_addr;
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header        X-Forwarded-Proto $scheme;
client_max_body_size    10m;
client_body_buffer_size 128k;
proxy_connect_timeout   90;
proxy_send_timeout      90;
proxy_read_timeout      90;
proxy_buffers           32 4k;

/etc/nginx/nginx.conf 구성 파일의 내용을 다음 파일로 바꿉니다. 예제에서는 httpserver 섹션이 하나의 구성 파일에 포함됩니다.

http {
    include        /etc/nginx/proxy.conf;
    limit_req_zone $binary_remote_addr zone=one:10m rate=5r/s;
    server_tokens  off;

    sendfile on;
    # Adjust keepalive_timeout to the lowest possible value that makes sense 
    # for your use case.
    keepalive_timeout   29;
    client_body_timeout 10; client_header_timeout 10; send_timeout 10;

    upstream helloapp{
        server 127.0.0.1:5000;
    }

    server {
        listen                    443 ssl http2;
        listen                    [::]:443 ssl http2;
        server_name               example.com *.example.com;
        ssl_certificate           /etc/ssl/certs/testCert.crt;
        ssl_certificate_key       /etc/ssl/certs/testCert.key;
        ssl_session_timeout       1d;
        ssl_protocols             TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers off;
        ssl_ciphers               ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
        ssl_session_cache         shared:SSL:10m;
        ssl_session_tickets       off;
        ssl_stapling              off;

        add_header X-Frame-Options DENY;
        add_header X-Content-Type-Options nosniff;

        #Redirects all traffic
        location / {
            proxy_pass http://helloapp;
            limit_req  zone=one burst=10 nodelay;
        }
    }
}

참고 항목

Blazor WebAssembly 앱에서 수행하는 많은 수의 요청을 수용하려면 앱에 더 큰 burst 매개 변수 값이 필요합니다. 자세한 내용은 ASP.NET Core Blazor WebAssembly 호스트 및 배포를 참조하세요.

참고 항목

앞의 예제에서는 OCSP(온라인 인증서 상태 프로토콜) 스테이플링을 사용하지 않도록 설정합니다. 사용하도록 설정한 경우 인증서가 해당 기능을 지원하는지 확인하세요. OCSP를 사용하도록 설정하는 방법에 대한 자세한 내용 및 지침은 Module ngx_http_ssl_module (Nginx documentation)(ngx_http_ssl_module 모듈(Nginx 설명서)) 문서에서 다음 속성을 참조하세요.

  • ssl_stapling
  • ssl_stapling_file
  • ssl_stapling_responder
  • ssl_stapling_verify

클릭재킹(clickjacking)으로부터 Nginx 보호

또한 ‘UI 교정 공격’이라고도 하는클릭재킹(Clickjacking)은 웹 사이트 방문자를 속여서 현재 방문 중인 것과 다른 페이지에서 링크 또는 단추를 클릭하게 하는 악의적인 공격입니다. X-FRAME-OPTIONS를 사용하여 사이트를 보호합니다.

클릭재킹 공격을 완화하려면:

  1. nginx.conf 파일을 편집합니다.

    sudo nano /etc/nginx/nginx.conf
    

    http{} 코드 블록 내에서 add_header X-Frame-Options "SAMEORIGIN";줄을 추가합니다.

  2. 파일을 저장합니다.

  3. Nginx를 다시 시작합니다.

MIME 형식 검색

이 헤더는 응답 콘텐츠 형식을 재정의하지 않도록 브라우저에 지시하므로 대부분의 브라우저에서 선언된 콘텐츠 형식이 아닌 응답에 대한 MIME 검색을 차단합니다. nosniff 옵션을 사용하면 서버에 콘텐츠가 text/html이라고 표시될 경우 브라우저가 이를text/html로 렌더링합니다.

  1. nginx.conf 파일을 편집합니다.

    sudo nano /etc/nginx/nginx.conf
    

    http{} 코드 블록 내에서 add_header X-Content-Type-Options "nosniff";줄을 추가합니다.

  2. 파일을 저장합니다.

  3. Nginx를 다시 시작합니다.

추가 Nginx 제안

서버에서 공유 프레임워크를 업그레이드한 후 서버에서 호스트되는 ASP.NET Core 앱을 다시 시작합니다.

추가 리소스

이 가이드에서는 Ubuntu 16.04 Server에서 프로덕션 준비 ASP.NET Core 환경을 설정하는 방법을 설명합니다. 이 지침은 최신 버전의 Ubuntu에서 작동할 수 있지만 최신 버전에서 테스트되지는 않았습니다.

ASP.NET Core에서 지원하는 다른 Linux 배포에 대한 자세한 내용은 Linux에서 .NET Core의 필수 구성 요소를 참조하세요.

참고 항목

Ubuntu 14.04의 경우 Kestrel 프로세스를 모니터링하기 위한 솔루션으로 supervisord를 사용하는 것이 좋습니다. systemd 는 Ubuntu 14.04에서 사용할 수 없습니다. Ubuntu 14.04 지침의 경우 이 항목의 이전 버전을 참조하세요.

이 가이드의 내용:

  • 기존 ASP.NET Core 앱을 역방향 프록시 서버 뒤에 배치합니다.
  • 역방향 프록시 서버를 설정하여 Kestrel 웹 서버에 요청을 전달합니다.
  • 웹앱이 시작 시 디먼으로 실행되는지 확인합니다.
  • 웹앱 다시 시작을 지원하도록 프로세스 관리 도구를 구성합니다.

필수 조건

  • sudo 권한을 가진 표준 사용자 계정으로 Ubuntu 16.04 Server에 액세스합니다.
  • 서버에 설치된, 미리 보기가 아닌 최신 .NET 런타임.
  • 기존 ASP.NET Core 앱입니다.

공유 프레임워크를 업그레이드한 후 나중에 언제든지 서버에서 호스트되는 ASP.NET Core 앱을 다시 시작합니다.

앱 게시 및 복사

프레임워크 종속 배포인 경우 앱을 구성합니다.

앱이 개발 환경에서 로컬로 실행되고 서버에 의해 보안 HTTPS 연결을 하도록 구성되지 않은 경우 다음 방법 중 하나를 채택합니다.

  • 보안 로컬 연결을 처리하도록 앱을 구성합니다. 자세한 내용은 HTTPS 구성 섹션을 참조하세요.

  • 안전하지 않은 엔드포인트에서 실행되도록 앱을 구성합니다.

    • 개발 환경에서 HTTPS 리디렉션 미들웨어를 사용하지 않도록 설정합니다(Program.cs).

      if (!app.Environment.IsDevelopment())
      {
          app.UseHttpsRedirection();
      }
      

      자세한 내용은 ASP.NET Core에서 여러 환경 사용을 참조하세요.

    • 파일의 속성 Properties/launchSettings.json 에서 applicationUrl 제거 https://localhost:5001 합니다(있는 경우).

환경별 구성에 대한 자세한 내용은 ASP.NET Core에서 여러 환경 사용을 참조하세요.

개발 환경에서 dotnet publish를 실행하여 서버에서 실행할 수 있는 디렉터리(예: bin/Release/{TARGET FRAMEWORK MONIKER}/publish, 여기서 자리 표시자 {TARGET FRAMEWORK MONIKER}는 대상 프레임워크 모니커/TFM)로 앱을 패키징합니다.

dotnet publish --configuration Release

.NET Core 런타임을 서버에서 유지 관리하지 않으려는 경우 앱은 자체 포함된 배포로 게시될 수도 있습니다.

조직의 워크플로에 통합된 도구(예: SCP, SFTP)를 사용하여 ASP.NET Core 앱을 서버에 복사합니다. 디렉터리 아래에 var 웹앱을 찾는 것이 일반적입니다(예: var/www/helloapp).

참고 항목

프로덕션 배포 시나리오에서 지속적인 통합 워크플로는 앱을 게시하고 자산을 서버로 복사하는 워크플로를 수행합니다.

앱을 테스트합니다.

  1. 명령줄에서 dotnet <app_assembly>.dll 앱을 실행하세요.
  2. 브라우저에서 http://<serveraddress>:<port>로 이동하여 앱이 Linux에서 로컬로 작동하는지 확인합니다.

역방향 프록시 서버 구성

역방향 프록시는 동적 웹앱을 지원하기 위한 일반적인 설정입니다. 역방향 프록시는 HTTP 요청을 종료하고 이 요청을 ASP.NET Core 앱에 전달합니다.

역방향 프록시 서버를 사용합니다.

Kestrel은 ASP.NET Core에서 동적 콘텐츠를 제공하는 데 유용합니다. 그러나 웹 지원 기능은 IIS, Apache 또는 Nginx와 같은 서버만큼 기능이 다양하지 않습니다. 역방향 프록시 서버는 정적 콘텐츠 지원, 요청 캐시, 요청 압축 및 HTTP 서버에서 HTTPS 종료 같은 작업을 오프로드할 수 있습니다. 역방향 프록시 서버는 전용 컴퓨터에 있거나 HTTP 서버와 함께 배포될 수 있습니다.

이 가이드에서는 Nginx의 단일 인스턴스가 사용됩니다. 이 인스턴스는 HTTP 서버와 함께 동일한 서버에서 실행됩니다. 요구 사항에 따라 다른 설정을 선택할 수 있습니다.

요청이 역방향 프록시에 의해 전달되므로 Microsoft.AspNetCore.HttpOverrides 패키지의 전달된 헤더 미들웨어를 사용합니다. 이 미들웨어는 X-Forwarded-Proto 헤더를 사용하여 Request.Scheme을 업데이트하므로 리디렉션 URI 및 기타 보안 정책이 제대로 작동합니다.

전달된 헤더 미들웨어는 다른 미들웨어보다 먼저 실행해야 합니다. 이 순서를 지정하면 전달된 헤더 정보에 따라 달라지는 미들웨어는 처리하기 위해 헤더 값을 사용할 수 있습니다. 진단 및 오류 처리 미들웨어 다음에 전달된 헤더 미들웨어를 실행하려면 전달된 헤더 미들웨어 순서를 참조하세요.

다른 미들웨어를 호출하기 전에 Program.cs의 맨 위에 있는 UseForwardedHeaders 메서드를 호출합니다. X-Forwarded-ForX-Forwarded-Proto 헤더를 전달하도록 미들웨어를 구성합니다.

// requires using Microsoft.AspNetCore.HttpOverrides;
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

app.UseAuthentication();

미들웨어에 ForwardedHeadersOptions가 지정되지 않은 경우 전달할 기본 헤더는 None입니다.

표준 localhost 주소(127.0.0.1)를 포함하여 루프백 주소(127.0.0.0/8, [::1])에서 실행 중인 프록시는 기본적으로 신뢰할 수 있습니다. 조직 내의 다른 신뢰할 수 있는 프록시 또는 네트워크가 인터넷과 웹 서버 간의 요청을 처리하는 경우 ForwardedHeadersOptions를 사용하여 KnownProxies 또는 KnownNetworks 목록에 추가합니다. 다음 예제는 IP 주소 10.0.0.100의 신뢰할 수 있는 프록시 서버를 Program.cs의 전달된 헤더 미들웨어 KnownProxies에 추가합니다.

using System.Net;

var builder = WebApplication.CreateBuilder(args);

builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.KnownProxies.Add(IPAddress.Parse("10.0.0.100"));
});

자세한 내용은 프록시 서버 및 부하 분산 장치를 사용하도록 ASP.NET Core 구성을 참조하세요.

Nginx 설치

apt-get을 사용하여 Nginx를 설치합니다. 설치 관리자는 시스템 시작 시 Nginx를 systemd 디먼으로 실행하는 init 스크립트를 만듭니다. Nginx: 공식 Debian/Ubuntu 패키지에서 Ubuntu에 대한 설치 지침을 따르세요.

참고 항목

선택적 Nginx 모듈이 필요한 경우 소스에서 Nginx를 빌드해야 할 수 있습니다.

Nginx가 처음 설치되었으므로 다음을 실행하여 명시적으로 시작합니다.

sudo service nginx start

브라우저에 Nginx에 대한 기본 방문 페이지가 표시되는지 확인합니다. 방문 페이지는 http://<server_IP_address>/index.nginx-debian.html에 도달할 수 있습니다.

Nginx 구성

Nginx를 역방향 프록시로 구성하여 HTTP 요청을 ASP.NET Core 앱에 전달하려면 /etc/nginx/sites-available/default를 수정합니다. 텍스트 편집기에서 해당 항목을 열고 콘텐츠를 다음 코드 조각으로 바꿉니다.

server {
    listen        80;
    server_name   example.com *.example.com;
    location / {
        proxy_pass         http://127.0.0.1:5000;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection keep-alive;
        proxy_set_header   Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
}

앱이 앱인 SignalR Blazor Server 경우 ASP.NET Core SignalR 프로덕션 호스팅 및 크기 조정을 참조하고 ASP.NET Core 서버 쪽 Blazor 앱을 각각 호스트 및 배포합니다.

server_name이 일치하지 않으면 Nginx는 기본 서버를 사용합니다. 기본 서버가 정의되지 않은 경우 구성 파일의 첫 번째 서버는 기본 서버입니다. 구성 파일에 있는 444 상태 코드를 반환하는 특정 기본 서버를 추가하는 것이 좋습니다. 기본 서버 구성 예제는 다음과 같습니다.

server {
    listen   80 default_server;
    # listen [::]:80 default_server deferred;
    return   444;
}

이전 구성 파일과 기본 서버를 사용하여 Nginx는 포트 80에서 호스트 헤더 example.com 또는 *.example.com가 포함된 공용 트래픽을 허용합니다. 이러한 호스트와 일치하지 않는 요청은 Kestrel로 전달되지 않습니다. Nginx는 일치하는 요청을 Kestrel의 http://127.0.0.1:5000에 전달합니다. 자세한 내용은 Nginx가 요청을 처리하는 방법을 참조하세요. Kestrel의 IP/포트를 변경하려면 Kestrel: 엔드포인트 구성을 참조하세요.

Warning

적절한 server_name 지시문을 지정하지 않으면 앱이 보안 취약성에 노출됩니다. 전체 부모 도메인을 제어하는 경우 하위 도메인 와일드카드 바인딩(예: *.example.com)에는 이러한 보안 위험이 발생하지 않습니다(취약한 *.com과 반대임). 자세한 내용은 RFC 9110: HTTP 의미 체계(섹션 7.2: 호스트 및 :authority)를 참조하세요.

Nginx 구성이 설정되면 sudo nginx -t를 실행하여 구성 파일의 구문을 확인합니다. 구성 파일 테스트에 성공하면 sudo nginx -s reload를 실행하여 Nginx가 변경 내용을 선택하도록 합니다.

앱을 서버에서 직접 실행하려면:

  1. 앱의 디렉터리로 이동합니다.
  2. dotnet <app_assembly.dll> 앱을 실행합니다. 여기서 app_assembly.dll은 앱의 어셈블리 파일 이름입니다.

앱이 서버에서 실행되지만 인터넷을 통해 응답하지 않는 경우 서버의 방화벽을 확인하고 포트 80이 열려 있는지 확인합니다. Ubuntu Azure VM을 사용하는 경우 인바운드 포트 80 트래픽을 사용하는 NSG(네트워크 보안 그룹) 규칙을 추가합니다. 인바운드 규칙을 사용할 때 아웃바운드 트래픽이 자동으로 부여되므로 아웃바운드 포트 80 규칙을 사용하도록 설정할 필요가 없습니다.

앱 테스트를 완료한 후에 명령 프롬프트에서 Ctrl+C(Windows) 또는 +C(macOS)를 사용하여 앱을 종료합니다.

앱 모니터링

서버는 http://<serveraddress>:80에 보낸 요청을 Kestrel의 http://127.0.0.1:5000에서 실행되는 ASP.NET Core 앱에 전달하도록 설정됩니다. 그러나 Nginx는 Kestrel 프로세스를 관리하도록 설정되지 않습니다. systemd 는 기본 웹앱을 시작하고 모니터링하는 서비스 파일을 만드는 데 사용할 수 있습니다. systemd 는 프로세스를 시작, 중지 및 관리하기 위한 많은 강력한 기능을 제공하는 init 시스템입니다.

서비스 파일 만들기

서비스 정의 파일을 만듭니다.

sudo nano /etc/systemd/system/kestrel-helloapp.service

다음 예제는 앱의 서비스 파일입니다.

[Unit]
Description=Example .NET Web API App running on Ubuntu

[Service]
WorkingDirectory=/var/www/helloapp
ExecStart=/usr/bin/dotnet /var/www/helloapp/helloapp.dll
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dotnet-example
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_NOLOGO=true

[Install]
WantedBy=multi-user.target

앞의 예제에서 서비스를 관리하는 사용자는 User 옵션으로 지정됩니다. 사용자(www-data)가 존재해야 하며 앱 파일에 대한 적절한 소유권이 있어야 합니다.

TimeoutStopSec를 사용하여 초기 인터럽트 신호를 받은 후 앱이 종료되기를 기다리는 기간을 구성합니다. 이 기간 내에 앱이 종료되지 않으면 앱을 종료하기 위해 SIGKILL이 실행됩니다. 단위 없는 초로 된 값(예: 150) 또는 시간 범위 값(예: 2min 30s)으로 값을 입력하거나, 시간 제한을 사용하지 않으려면 infinity를 입력합니다. TimeoutStopSec는 관리자 구성 파일(systemd-system.conf, system.conf.d, systemd-user.conf, user.conf.d)에서 DefaultTimeoutStopSec의 값으로 기본 설정됩니다. 대부분의 배포에서 기본 시간 제한은 90초입니다.

# The default value is 90 seconds for most distributions.
TimeoutStopSec=90

Linux에는 대/소문자를 구분하는 파일 시스템이 있습니다. ASPNETCORE_ENVIRONMENTProduction으로 설정하면 appsettings.production.json이 아니라 appsettings.Production.json구성 파일이 검색됩니다.

일부 값(예: SQL 연결 문자열)은 환경 변수를 읽기 위해 구성 공급자에 대해 이스케이프되어야 합니다. 다음 명령을 사용하여 구성 파일에서 사용할 제대로 이스케이프된 값을 생성합니다.

systemd-escape "<value-to-escape>"

콜론(:) 구분 기호는 환경 변수 이름에서 지원되지 않습니다. 콜론 대신 이중 밑줄(__)을 사용합니다. 환경 변수 구성 공급자는 환경 변수를 구성으로 읽을 때 이중 밑줄을 콜론으로 변환합니다. 다음 예제에서 연결 문자열 키 ConnectionStrings:DefaultConnection은 서비스 정의 파일에 ConnectionStrings__DefaultConnection으로 설정됩니다.

Environment=ConnectionStrings__DefaultConnection={Connection String}

파일을 저장하고 서비스를 사용하도록 설정합니다.

sudo systemctl enable kestrel-helloapp.service

서비스를 시작하고 실행 중인지 확인합니다.

sudo systemctl start kestrel-helloapp.service
sudo systemctl status kestrel-helloapp.service

◝ kestrel-helloapp.service - Example .NET Web API App running on Ubuntu
    Loaded: loaded (/etc/systemd/system/kestrel-helloapp.service; enabled)
    Active: active (running) since Thu 2016-10-18 04:09:35 NZDT; 35s ago
Main PID: 9021 (dotnet)
    CGroup: /system.slice/kestrel-helloapp.service
            └─9021 /usr/local/bin/dotnet /var/www/helloapp/helloapp.dll

역방향 프록시를 구성하고 Kestrel를 통해 systemd을 관리하면 웹앱이 완전히 구성되고 로컬 머신(http://localhost)의 브라우저에서 웹앱에 액세스할 수 있습니다. 차단 중인 방화벽이 없다면 원격 컴퓨터에서 액세스할 수도 있습니다. 응답 헤더를 검사하는 Server 헤더는 Kestrel에서 지원하는 ASP.NET Core 앱을 보여줍니다.

HTTP/1.1 200 OK
Date: Tue, 11 Oct 2016 16:22:23 GMT
Server: Kestrel
Keep-Alive: timeout=5, max=98
Connection: Keep-Alive
Transfer-Encoding: chunked

로그 보기

Kestrel을 사용하는 웹앱은 systemd를 사용하여 관리되므로 모든 이벤트 및 프로세스가 중앙형 저널에 기록됩니다. 그러나 이 저널에는 systemd를 통해 관리하는 모든 서비스 및 프로세스에 대한 모든 항목이 포함됩니다. kestrel-helloapp.service 관련 항목을 보려면 다음 명령을 사용합니다.

sudo journalctl -fu kestrel-helloapp.service

추가 필터링을 위해 --since today, --until 1 hour ago 같은 시간 옵션을 사용하거나 이러한 옵션을 조합하여 반환되는 항목 수를 줄일 수 있습니다.

sudo journalctl -fu kestrel-helloapp.service --since "2016-10-18" --until "2016-10-18 04:00"

데이터 보호

ASP.NET Core 데이터 보호 스택은 인증 미들웨어(예: cookie 미들웨어) 및 CSRF(교차 사이트 요청 위조) 보호를 비롯한 여러 ASP.NET Core 미들웨어에 사용됩니다. 사용자 코드에서 데이터 보호 API가 호출되지 않더라도 영구적 암호화 키 저장소를 만들도록 데이터 보호를 구성해야 합니다. 데이터 보호를 구성하지 않으면 키는 메모리에 보관되고 앱이 다시 시작되면 삭제됩니다.

키 링이 메모리에 저장된 경우 앱을 다시 시작하면 다음과 같이 됩니다.

  • 모든 cookie 기반 인증 토큰이 무효화됩니다.
  • 사용자는 다음 요청에서 다시 로그인해야 합니다.
  • 키 링으로 보호된 데이터의 암호를 더 이상 해독할 수 없습니다. 여기에는 CSRF 토큰ASP.NET Core MVC TempData 쿠키가 포함될 수 있습니다.

키 링을 유지하고 암호화하도록 데이터 보호를 구성하려면 다음을 참조하십시오.

긴 요청 헤더 필드

프록시 서버 기본 설정은 일반적으로 플랫폼에 따라 요청 헤더 필드를 4K 또는 8K로 제한합니다. 앱에 기본값보다 긴 필드가 필요할 수 있습니다(예: Azure Active Directory를 사용하는 앱). 더 긴 필드가 필요한 경우 프록시 서버의 기본 설정을 조정해야 합니다. 적용할 값은 시나리오에 따라 달라집니다. 자세한 내용은 서버의 설명서를 참조하세요.

Warning

필요한 경우가 아니면 프록시 버퍼의 기본값을 늘리지 마세요. 이러한 값을 늘리면 악의적인 사용자의 버퍼 오버런(오버플로) 및 DoS(서비스 거부) 공격의 위험이 증가됩니다.

앱 보안 유지

AppArmor 사용

LSM(Linux Security Modules)은 Linux 2.6 이후 Linux 커널에 포함된 프레임워크입니다. LSM은 보안 모듈의 다양한 구현을 지원합니다. AppArmor는 프로그램을 제한된 리소스 세트로 한정할 수 있는 필수 Access Control 시스템을 구현하는 LSM입니다. AppArmor가 사용하도록 설정되고 제대로 구성되어 있는지 확인합니다.

방화벽 구성

사용하지 않는 모든 외부 포트를 닫습니다. 복잡하지 않은 방화벽(ufw)은 방화벽을 구성하기 위한 CLI를 제공하여 iptables에 대한 프런트 엔드를 제공합니다.

Warning

방화벽이 올바르게 구성되지 않으면 전체 시스템에 대한 액세스가 차단됩니다. 올바른 SSH 포트를 지정하지 못하면 SSH를 사용하여 시스템에 연결하는 경우 실직적으로 시스템에 액세스할 수 없게 됩니다. 기본 포트는 22입니다. 자세한 내용은 ufw 소개매뉴얼을 참조하세요.

ufw를 설치하고 필요한 모든 포트에서 트래픽을 허용하도록 구성합니다.

sudo apt-get install ufw

sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

sudo ufw enable

Nginx 보안 유지

Nginx 응답 이름 변경

편집 src/http/ngx_http_header_filter_module.c:

static char ngx_http_server_string[] = "Server: Web Server" CRLF;
static char ngx_http_server_full_string[] = "Server: Web Server" CRLF;

옵션 구성

추가 필수 모듈을 사용하여 서버를 구성합니다. ModSecurity와 같은 웹앱 방화벽을 사용하여 앱을 강화해 보세요.

HTTPS 구성

보안(HTTPS) 로컬 연결을 위해 앱 구성

dotnet run 명령은 applicationUrl 속성이 제공하는 URL에서 수신 대기하도록 앱을 구성하는 앱의 Properties/launchSettings.json 파일을 사용합니다. 예들 들어 https://localhost:5001;http://localhost:5000입니다.

다음 방법 중 하나를 사용하여 dotnet run 명령 또는 개발 환경(Visual Studio Code에서 F5 또는 Ctrl+F5)에 개발 중인 인증서를 사용하도록 앱을 구성합니다.

보안 (HTTPS) 클라이언트 연결을 위해 역방향 프록시 구성

Warning

이 섹션의 보안 구성은 추가 사용자 지정을 위한 시작 지점으로 사용할 일반 구성입니다. 타사 도구, 서버, 운영 체제에 대한 지원은 제공하지 않습니다. ‘이 섹션의 구성을 사용할 때는 주의해야 합니다.’ 자세한 내용을 보려면 다음 리소스에 액세스하세요.

  • 신뢰할 수 있는 CA(인증 기관)에서 발급된 유효한 인증서를 지정하여 포트 443에서 HTTPS 트래픽을 수신 대기하도록 서버를 구성합니다.

  • 다음 /etc/nginx/nginx.conf 파일에 설명된 일부 사례를 채택하여 보안을 강화합니다.

  • 다음 예제에서는 안전하지 않은 요청을 리디렉션하도록 서버를 구성하지 않습니다. HTTPS 리디렉션 미들웨어를 사용하는 것이 좋습니다. 자세한 내용은 ASP.NET Core에서 HTTPS 적용을 참조하세요.

    참고 항목

    서버 구성이 HTTPS 리디렉션 미들웨어 대신 보안 리디렉션을 처리하는 개발 환경인 경우 영구 리디렉션(301) 대신 임시 리디렉션(302)을 사용하는 것이 좋습니다. 링크 캐싱은 개발 환경에서 불안정한 동작을 일으킬 수 있습니다.

  • Strict-Transport-Security(HSTS) 헤더를 추가하면 클라이언트에서 만든 모든 후속 요청이 HTTPS를 통해 이루어집니다. Strict-Transport-Security 헤더 설정에 대한 지침은 ASP.NET Core에서 HTTPS 적용을 참조하세요.

  • 추후 HTTPS가 사용하지 않도록 설정될 경우 다음 방법 중 하나를 사용합니다.

    • HSTS 헤더를 추가하지 않습니다.
    • 짧은 max-age 값을 선택합니다.

/etc/nginx/proxy.conf 구성 파일을 추가합니다.

proxy_redirect          off;
proxy_set_header        Host $host;
proxy_set_header        X-Real-IP $remote_addr;
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header        X-Forwarded-Proto $scheme;
client_max_body_size    10m;
client_body_buffer_size 128k;
proxy_connect_timeout   90;
proxy_send_timeout      90;
proxy_read_timeout      90;
proxy_buffers           32 4k;

/etc/nginx/nginx.conf 구성 파일의 내용을 다음 파일로 바꿉니다. 예제에서는 httpserver 섹션이 하나의 구성 파일에 포함됩니다.

http {
    include        /etc/nginx/proxy.conf;
    limit_req_zone $binary_remote_addr zone=one:10m rate=5r/s;
    server_tokens  off;

    sendfile on;
    # Adjust keepalive_timeout to the lowest possible value that makes sense 
    # for your use case.
    keepalive_timeout   29;
    client_body_timeout 10; client_header_timeout 10; send_timeout 10;

    upstream helloapp{
        server 127.0.0.1:5000;
    }

    server {
        listen                    443 ssl http2;
        listen                    [::]:443 ssl http2;
        server_name               example.com *.example.com;
        ssl_certificate           /etc/ssl/certs/testCert.crt;
        ssl_certificate_key       /etc/ssl/certs/testCert.key;
        ssl_session_timeout       1d;
        ssl_protocols             TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers off;
        ssl_ciphers               ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
        ssl_session_cache         shared:SSL:10m;
        ssl_session_tickets       off;
        ssl_stapling              off;

        add_header X-Frame-Options DENY;
        add_header X-Content-Type-Options nosniff;

        #Redirects all traffic
        location / {
            proxy_pass http://helloapp;
            limit_req  zone=one burst=10 nodelay;
        }
    }
}

참고 항목

Blazor WebAssembly 앱에서 수행하는 많은 수의 요청을 수용하려면 앱에 더 큰 burst 매개 변수 값이 필요합니다. 자세한 내용은 ASP.NET Core Blazor WebAssembly 호스트 및 배포를 참조하세요.

참고 항목

앞의 예제에서는 OCSP(온라인 인증서 상태 프로토콜) 스테이플링을 사용하지 않도록 설정합니다. 사용하도록 설정한 경우 인증서가 해당 기능을 지원하는지 확인하세요. OCSP를 사용하도록 설정하는 방법에 대한 자세한 내용 및 지침은 Module ngx_http_ssl_module (Nginx documentation)(ngx_http_ssl_module 모듈(Nginx 설명서)) 문서에서 다음 속성을 참조하세요.

  • ssl_stapling
  • ssl_stapling_file
  • ssl_stapling_responder
  • ssl_stapling_verify

클릭재킹(clickjacking)으로부터 Nginx 보호

또한 ‘UI 교정 공격’이라고도 하는클릭재킹(Clickjacking)은 웹 사이트 방문자를 속여서 현재 방문 중인 것과 다른 페이지에서 링크 또는 단추를 클릭하게 하는 악의적인 공격입니다. X-FRAME-OPTIONS를 사용하여 사이트를 보호합니다.

클릭재킹 공격을 완화하려면:

  1. nginx.conf 파일을 편집합니다.

    sudo nano /etc/nginx/nginx.conf
    

    add_header X-Frame-Options "SAMEORIGIN"; 줄을 추가합니다.

  2. 파일을 저장합니다.

  3. Nginx를 다시 시작합니다.

MIME 형식 검색

이 헤더는 응답 콘텐츠 형식을 재정의하지 않도록 브라우저에 지시하므로 대부분의 브라우저에서 선언된 콘텐츠 형식이 아닌 응답에 대한 MIME 검색을 차단합니다. nosniff 옵션을 사용하면 서버에 콘텐츠가 text/html이라고 표시될 경우 브라우저가 이를text/html로 렌더링합니다.

  1. nginx.conf 파일을 편집합니다.

    sudo nano /etc/nginx/nginx.conf
    

    add_header X-Content-Type-Options "nosniff"; 줄을 추가합니다.

  2. 파일을 저장합니다.

  3. Nginx를 다시 시작합니다.

추가 Nginx 제안

서버에서 공유 프레임워크를 업그레이드한 후 서버에서 호스트되는 ASP.NET Core 앱을 다시 시작합니다.

추가 리소스

이 가이드에서는 Ubuntu 16.04 Server에서 프로덕션 준비 ASP.NET Core 환경을 설정하는 방법을 설명합니다. 이 지침은 최신 버전의 Ubuntu에서 작동할 수 있지만 최신 버전에서 테스트되지는 않았습니다.

ASP.NET Core에서 지원하는 다른 Linux 배포에 대한 자세한 내용은 Linux에서 .NET Core의 필수 구성 요소를 참조하세요.

참고 항목

Ubuntu 14.04의 경우 Kestrel 프로세스를 모니터링하기 위한 솔루션으로 supervisord를 사용하는 것이 좋습니다. systemd 는 Ubuntu 14.04에서 사용할 수 없습니다. Ubuntu 14.04 지침의 경우 이 항목의 이전 버전을 참조하세요.

이 가이드의 내용:

  • 기존 ASP.NET Core 앱을 역방향 프록시 서버 뒤에 배치합니다.
  • 역방향 프록시 서버를 설정하여 Kestrel 웹 서버에 요청을 전달합니다.
  • 웹앱이 시작 시 디먼으로 실행되는지 확인합니다.
  • 웹앱 다시 시작을 지원하도록 프로세스 관리 도구를 구성합니다.

필수 조건

  • sudo 권한을 가진 표준 사용자 계정으로 Ubuntu 16.04 Server에 액세스합니다.
  • 서버에 설치된, 미리 보기가 아닌 최신 .NET 런타임.
  • 기존 ASP.NET Core 앱입니다.

공유 프레임워크를 업그레이드한 후 나중에 언제든지 서버에서 호스트되는 ASP.NET Core 앱을 다시 시작합니다.

앱 게시 및 복사

프레임워크 종속 배포인 경우 앱을 구성합니다.

앱이 개발 환경에서 로컬로 실행되고 서버에 의해 보안 HTTPS 연결을 하도록 구성되지 않은 경우 다음 방법 중 하나를 채택합니다.

  • 보안 로컬 연결을 처리하도록 앱을 구성합니다. 자세한 내용은 HTTPS 구성 섹션을 참조하세요.

  • 안전하지 않은 엔드포인트에서 실행되도록 앱을 구성합니다.

    • 개발 환경에서 HTTPS 리디렉션 미들웨어를 사용하지 않도록 설정합니다(Program.cs).

      if (!app.Environment.IsDevelopment())
      {
          app.UseHttpsRedirection();
      }
      

      자세한 내용은 ASP.NET Core에서 여러 환경 사용을 참조하세요.

    • 파일의 속성 Properties/launchSettings.json 에서 applicationUrl 제거 https://localhost:5001 합니다(있는 경우).

환경별 구성에 대한 자세한 내용은 ASP.NET Core에서 여러 환경 사용을 참조하세요.

개발 환경에서 dotnet publish를 실행하여 서버에서 실행할 수 있는 디렉터리(예: bin/Release/{TARGET FRAMEWORK MONIKER}/publish, 여기서 자리 표시자 {TARGET FRAMEWORK MONIKER}는 대상 프레임워크 모니커/TFM)로 앱을 패키징합니다.

dotnet publish --configuration Release

.NET Core 런타임을 서버에서 유지 관리하지 않으려는 경우 앱은 자체 포함된 배포로 게시될 수도 있습니다.

조직의 워크플로에 통합된 도구(예: SCP, SFTP)를 사용하여 ASP.NET Core 앱을 서버에 복사합니다. 디렉터리 아래에 var 웹앱을 찾는 것이 일반적입니다(예: var/www/helloapp).

참고 항목

프로덕션 배포 시나리오에서 지속적인 통합 워크플로는 앱을 게시하고 자산을 서버로 복사하는 워크플로를 수행합니다.

앱을 테스트합니다.

  1. 명령줄에서 dotnet <app_assembly>.dll 앱을 실행하세요.
  2. 브라우저에서 http://<serveraddress>:<port>로 이동하여 앱이 Linux에서 로컬로 작동하는지 확인합니다.

역방향 프록시 서버 구성

역방향 프록시는 동적 웹앱을 지원하기 위한 일반적인 설정입니다. 역방향 프록시는 HTTP 요청을 종료하고 이 요청을 ASP.NET Core 앱에 전달합니다.

역방향 프록시 서버를 사용합니다.

Kestrel은 ASP.NET Core에서 동적 콘텐츠를 제공하는 데 유용합니다. 그러나 웹 지원 기능은 IIS, Apache 또는 Nginx와 같은 서버만큼 기능이 다양하지 않습니다. 역방향 프록시 서버는 정적 콘텐츠 지원, 요청 캐시, 요청 압축 및 HTTP 서버에서 HTTPS 종료 같은 작업을 오프로드할 수 있습니다. 역방향 프록시 서버는 전용 컴퓨터에 있거나 HTTP 서버와 함께 배포될 수 있습니다.

이 가이드에서는 Nginx의 단일 인스턴스가 사용됩니다. 이 인스턴스는 HTTP 서버와 함께 동일한 서버에서 실행됩니다. 요구 사항에 따라 다른 설정을 선택할 수 있습니다.

요청이 역방향 프록시에 의해 전달되므로 Microsoft.AspNetCore.HttpOverrides 패키지의 전달된 헤더 미들웨어를 사용합니다. 이 미들웨어는 X-Forwarded-Proto 헤더를 사용하여 Request.Scheme을 업데이트하므로 리디렉션 URI 및 기타 보안 정책이 제대로 작동합니다.

전달된 헤더 미들웨어는 다른 미들웨어보다 먼저 실행해야 합니다. 이 순서를 지정하면 전달된 헤더 정보에 따라 달라지는 미들웨어는 처리하기 위해 헤더 값을 사용할 수 있습니다. 진단 및 오류 처리 미들웨어 다음에 전달된 헤더 미들웨어를 실행하려면 전달된 헤더 미들웨어 순서를 참조하세요.

다른 미들웨어를 호출하기 전에 Startup.Configure의 맨 위에 있는 UseForwardedHeaders 메서드를 호출합니다. X-Forwarded-ForX-Forwarded-Proto 헤더를 전달하도록 미들웨어를 구성합니다.

using Microsoft.AspNetCore.HttpOverrides;

...

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

app.UseAuthentication();

미들웨어에 ForwardedHeadersOptions가 지정되지 않은 경우 전달할 기본 헤더는 None입니다.

표준 localhost 주소(127.0.0.1)를 포함하여 루프백 주소(127.0.0.0/8, [::1])에서 실행 중인 프록시는 기본적으로 신뢰할 수 있습니다. 조직 내의 다른 신뢰할 수 있는 프록시 또는 네트워크가 인터넷과 웹 서버 간의 요청을 처리하는 경우 ForwardedHeadersOptions를 사용하여 KnownProxies 또는 KnownNetworks 목록에 추가합니다. 다음 예제는 IP 주소 10.0.0.100의 신뢰할 수 있는 프록시 서버를 Startup.ConfigureServices의 전달된 헤더 미들웨어 KnownProxies에 추가합니다.

using System.Net;

...

services.Configure<ForwardedHeadersOptions>(options =>
{
    options.KnownProxies.Add(IPAddress.Parse("10.0.0.100"));
});

자세한 내용은 프록시 서버 및 부하 분산 장치를 사용하도록 ASP.NET Core 구성을 참조하세요.

Nginx 설치

apt-get을 사용하여 Nginx를 설치합니다. 설치 관리자는 시스템 시작 시 Nginx를 systemd 디먼으로 실행하는 init 스크립트를 만듭니다. Nginx: 공식 Debian/Ubuntu 패키지에서 Ubuntu에 대한 설치 지침을 따르세요.

참고 항목

선택적 Nginx 모듈이 필요한 경우 소스에서 Nginx를 빌드해야 할 수 있습니다.

Nginx가 처음 설치되었으므로 다음을 실행하여 명시적으로 시작합니다.

sudo service nginx start

브라우저에 Nginx에 대한 기본 방문 페이지가 표시되는지 확인합니다. 방문 페이지는 http://<server_IP_address>/index.nginx-debian.html에 도달할 수 있습니다.

Nginx 구성

Nginx를 역방향 프록시로 구성하여 HTTP 요청을 ASP.NET Core 앱에 전달하려면 /etc/nginx/sites-available/default를 수정합니다. 텍스트 편집기에서 해당 항목을 열고 콘텐츠를 다음 코드 조각으로 바꿉니다.

server {
    listen        80;
    server_name   example.com *.example.com;
    location / {
        proxy_pass         http://127.0.0.1:5000;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection keep-alive;
        proxy_set_header   Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
}

앱이 앱인 SignalR Blazor Server 경우 ASP.NET Core SignalR 프로덕션 호스팅 및 크기 조정을 참조하고 ASP.NET Core 서버 쪽 Blazor 앱을 각각 호스트 및 배포합니다.

server_name이 일치하지 않으면 Nginx는 기본 서버를 사용합니다. 기본 서버가 정의되지 않은 경우 구성 파일의 첫 번째 서버는 기본 서버입니다. 구성 파일에 있는 444 상태 코드를 반환하는 특정 기본 서버를 추가하는 것이 좋습니다. 기본 서버 구성 예제는 다음과 같습니다.

server {
    listen   80 default_server;
    # listen [::]:80 default_server deferred;
    return   444;
}

이전 구성 파일과 기본 서버를 사용하여 Nginx는 포트 80에서 호스트 헤더 example.com 또는 *.example.com가 포함된 공용 트래픽을 허용합니다. 이러한 호스트와 일치하지 않는 요청은 Kestrel로 전달되지 않습니다. Nginx는 일치하는 요청을 Kestrel의 http://127.0.0.1:5000에 전달합니다. 자세한 내용은 Nginx가 요청을 처리하는 방법을 참조하세요. Kestrel의 IP/포트를 변경하려면 Kestrel: 엔드포인트 구성을 참조하세요.

Warning

적절한 server_name 지시문을 지정하지 않으면 앱이 보안 취약성에 노출됩니다. 전체 부모 도메인을 제어하는 경우 하위 도메인 와일드카드 바인딩(예: *.example.com)에는 이러한 보안 위험이 발생하지 않습니다(취약한 *.com과 반대임). 자세한 내용은 RFC 9110: HTTP 의미 체계(섹션 7.2: 호스트 및 :authority)를 참조하세요.

Nginx 구성이 설정되면 sudo nginx -t를 실행하여 구성 파일의 구문을 확인합니다. 구성 파일 테스트에 성공하면 sudo nginx -s reload를 실행하여 Nginx가 변경 내용을 선택하도록 합니다.

앱을 서버에서 직접 실행하려면:

  1. 앱의 디렉터리로 이동합니다.
  2. dotnet <app_assembly.dll> 앱을 실행합니다. 여기서 app_assembly.dll은 앱의 어셈블리 파일 이름입니다.

앱이 서버에서 실행되지만 인터넷을 통해 응답하지 않는 경우 서버의 방화벽을 확인하고 포트 80이 열려 있는지 확인합니다. Ubuntu Azure VM을 사용하는 경우 인바운드 포트 80 트래픽을 사용하는 NSG(네트워크 보안 그룹) 규칙을 추가합니다. 인바운드 규칙을 사용할 때 아웃바운드 트래픽이 자동으로 부여되므로 아웃바운드 포트 80 규칙을 사용하도록 설정할 필요가 없습니다.

앱 테스트를 완료한 후에 명령 프롬프트에서 Ctrl+C(Windows) 또는 +C(macOS)를 사용하여 앱을 종료합니다.

앱 모니터링

서버는 http://<serveraddress>:80에 보낸 요청을 Kestrel의 http://127.0.0.1:5000에서 실행되는 ASP.NET Core 앱에 전달하도록 설정됩니다. 그러나 Nginx는 Kestrel 프로세스를 관리하도록 설정되지 않습니다. systemd 는 기본 웹앱을 시작하고 모니터링하는 서비스 파일을 만드는 데 사용할 수 있습니다. systemd 는 프로세스를 시작, 중지 및 관리하기 위한 많은 강력한 기능을 제공하는 init 시스템입니다.

서비스 파일 만들기

서비스 정의 파일을 만듭니다.

sudo nano /etc/systemd/system/kestrel-helloapp.service

다음 예제는 앱의 서비스 파일입니다.

[Unit]
Description=Example .NET Web API App running on Ubuntu

[Service]
WorkingDirectory=/var/www/helloapp
ExecStart=/usr/bin/dotnet /var/www/helloapp/helloapp.dll
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dotnet-example
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy=multi-user.target

앞의 예제에서 서비스를 관리하는 사용자는 User 옵션으로 지정됩니다. 사용자(www-data)가 존재해야 하며 앱 파일에 대한 적절한 소유권이 있어야 합니다.

TimeoutStopSec를 사용하여 초기 인터럽트 신호를 받은 후 앱이 종료되기를 기다리는 기간을 구성합니다. 이 기간 내에 앱이 종료되지 않으면 앱을 종료하기 위해 SIGKILL이 실행됩니다. 단위 없는 초로 된 값(예: 150) 또는 시간 범위 값(예: 2min 30s)으로 값을 입력하거나, 시간 제한을 사용하지 않으려면 infinity를 입력합니다. TimeoutStopSec는 관리자 구성 파일(systemd-system.conf, system.conf.d, systemd-user.conf, user.conf.d)에서 DefaultTimeoutStopSec의 값으로 기본 설정됩니다. 대부분의 배포에서 기본 시간 제한은 90초입니다.

# The default value is 90 seconds for most distributions.
TimeoutStopSec=90

Linux에는 대/소문자를 구분하는 파일 시스템이 있습니다. ASPNETCORE_ENVIRONMENTProduction으로 설정하면 appsettings.production.json이 아니라 appsettings.Production.json구성 파일이 검색됩니다.

일부 값(예: SQL 연결 문자열)은 환경 변수를 읽기 위해 구성 공급자에 대해 이스케이프되어야 합니다. 다음 명령을 사용하여 구성 파일에서 사용할 제대로 이스케이프된 값을 생성합니다.

systemd-escape "<value-to-escape>"

콜론(:) 구분 기호는 환경 변수 이름에서 지원되지 않습니다. 콜론 대신 이중 밑줄(__)을 사용합니다. 환경 변수 구성 공급자는 환경 변수를 구성으로 읽을 때 이중 밑줄을 콜론으로 변환합니다. 다음 예제에서 연결 문자열 키 ConnectionStrings:DefaultConnection은 서비스 정의 파일에 ConnectionStrings__DefaultConnection으로 설정됩니다.

Environment=ConnectionStrings__DefaultConnection={Connection String}

파일을 저장하고 서비스를 사용하도록 설정합니다.

sudo systemctl enable kestrel-helloapp.service

서비스를 시작하고 실행 중인지 확인합니다.

sudo systemctl start kestrel-helloapp.service
sudo systemctl status kestrel-helloapp.service

◝ kestrel-helloapp.service - Example .NET Web API App running on Ubuntu
    Loaded: loaded (/etc/systemd/system/kestrel-helloapp.service; enabled)
    Active: active (running) since Thu 2016-10-18 04:09:35 NZDT; 35s ago
Main PID: 9021 (dotnet)
    CGroup: /system.slice/kestrel-helloapp.service
            └─9021 /usr/local/bin/dotnet /var/www/helloapp/helloapp.dll

역방향 프록시를 구성하고 Kestrel를 통해 systemd을 관리하면 웹앱이 완전히 구성되고 로컬 머신(http://localhost)의 브라우저에서 웹앱에 액세스할 수 있습니다. 차단 중인 방화벽이 없다면 원격 컴퓨터에서 액세스할 수도 있습니다. 응답 헤더를 검사하는 Server 헤더는 Kestrel에서 지원하는 ASP.NET Core 앱을 보여줍니다.

HTTP/1.1 200 OK
Date: Tue, 11 Oct 2016 16:22:23 GMT
Server: Kestrel
Keep-Alive: timeout=5, max=98
Connection: Keep-Alive
Transfer-Encoding: chunked

로그 보기

Kestrel을 사용하는 웹앱은 systemd를 사용하여 관리되므로 모든 이벤트 및 프로세스가 중앙형 저널에 기록됩니다. 그러나 이 저널에는 systemd를 통해 관리하는 모든 서비스 및 프로세스에 대한 모든 항목이 포함됩니다. kestrel-helloapp.service 관련 항목을 보려면 다음 명령을 사용합니다.

sudo journalctl -fu kestrel-helloapp.service

추가 필터링을 위해 --since today, --until 1 hour ago 같은 시간 옵션을 사용하거나 이러한 옵션을 조합하여 반환되는 항목 수를 줄일 수 있습니다.

sudo journalctl -fu kestrel-helloapp.service --since "2016-10-18" --until "2016-10-18 04:00"

데이터 보호

ASP.NET Core 데이터 보호 스택은 인증 미들웨어(예: cookie 미들웨어) 및 CSRF(교차 사이트 요청 위조) 보호를 비롯한 여러 ASP.NET Core 미들웨어에 사용됩니다. 사용자 코드에서 데이터 보호 API가 호출되지 않더라도 영구적 암호화 키 저장소를 만들도록 데이터 보호를 구성해야 합니다. 데이터 보호를 구성하지 않으면 키는 메모리에 보관되고 앱이 다시 시작되면 삭제됩니다.

키 링이 메모리에 저장된 경우 앱을 다시 시작하면 다음과 같이 됩니다.

  • 모든 cookie 기반 인증 토큰이 무효화됩니다.
  • 사용자는 다음 요청에서 다시 로그인해야 합니다.
  • 키 링으로 보호된 데이터의 암호를 더 이상 해독할 수 없습니다. 여기에는 CSRF 토큰ASP.NET Core MVC TempData 쿠키가 포함될 수 있습니다.

키 링을 유지하고 암호화하도록 데이터 보호를 구성하려면 다음을 참조하십시오.

긴 요청 헤더 필드

프록시 서버 기본 설정은 일반적으로 플랫폼에 따라 요청 헤더 필드를 4K 또는 8K로 제한합니다. 앱에 기본값보다 긴 필드가 필요할 수 있습니다(예: Azure Active Directory를 사용하는 앱). 더 긴 필드가 필요한 경우 프록시 서버의 기본 설정을 조정해야 합니다. 적용할 값은 시나리오에 따라 달라집니다. 자세한 내용은 서버의 설명서를 참조하세요.

Warning

필요한 경우가 아니면 프록시 버퍼의 기본값을 늘리지 마세요. 이러한 값을 늘리면 악의적인 사용자의 버퍼 오버런(오버플로) 및 DoS(서비스 거부) 공격의 위험이 증가됩니다.

앱 보안 유지

AppArmor 사용

LSM(Linux Security Modules)은 Linux 2.6 이후 Linux 커널에 포함된 프레임워크입니다. LSM은 보안 모듈의 다양한 구현을 지원합니다. AppArmor는 프로그램을 제한된 리소스 세트로 한정할 수 있는 필수 Access Control 시스템을 구현하는 LSM입니다. AppArmor가 사용하도록 설정되고 제대로 구성되어 있는지 확인합니다.

방화벽 구성

사용하지 않는 모든 외부 포트를 닫습니다. 복잡하지 않은 방화벽(ufw)은 방화벽을 구성하기 위한 CLI를 제공하여 iptables에 대한 프런트 엔드를 제공합니다.

Warning

방화벽이 올바르게 구성되지 않으면 전체 시스템에 대한 액세스가 차단됩니다. 올바른 SSH 포트를 지정하지 못하면 SSH를 사용하여 시스템에 연결하는 경우 실직적으로 시스템에 액세스할 수 없게 됩니다. 기본 포트는 22입니다. 자세한 내용은 ufw 소개매뉴얼을 참조하세요.

ufw를 설치하고 필요한 모든 포트에서 트래픽을 허용하도록 구성합니다.

sudo apt-get install ufw

sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

sudo ufw enable

Nginx 보안 유지

Nginx 응답 이름 변경

편집 src/http/ngx_http_header_filter_module.c:

static char ngx_http_server_string[] = "Server: Web Server" CRLF;
static char ngx_http_server_full_string[] = "Server: Web Server" CRLF;

옵션 구성

추가 필수 모듈을 사용하여 서버를 구성합니다. ModSecurity와 같은 웹앱 방화벽을 사용하여 앱을 강화해 보세요.

HTTPS 구성

보안(HTTPS) 로컬 연결을 위해 앱 구성

dotnet run 명령은 applicationUrl 속성이 제공하는 URL에서 수신 대기하도록 앱을 구성하는 앱의 Properties/launchSettings.json 파일을 사용합니다. 예들 들어 https://localhost:5001;http://localhost:5000입니다.

다음 방법 중 하나를 사용하여 dotnet run 명령 또는 개발 환경(Visual Studio Code에서 F5 또는 Ctrl+F5)에 개발 중인 인증서를 사용하도록 앱을 구성합니다.

보안 (HTTPS) 클라이언트 연결을 위해 역방향 프록시 구성

Warning

이 섹션의 보안 구성은 추가 사용자 지정을 위한 시작 지점으로 사용할 일반 구성입니다. 타사 도구, 서버, 운영 체제에 대한 지원은 제공하지 않습니다. ‘이 섹션의 구성을 사용할 때는 주의해야 합니다.’ 자세한 내용을 보려면 다음 리소스에 액세스하세요.

  • 신뢰할 수 있는 CA(인증 기관)에서 발급된 유효한 인증서를 지정하여 포트 443에서 HTTPS 트래픽을 수신 대기하도록 서버를 구성합니다.

  • 다음 /etc/nginx/nginx.conf 파일에 설명된 일부 사례를 채택하여 보안을 강화합니다.

  • 다음 예제에서는 안전하지 않은 요청을 리디렉션하도록 서버를 구성하지 않습니다. HTTPS 리디렉션 미들웨어를 사용하는 것이 좋습니다. 자세한 내용은 ASP.NET Core에서 HTTPS 적용을 참조하세요.

    참고 항목

    서버 구성이 HTTPS 리디렉션 미들웨어 대신 보안 리디렉션을 처리하는 개발 환경인 경우 영구 리디렉션(301) 대신 임시 리디렉션(302)을 사용하는 것이 좋습니다. 링크 캐싱은 개발 환경에서 불안정한 동작을 일으킬 수 있습니다.

  • Strict-Transport-Security(HSTS) 헤더를 추가하면 클라이언트에서 만든 모든 후속 요청이 HTTPS를 통해 이루어집니다. Strict-Transport-Security 헤더 설정에 대한 지침은 ASP.NET Core에서 HTTPS 적용을 참조하세요.

  • 추후 HTTPS가 사용하지 않도록 설정될 경우 다음 방법 중 하나를 사용합니다.

    • HSTS 헤더를 추가하지 않습니다.
    • 짧은 max-age 값을 선택합니다.

/etc/nginx/proxy.conf 구성 파일을 추가합니다.

proxy_redirect          off;
proxy_set_header        Host $host;
proxy_set_header        X-Real-IP $remote_addr;
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header        X-Forwarded-Proto $scheme;
client_max_body_size    10m;
client_body_buffer_size 128k;
proxy_connect_timeout   90;
proxy_send_timeout      90;
proxy_read_timeout      90;
proxy_buffers           32 4k;

/etc/nginx/nginx.conf 구성 파일의 내용을 다음 파일로 바꿉니다. 예제에서는 httpserver 섹션이 하나의 구성 파일에 포함됩니다.

http {
    include        /etc/nginx/proxy.conf;
    limit_req_zone $binary_remote_addr zone=one:10m rate=5r/s;
    server_tokens  off;

    sendfile on;
    # Adjust keepalive_timeout to the lowest possible value that makes sense 
    # for your use case.
    keepalive_timeout   29;
    client_body_timeout 10; client_header_timeout 10; send_timeout 10;

    upstream helloapp{
        server 127.0.0.1:5000;
    }

    server {
        listen                    443 ssl http2;
        listen                    [::]:443 ssl http2;
        server_name               example.com *.example.com;
        ssl_certificate           /etc/ssl/certs/testCert.crt;
        ssl_certificate_key       /etc/ssl/certs/testCert.key;
        ssl_session_timeout       1d;
        ssl_protocols             TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers off;
        ssl_ciphers               ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
        ssl_session_cache         shared:SSL:10m;
        ssl_session_tickets       off;
        ssl_stapling              off;

        add_header X-Frame-Options DENY;
        add_header X-Content-Type-Options nosniff;

        #Redirects all traffic
        location / {
            proxy_pass http://helloapp;
            limit_req  zone=one burst=10 nodelay;
        }
    }
}

참고 항목

Blazor WebAssembly 앱에서 수행하는 많은 수의 요청을 수용하려면 앱에 더 큰 burst 매개 변수 값이 필요합니다. 자세한 내용은 ASP.NET Core Blazor WebAssembly 호스트 및 배포를 참조하세요.

참고 항목

앞의 예제에서는 OCSP(온라인 인증서 상태 프로토콜) 스테이플링을 사용하지 않도록 설정합니다. 사용하도록 설정한 경우 인증서가 해당 기능을 지원하는지 확인하세요. OCSP를 사용하도록 설정하는 방법에 대한 자세한 내용 및 지침은 Module ngx_http_ssl_module (Nginx documentation)(ngx_http_ssl_module 모듈(Nginx 설명서)) 문서에서 다음 속성을 참조하세요.

  • ssl_stapling
  • ssl_stapling_file
  • ssl_stapling_responder
  • ssl_stapling_verify

클릭재킹(clickjacking)으로부터 Nginx 보호

또한 ‘UI 교정 공격’이라고도 하는클릭재킹(Clickjacking)은 웹 사이트 방문자를 속여서 현재 방문 중인 것과 다른 페이지에서 링크 또는 단추를 클릭하게 하는 악의적인 공격입니다. X-FRAME-OPTIONS를 사용하여 사이트를 보호합니다.

클릭재킹 공격을 완화하려면:

  1. nginx.conf 파일을 편집합니다.

    sudo nano /etc/nginx/nginx.conf
    

    add_header X-Frame-Options "SAMEORIGIN"; 줄을 추가합니다.

  2. 파일을 저장합니다.

  3. Nginx를 다시 시작합니다.

MIME 형식 검색

이 헤더는 응답 콘텐츠 형식을 재정의하지 않도록 브라우저에 지시하므로 대부분의 브라우저에서 선언된 콘텐츠 형식이 아닌 응답에 대한 MIME 검색을 차단합니다. nosniff 옵션을 사용하면 서버에 콘텐츠가 text/html이라고 표시될 경우 브라우저가 이를text/html로 렌더링합니다.

  1. nginx.conf 파일을 편집합니다.

    sudo nano /etc/nginx/nginx.conf
    

    add_header X-Content-Type-Options "nosniff"; 줄을 추가합니다.

  2. 파일을 저장합니다.

  3. Nginx를 다시 시작합니다.

추가 Nginx 제안

서버에서 공유 프레임워크를 업그레이드한 후 서버에서 호스트되는 ASP.NET Core 앱을 다시 시작합니다.

추가 리소스