미등록 도메인 Catch-All 차단
등록하지 않은 도메인으로 수신된 요청을 기본 서버 블록에서 차단하며, 80은 444, 443은 핸드셰이크 거부로 처리한다.
문제 정의
nginx는 Host가 어느 server_name과도 일치하지 않으면 그 포트의 기본 서버로 요청을 전달한다. 기본 서버를 별도로 지정하지 않았다면 설정 파일에서 가장 먼저 나오는 블록이 기본 서버가 된다. 이 때문에 서버 주소를 가리키는 타인의 도메인으로 접속하면 해당 서버의 사이트가 그대로 표시된다.
80 포트의 444 처리
444는 nginx에서만 사용하는 값으로, 응답을 전송하지 않고 연결을 종료한다.
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
# 인증서 갱신 경로는 살려 둔다
location /.well-known/acme-challenge/ {
root /var/www/html;
}
# 그 밖의 요청은 응답 없이 연결을 닫는다
location / {
return 444;
}
}
443 포트의 핸드셰이크 거부
HTTPS는 응답을 전송하기 전에 인증서부터 제시해야 한다. 일치하지 않는 이름에는 인증서를 제시하지 않고 연결을 거부하는 방식이 더 적절하다.
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
server_name _;
# 이름이 맞지 않는 요청은 TLS 연결 단계에서 거부한다
ssl_reject_handshake on;
}
참고
ssl_reject_handshake는 nginx 1.19.4부터 사용할 수 있다.
확인 방법
서버 내부에서 존재하지 않는 도메인 이름으로 요청을 전송한다.
curl -s -o /dev/null -w '%{http_code}\n' \
--resolve unknown.example:80:127.0.0.1 http://unknown.example/
# 000 ← 응답 없이 끊겼다는 뜻
| 요청 | 처리 | curl 결과 |
|---|---|---|
| 등록한 도메인 | 해당 사이트로 전달 | 200 등 |
| 미등록 도메인, 80 | 응답 없이 연결 종료 | 000 |
| 미등록 도메인, 443 | 핸드셰이크 거부 | 000 |
정리
- 기본 서버 블록을 명시적으로 두면 첫 블록이 기본 서버가 되는 동작을 방지할 수 있다.
- 80은
return 444, 443은ssl_reject_handshake on으로 처리한다. - 인증서 갱신 경로는 예외로 유지한다.