nginx: So verhindern Sie, dass ein genau benannter SSL-Serverblock als Sammelpunkt für alle SSL fungiert

17

Ich habe einen Webserver mit vielen virtuellen Servern. Nur 1 davon ist SSL. Das Problem ist, dass kein Catchall-Serverblock auf SSL wartet und jede https-Anfrage an die anderen Sites vom 1 SSL-Block bearbeitet wird.

Meine Konfiguration sieht im Wesentlichen so aus:

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

Da es für 443 keinen Standard-Listener gibt, wird eine Anfrage wie https://server1.comdiese vom server2.comhttps-Block bedient. Dies folgt der Logik server_namein den Dokumenten.

Wenn es keine Übereinstimmung gibt, wird ein Serverblock {...} in der Konfigurationsdatei in der folgenden Reihenfolge verwendet:

  1. der Server-Block mit einer passenden Listen-Direktive, die als [default | default_server] markiert ist
  2. der erste Serverblock mit einer passenden Listen-Direktive (oder implizit listen 80;)

Was ist die bevorzugte Lösung für dieses Problem? Muss ich ein Dummy-Zertifikat für meinen Catch-All-Server-Block einrichten, damit ich 443 abhören und die schlechten Anforderungen verarbeiten kann? Gibt es einen Parameter, von dem ich nichts weiß, der eine genaue Übereinstimmung mit dem Hostnamen erzwingt server?

numbers1311407
quelle
Was möchten Sie tun, wenn Benutzer versuchen, über https auf die anderen Websites zuzugreifen?
David Schwartz
Im Idealfall möchte ich, dass nginx überhaupt kein https bereitstellt, sofern der Hostname nicht übereinstimmt, oder dass es auf demselben Host zu http umleitet.
numbers1311407

Antworten:

9

Im Idealfall möchte ich, dass nginx überhaupt kein https bereitstellt, sofern der Hostname nicht übereinstimmt, oder dass es auf demselben Host zu http umleitet.

Beides ist nicht möglich. Die Verbindung von einem Client zu https://foo.example.com/ kann nur von einem SSL-Zertifikat mit dem Namen "foo.example.com" akzeptiert werden. Es besteht keine Möglichkeit zur Umleitung, bis die SSL-Verbindung akzeptiert wird.

Wenn Sie jeden Standort für SSL konfigurieren, erhält ein Benutzer, der auf den Zertifikatfehler klickt, den von ihm angeforderten Standort. Wenn Sie eine "Alle abfangen" -Site für SSL konfigurieren, die nur eine Fehlerseite bereitstellt, und das namensbasierte virtuelle Hosting für die eine Site konfigurieren, die SSL unterstützen soll, können Sie Clients eine Fehlerseite bereitstellen.

Virtuelles Hosting mit SSL und HTTP passt einfach nicht zusammen.

David Schwartz
quelle
Dies ist, was ich nach dem Lesen der Dokumente gesammelt habe. Ich hatte nur gehofft, etwas verpasst zu haben. SSL-Warnungen interessieren mich überhaupt nicht. Ich möchte nur nicht, dass jemand server1.com betritt und sich auf der Homepage von server2.com wiederfindet. Gibt es wirklich keine Möglichkeit, nginx anzuweisen , eine Anfrage nicht anzunehmen?
numbers1311407
Wenn die Anforderung nicht akzeptiert wird, funktioniert die erste Site nicht. Es muss die Anfrage annehmen, um herauszufinden, auf welche Site der Benutzer zugreifen möchte.
David Schwartz
2
Msgstr "Die Verbindung von einem Client zu foo.example.com kann nur von einem SSL - Zertifikat mit" foo.example.com "als einem seiner Namen akzeptiert werden." - Dies ist nicht korrekt. Der Server akzeptiert die Anforderung und der Client muss überprüfen, ob der angeforderte DN mit dem Serverzertifikat-DN übereinstimmt.
ColinM
4

Die einzige Möglichkeit besteht darin, ein selbstsigniertes SSL-Zertifikat zu erstellen und damit die Kontrolle über eingehende https-Anforderungen zu erlangen. Sie können Ihr selbstsigniertes SSL-Zertifikat in wenigen einfachen Schritten erstellen, die in diesem Beitrag beschrieben werden .

Angenommen, Sie erstellen ein selbstsigniertes Zertifikat mit dem Dateinamen server.crt. In Ihrer Nginx-Konfiguration würden Sie dann Folgendes anhängen:

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

Sie erhalten weiterhin die SSL-Warnmeldung des Browsers, haben aber zumindest die Kontrolle darüber, was als Nächstes passiert.

user1973679
quelle
1
Ich stimme dem zu. Es gibt das Problem, dass der Browser eine Warnmeldung über nicht vertrauenswürdige Zertifikate anzeigt, aber wenn Sie nur verhindern möchten, dass Benutzer zu https: // <IP-Adresse> gehen, um ein ebenso ungültiges Zertifikat für einen Ihrer echten vhosts (ungültig) zu erhalten Da der Hostname nicht übereinstimmt, sollten Sie ihnen ein ungültiges selbstsigniertes Dummy-Zertifikat zukommen lassen. Diese Art sagt ihnen, "hier gibt es nichts zu sehen, nicht einmal ein Zertifikat von einem anderen Host".
Daniel F
2

Fügen Sie einen Catch-All-Serverblock hinzu und geben Sie den Statuscode 444 zurück. Er weist nginx an, die Verbindung zu schließen, bevor Daten gesendet werden.

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

In diesen Tagen können Sie die TLS Server Name Indication-Erweiterung (SNI, RFC 6066) verwenden. Der HTTPS-Listener kann den Domänennamen erkennen, bevor er das entsprechende Zertifikat ausstellt.

Dies bedeutet, dass Sie Zertifikate für ALLE Ihre Domänen benötigen. Wenn SNI zum Erkennen einer der anderen Domänen verwendet wird, können Sie einfach die HTTP 301-Umleitung zur unverschlüsselten HTTP-Version verwenden, es sei denn, der Servername stimmt mit dem Namen überein, der benötigt wird Verschlüsselung.

Weitere Informationen zu SNI finden Sie in der Nginx-Dokumentation unter http://nginx.org/en/docs/http/configuring_https_servers.html

Evgeny
quelle
0

Ordnen Sie den angeforderten Hostnamen gültigen Hostnamen im http {}Block zu:

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

Und dann im server {}Block Verbindungen mit dem falschen Hostnamen beenden:

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

Verwenden Sie bei Bedarf mehrere Zuordnungen für mehrere Serverblöcke. Die Verbindung wird weiterhin mit einem Ihrer Zertifikate hergestellt. Wenn jedoch dieser letzte Block in jedem Serverblock vorhanden ist, der SSL bereitstellt, werden Verbindungen mit ungültigen Hostnamen effektiv "blockiert". Es ist möglicherweise nur im ersten Serverblock erforderlich, aber das Hinzufügen zu jedem Serverblock stellt sicher, dass die Reihenfolge keine Rolle spielt.

Die $ssl_server_nameVariable ist in Nginx 1.7 oder höher vorhanden.

ColinM
quelle
0

So habe ich das Problem gelöst:

  1. Selbstsigniertes Zertifikat erstellen:

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

  1. Kopieren Sie es, wo NginX es finden kann:

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

  1. Richten Sie eine Sammelroute ein:
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;
}

Das führt dazu, dass Sie auf jedem Server, der kein eigenes Zertifikat hat, eine Warnung erhalten (und nicht umgangen werden kann), in der Warnung wird jedoch nicht der falsche Zertifikatname angegeben. Wenn der Benutzer auf "Trotzdem besuchen" klickt, wird er zur Nicht-SSL-Version der von ihm eingegebenen Site weitergeleitet.

Einschränkung :

Wenn Ihre SLL-fähige Site nur definiert www.example.com(und nicht example.com), wird Ihre Catch-All-Route https://example.commit dem selbstsignierten Zertifikat und der entsprechenden Warnung geliefert.

ierdna
quelle
-2

Weiterleiten an http:

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

Rückkehr 404 :

server {
    listen       443;
    server_name  *.com;
    return 404;
}    
Freestyler
quelle
1
Dies führt weiterhin zu einer SSL-Warnung, da der SSL-Tunnel eingerichtet werden muss, bevor eine HTTP-Umleitung erfolgt. Siehe die akzeptierte Antwort von David Schwartz.
cjc