nginx: cómo evitar que un bloque de servidor SSL con un nombre exacto actúe como el elemento clave para todos los SSL


17

Tengo un servidor web con muchos servidores virtuales. Solo 1 de los cuales es SSL. El problema es que, debido a que no hay ningún bloque de servidor general que escuche SSL, cualquier solicitud https a los otros sitios es atendida por el bloque 1 SSL.

Mi configuración, esencialmente, se ve así:

# 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;
  # ...
}

Ahora, como no hay un escucha predeterminado para 443, una solicitud como https://server1.comterminará siendo atendida por el server2.combloque https. Esto sigue la lógica server_nameen los documentos.

Si no hay coincidencia, se usará un bloque de servidor {...} en el archivo de configuración en función del siguiente orden:

  1. el bloque del servidor con una directiva de escucha coincidente marcada como [default | default_server]
  2. el primer bloque de servidor con una directiva de escucha coincidente (o escucha implícita 80;)

¿Cuál es la solución preferida para este problema? ¿Debo configurar un certificado ficticio para el bloqueo de todos los servidores para poder escuchar en 443 y manejar las solicitudes incorrectas? ¿Hay algún parámetro que desconozca que fuerce una coincidencia exacta del nombre de host con server?


¿Qué quieres que suceda cuando las personas intenten acceder a otros sitios usando https?
David Schwartz

Idealmente, me gustaría que nginx no sirva https en absoluto a menos que el nombre de host coincida, o que redirija a http en el mismo host.
números1311407

Respuestas:


9

Idealmente, me gustaría que nginx no sirva https en absoluto a menos que el nombre de host coincida, o que redirija a http en el mismo host.

Tampoco es posible. La conexión de un cliente que va a https://foo.example.com/ no puede ser aceptada por nada más que un certificado SSL con "foo.example.com" como uno de sus nombres. No hay oportunidad de redirigir hasta que se acepte la conexión SSL.

Si configura cada sitio para SSL, un usuario que haga clic en el error del certificado obtendrá el sitio que solicitó. Si configura un sitio "general" para SSL que proporciona solo una página de error y configura un alojamiento virtual basado en el nombre para el único sitio que debe soportar SSL, puede enviar una página de error a los clientes.

El alojamiento virtual SSL y HTTP simplemente no funciona bien juntos.


Esto es lo que reuní después de leer los documentos. Solo esperaba haberme perdido algo. No me importan las advertencias SSL en absoluto. Simplemente no quiero que alguien entre en server1.com y se encuentre mirando la página de inicio de server2.com ... ¿Realmente no hay forma de decirle a nginx que no acepte una solicitud?
números1311407

Si no acepta la solicitud, el primer sitio no funcionará. Tiene que aceptar la solicitud para averiguar a qué sitio está intentando acceder el usuario.
David Schwartz

2
"La conexión de un cliente que va a foo.example.com no puede ser aceptada por nada más que un certificado SSL con" foo.example.com "como uno de sus nombres". - Esto no es correcto, el servidor aceptará la solicitud y depende del cliente verificar que el DN solicitado coincida con el DN del certificado del servidor.
ColinM

4

La única forma de hacerlo es crear un certificado SSL autofirmado y usarlo para obtener control sobre las solicitudes https entrantes. Puede crear su certificado SSL autofirmado en unos sencillos pasos descritos en esta publicación .

Supongamos que crea un certificado autofirmado con un nombre de archivo de server.crt. Luego agregará lo siguiente en su configuración de 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;
}

Seguirá recibiendo el mensaje de advertencia SSL del navegador, pero al menos tendrá control sobre lo que sucede a continuación.


1
Estoy de acuerdo con ésto. Existe el problema de que el navegador muestre un mensaje de advertencia sobre certificados no confiables, pero si solo está tratando de evitar que los usuarios accedan a https: // <ip-address> para obtener serverd un certificado igualmente inválido para uno de sus servidores reales (no válido porque el nombre de host no coincidirá), entonces es mejor que les sirva un certificado ficticio autofirmado y no válido. Eso les dice "no hay nada que ver aquí, ni siquiera un certificado de otro host".
Daniel F

2

Agregue un bloque de servidor general y devuelva el código de estado 444. Le dice a nginx que cierre la conexión antes de enviar cualquier dato.

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

1

En estos días, puede usar la extensión de indicación de nombre de servidor TLS (SNI, RFC 6066). El oyente HTTPS podrá reconocer el nombre de dominio antes de entregar el certificado apropiado.

Esto significa que necesitará tener certificados para TODOS sus dominios, y cuando SNI se usa para reconocer uno de los otros dominios, puede usar el redireccionamiento HTTP 301 a la versión HTTP no cifrada a menos que el nombre del servidor coincida con el único que necesita cifrado

Más información sobre SNI disponible en la documentación de nginx http://nginx.org/en/docs/http/configuring_https_servers.html


0

Asigne el nombre de host solicitado a nombres de host válidos en el http {}bloque:

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

Y luego, en el server {}bloque, elimine las conexiones con el nombre de host incorrecto:

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

Utilice varios mapas según sea necesario para múltiples bloques de servidores. La conexión aún se establecerá utilizando uno de sus certificados, pero si este último bloque está presente en cada bloque de servidor que sirve SSL, efectivamente "bloqueará" las conexiones con nombres de host no válidos. Es posible que solo sea necesario en el primer bloque de servidor, pero agregarlo a cada bloque de servidor garantizará que el orden no importe.

La $ssl_server_namevariable está presente en nginx 1.7 o superior.


0

Así es como resolví el problema:

  1. Crear certificado autofirmado:

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

  1. Cópielo donde NginX pueda encontrarlo:

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

  1. Configure una ruta general:
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;
}

Lo que esto hará: le dará una advertencia (de ninguna manera) en cualquier servidor que no tenga su propio certificado, pero la advertencia no dirá el nombre del certificado incorrecto. Si el usuario hace clic en "visitar de todos modos", será redirigido a la versión no ssl del sitio que ha escrito.

advertencia :

si su sitio habilitado para SLL solo define www.example.com(y no example.com), su ruta general terminará sirviendo https://example.comcon el certificado autofirmado y la advertencia correspondiente.


-2

Redireccionar a http:

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

Volver 404 :

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

1
Eso todavía dará como resultado una advertencia SSL, ya que el túnel SSL debe establecerse antes de que ocurra cualquier redirección HTTP. Ver la respuesta aceptada de David Schwartz.
cjc
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.