[server] nginx : 정확히 이름이 지정된 SSL 서버 블록이 모든 SSL의 포괄 역할을하는 것을 방지하는 방법

가상 서버가 많은 웹 서버가 있습니다. 그중 하나만 SSL입니다. 문제는 SSL을 수신하는 catchall 서버 블록이 없기 때문에 다른 사이트에 대한 https 요청은 1 SSL 블록에 의해 제공된다는 것입니다.

기본적으로 내 구성은 다음과 같습니다.

# the catch all
server {
  listen 80 default;

  # I could add this, but since I have no default cert, I cannot enable SSL,
  # and this listen ends up doing nothing (apparently).
  # listen 443;

  server_name _;
  # ...
}

# some server
server {
  listen 80;
  server_name server1.com;
  # ...
}

# some other server ...
server {
  listen 80;
  server_name server2.com;
  # ...
}

# ... and it's https equivalent
server {
  listen 443;
  ssl on;
  server_name server2.com;
  # ...
}

이제 443에 대한 기본 리스너가 없으므로 https 블록 으로 요청이 처리 https://server1.com됩니다 server2.com. 이에 대한 논리를 다음 server_name워드 프로세서.

일치하는 것이 없으면 구성 파일의 서버 {…} 블록이 다음 순서에 따라 사용됩니다.

  1. 일치하는 청취 지시문이있는 서버 블록 [default | default_server]
  2. 일치하는 청취 지시문이있는 첫 번째 서버 블록 (또는 암시 적 청취 80)

이 문제에 대해 선호되는 솔루션은 무엇입니까? 443에서 수신 대기하고 잘못된 요청을 처리 할 수 ​​있도록 모든 서버 포착 블록에 대해 더미 인증서를 설정해야합니까? 내가 알지 못하는 매개 변수가 정확한 호스트 이름과 강제로 일치 server합니까?



답변

호스트 이름이 일치하지 않는 한 nginx가 https를 전혀 제공하지 않거나 동일한 호스트에서 http로 리디렉션하는 것이 이상적입니다.

둘 다 가능하지 않습니다. https://foo.example.com/으로 가는 클라이언트로부터의 연결은 이름 중 하나로 “foo.example.com”을 사용하는 SSL 인증서 이외의 다른 것으로는 허용되지 않습니다. SSL 연결이 승인 될 때까지 리디렉션 할 기회가 없습니다.

SSL에 대해 각 사이트를 구성하면 인증서 오류를 클릭하는 사용자가 요청한 사이트를 얻게됩니다. 오류 페이지 만 제공하는 SSL에 대해 “모두 포획”사이트를 구성하고 SSL을 지원해야하는 한 사이트에 대한 이름 기반 가상 호스팅을 구성하면 클라이언트에 오류 페이지를 제공 할 수 있습니다.

SSL과 HTTP 가상 호스팅은 잘 어울리지 않습니다.


답변

수행 할 수있는 유일한 방법은 자체 서명 된 SSL 인증서를 작성하고이를 사용하여 수신 https 요청을 제어하는 ​​것입니다. 이 게시물에 요약 된 몇 가지 간단한 단계를 통해 자체 서명 된 SSL 인증서를 만들 수 있습니다 .

파일 이름이 server.crt 인 자체 서명 인증서를 작성한다고 가정 해 봅시다. 그런 다음 nginx 구성에 다음을 추가하십시오.

server {
    listen  443;

    ssl    on;
    ssl_certificate         /etc/nginx/ssl/server.crt;
    ssl_certificate_key     /etc/nginx/ssl/server.key;

    server_name server1.com;

    keepalive_timeout 60;
    rewrite ^       http://$server_name$request_uri? permanent;
}

여전히 브라우저 SSL 경고 메시지가 표시되지만 최소한 다음에 발생할 작업을 제어 할 수 있습니다.


답변

범용 서버 블록을 추가하고 상태 코드 444를 반환합니다. 데이터를 보내기 전에 nginx에 연결을 닫으라고 지시합니다.

server {
    listen 443 default_server ssl;
    server_name _;
    return 444;
}


답변

요즘에는 TLS 서버 이름 표시 확장 (SNI, RFC 6066)을 사용할 수 있습니다. HTTPS 리스너는 적절한 인증서를 제공하기 전에 도메인 이름을 인식 할 수 있습니다.

즉, 모든 도메인에 대한 인증서가 필요하고 SNI를 사용하여 다른 도메인 중 하나를 인식하는 경우 서버 이름이 필요한 단일 이름과 일치하지 않는 한 HTTP 301을 HTTP 비 암호화 버전으로 리디렉션 할 수 있습니다. 암호화.

SNI에 대한 자세한 내용은 nginx 설명서 ( http://nginx.org/en/docs/http/configuring_https_servers.html)를 참조하십시오.


답변

요청 된 호스트 이름을 http {}블록의 유효한 호스트 이름에 맵핑하십시오 .

map $ssl_server_name $correct_hostname_example {
  default 0;
  example.com 1;
  www.example.com 1;
}

그런 다음 server {}블록에서 잘못된 호스트 이름으로 연결을 종료하십시오.

if ($correct_hostname_example = 0) {
  return 444;
}

여러 서버 블록에 필요에 따라 여러 맵을 사용하십시오. 인증서 중 하나를 사용하여 연결이 계속 설정되지만이 마지막 블록이 SSL을 제공하는 모든 서버 블록에있는 경우 유효하지 않은 호스트 이름으로 연결을 효과적으로 “차단”합니다. 첫 번째 서버 블록에서만 필요할 수 있지만 모든 서버 블록에 추가하면 순서가 중요하지 않습니다.

$ssl_server_name변수 nginx를 1.7 이상으로 존재한다.


답변

이것이 내가 문제를 해결 한 방법입니다.

  1. 자체 서명 된 인증서를 작성하십시오.

openssl req -nodes -x509 -newkey rsa:4096 -keyout self_key.pem -out self_cert.pem -days 3650

  1. NginX가 찾을 수있는 곳에 복사하십시오 :

cp self*.pem /etc/nginx/ssl/

  1. 포괄 경로 설정 :
server {
    listen 443 default_server ssl;

    ssl on;
    ssl_certificate /etc/nginx/ssl/self_cert.pem;
    ssl_certificate_key /etc/nginx/ssl/self_key.pem;

    return 301 http://$host;
}

이 수행 할 작업 : 그것은 당신에게 경고를 줄 것 자체 인증서가없는 모든 서버에 (주위 방법이)하지만 경고는 잘못된 인증서 이름을 말을하지 않습니다. 사용자가 “어쨌든 방문”을 클릭하면 입력 한 사이트의 비 SSL 버전으로 리디렉션됩니다.

경고 :

SLL 가능 사이트가 정의 www.example.com하고 만 정의 하지 않으면 example.com포괄 경로는 https://example.com자체 서명 인증서 및 해당 경고와 함께 제공 됩니다.


답변

http로 리디렉션 :

server {
    listen       443;
    server_name  *.com;
    rewrite        ^ http://$host$request_uri? permanent;
}

404 :

server {
    listen       443;
    server_name  *.com;
    return 404;
}