web-dev-qa-db-fra.com

nginx - Comment empêcher le traitement des demandes avec des noms de serveur non définis avec HTTPS

Comment éviter que nginx traite une demande avec un nom de serveur non défini à l'aide du protocole https.

La configuration suivante rend ce travail pour les requêtes http normales. Il réinitialise la connexion pour les demandes avec Host headers Vide, ce qui équivaut à server_name Dans la configuration nginx:

server {
    listen      80;
    server_name "";
    return      444;
}

Mis à jour pour plus de clarté:

Le serveur sert cependant le html du bloc serveur par défaut supportant ssl lorsqu'une requête via https est envoyée avec un Host header Vide. Comment éviter cela?

Je voudrais obtenir le comportement exact comme pour les requêtes http avec un Host header Vide - aucun html servi, réinitialisation de la connexion (retour 444).

Quelle serait la bonne façon de bloquer ces requêtes https et d'obtenir également le comportement mentionné pour les connexions https? (Je voudrais éviter d'utiliser le certificat SSL approprié pour cela car cela peut simplement faire allusion aux spammeurs sur le vrai domaine du serveur.)


Mise à jour 13.03.2015

Mettre un haproxy devant nginx avec le paramètre

strict-sni

résolu mon problème complètement.

15
binaryanomaly

En raison de la nature du fonctionnement de SSL, la négociation SSL/TLS est effectuée avant que le nom d'hôte souhaité ne soit donné au serveur Web. Cela signifie que le (premier) certificat par défaut est utilisé lors de la tentative d'accès au site, quel que soit le nom de domaine utilisé.

Cela est vrai pour Apache et nginx.

Depuis le Apache Wiki :

En règle générale, il est impossible d'héberger plusieurs hôtes virtuels SSL sur la même adresse IP et le même port. En effet, Apache doit connaître le nom de l'hôte afin de choisir le certificat correct pour configurer la couche de chiffrement. Mais le nom de l'hôte demandé n'est contenu que dans les en-têtes de requête HTTP, qui font partie du contenu chiffré. Il n'est donc disponible qu'après négociation du cryptage. Cela signifie que le bon certificat ne peut pas être sélectionné, et les clients recevront des avertissements de non-correspondance de certificat et seront vulnérables aux attaques de l'homme du milieu.

De la documentation nginx :

Avec cette configuration, un navigateur reçoit le certificat du serveur par défaut, à savoir www.example.com, quel que soit le nom du serveur demandé. Cela est dû au comportement du protocole SSL. La connexion SSL est établie avant que le navigateur n'envoie une requête HTTP et que nginx ne connaisse pas le nom du serveur demandé. Par conséquent, il ne peut offrir que le certificat du serveur par défaut.

Comment pouvez-vous résoudre ce problème?

La solution la plus simple consiste à utiliser des adresses IP distinctes pour chaque site que vous souhaitez sécuriser.

Si cela n'est pas possible, il peut être possible de résoudre le problème en utilisant Indication du nom du serveur (SNI, RFC 6066 ). Cela permet à un navigateur de transmettre le nom de domaine au serveur pendant la prise de contact.

Nginx et Apache prennent en charge SNI. Vous pouvez en savoir plus sur nginx SNI dans la documentation .

Il convient de noter que SNI ne peut être utilisé que pour les noms de domaine et non pour les adresses IP. Vous devez prendre des précautions supplémentaires lors de la configuration de vos serveurs Web pour résoudre ce problème, afin que toute demande adressée à l'IP soit traitée correctement.

Seuls les noms de domaine peuvent être transmis dans SNI, mais certains navigateurs peuvent transmettre par erreur une adresse IP du serveur comme nom si une demande comprend une adresse IP littérale. Il ne faut pas se fier à cela.

Le wiki Apache contient plus d'informations sur l'implémentation SNI . Mais même leur documentation indique que cette solution n'est pas parfaite.

L'utilisation d'hôtes virtuels basés sur le nom avec SSL ajoute une autre couche de complication. Sans l'extension SNI, ce n'est généralement pas possible (bien qu'un sous-ensemble d'hôte virtuel puisse fonctionner). Avec SNI, il est nécessaire d'examiner attentivement la configuration pour garantir la sécurité.

Cela dit, vous pouvez voir comment cette configuration n'est pas aussi simple que les hôtes virtuels classiques. Afin de trouver une solution à votre problème, nous aurions besoin de plus de détails sur votre configuration et le comportement attendu lorsqu'une demande IP uniquement est envoyée.

Généralement, pour "bloquer" un domaine ou une requête IP non configuré, vous devez le configurer comme site par défaut, puis afficher une erreur, rediriger, quitter, etc.

9
David Houde

Si je comprends bien, vous souhaitez refuser les requêtes HTTP, qui ne contiennent pas d'en-tête Host, même si ces requêtes se trouvent à l'intérieur d'une connexion SSL (par exemple, les requêtes https). Ce sont des requêtes HTTP/1.0 à l'ancienne, HTTP/1.1 nécessite un en-tête Host mais aussi la plupart des clients HTTP/1.0 en envoient déjà un. Le blocage de ces clients peut se faire avec:

    if ( $http_Host = '' ) {
            return 444;
    }

Mais cela n'aide pas si le client utilise un en-tête Host avec indésirable ou l'adresse IP qu'il contient. Ainsi, il serait préférable de vérifier que l'en-tête Host contient les valeurs attendues (en bonus, cela aide également contre les attaques de reliure DNS), par exemple.

    if ( $http_Host !~* ^(example\.com|www\.example\.com)$ ) {
            return 444;
    }
5
Steffen Ullrich

J'ai utilisé la méthode similaire à celle mentionnée par @int_ua, mais un peu délicate.

J'ai configuré mon nginx pour utiliser RSA et ECDSA comme méthode d'authentification TLS, mais j'ai émis un certificat DSA pour le serveur par défaut.
Comme il n'y a pas de suite de chiffrement disponible, la prise de contact TLS échouerait avant de servir une page.
Je pense que cela aurait le même résultat que ce que vous avez configuré (HAproxy strict-sni) et je crois que ma méthode aurait de meilleures performances.

Vous pouvez voir le résultat de ma configuration:

SNI non valide: https: //207.246.127.148/
(Vous pouvez configurer vos hôtes sur cette adresse IP et afficher également le résultat)
SNI valide: https: //cloud.jemmylovejenny.tk/
Le lien SNI valide pointe vers la même adresse IP que ci-dessus

Je donnerais ma configuration ici:

Configuration SSL
(J'ai utilisé un chiffrement openssl égal patch pour que les chiffrements soient un peu étranges ... Vous pouvez également conserver votre configuration, mais n'oubliez pas qu'elle ne contient pas tout DSS chiffres!)

    #Protocols
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
    #
    #Key Exchange
    ssl_ecdh_curve X25519:P-256:P-384:P-224:P-521;
    ssl_dhparam /var/SSL/DH-param.pem;
    #
    #Cipher Suites
    ssl_ciphers "[TLS_AES_128_GCM_SHA256|TLS_CHACHA20_POLY1305_SHA256]:[TLS_AES_256_GCM_SHA384|TLS_AES_128_CCM_8_SHA256|TLS_AES_128_CCM_SHA256]:[ECDHE-ECDSA-CHACHA20-POLY1305|ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256|DHE-RSA-CHACHA20-POLY1305]:[ECDHE-ECDSA-AES256-GCM-SHA384|ECDHE-RSA-AES256-GCM-SHA384]:[ECDHE-ECDSA-AES128-SHA|ECDHE-RSA-AES128-SHA]:[ECDHE-ECDSA-AES256-SHA|ECDHE-RSA-AES256-SHA]:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA";
    ssl_prefer_server_ciphers on;



Configuration par défaut du serveur

##
# General
##
# Listen
listen 8080 default_server;
listen 8443 ssl spdy http2 default_server;
#
# Server Name
server_name _;

##
# SSL Settings
##
#
# Certificate
#  DSA
ssl_certificate /var/SSL/certificates/DEFAULT.dsa.crt;
ssl_certificate_key /var/SSL/keys/DEFAULT.dsa.key;

root /var/www/html/nginx/;



La clé DSA est générée à partir d'OpenSSL et le certificat est émis à partir de ma propre PKI. Vous pouvez utiliser ce certificat si vous le souhaitez.
(Ce certificat ne serait jamais envoyé depuis le serveur nginx, donc tout ce certificat, y compris la longueur de clé et la période de validité, n'a aucun sens)

Certificat:

-----BEGIN CERTIFICATE-----
MIIFrjCCBJagAwIBAgIUHVfGi/SP2d/B4vbxZSKSVEpSoGEwDQYJKoZIhvcNAQEL
BQAwgYExCzAJBgNVBAYTAkNOMSMwIQYDVQQKDBpKZW1teUxvdmVKZW5ueSBQS0kg
U2VydmljZTEeMBwGA1UECwwVcGtpLmplbW15bG92ZWplbm55LnRrMS0wKwYDVQQD
DCRKZW1teUxvdmVKZW5ueSBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMTgwMTAx
MDAwMDAwWhcNMTkxMjMxMjM1OTU5WjAiMSAwHgYDVQQDDBdERUZBVUxUIFNTTCBD
RVJUSUZJQ0FURTCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQCVcFt4xWkIBtiN/Xay
O7Ls5EjBCFckvyBQpRJ5wmjrxepQbUK9xmiXmpkXOsEYHy14UQXswzKPBWiHsNDs
8apFoGAvjBxSg9Y07wd5VBnhBGvqd0VmD92eKAFW1sZZVoSrLwizfIde0sj9bZCD
KICt/0jdz0QGBZzXTtd4MOcjUQIVAPD9cVtRAdD6al8v/SV2YVQHZmafAoGBAI+A
tCrjcvK0PFILpwpGD/3gJI8o2oxKoPjjE3SM9b4mrN/2ixEGgGiXHOrEyZ7IgSjf
1Z6X2nuN+IgsNdJAZjNbnuacxbu4z5FmnO6i9IRXEqtKNzONeHJSG+7w7zUPfsPT
8sTxHU0Z5ynjiLz4GcnO5LVcMNbf2uEsl41fObB4A4GEAAKBgHOFoU8xns0qMFLz
h3ZiYScs2Rznw7xeo2HbM8hGI9zKWRoV49f9V2vHFjdPSLkPbzgoSqOxmGD7UZep
W0TcsSPVKIuKBw07vvJkpUG8U71mcedNN5+fNbIcgjKdTlIIbrEFYRFG6zrIcZ3/
WArPchw3RC+SRrBXW8+27T4+0PMao4IB5TCCAeEwHwYDVR0jBBgwFoAU4BPpj9H7
K19wMi69RQ9t6BLyNOcwHQYDVR0OBBYEFFrpB6sLpQwodD7KWPssHj0fkqjCMAkG
A1UdEQQCMAAwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr
BgEFBQcDAjBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3Jscy5wa2kuamVtbXls
b3ZlamVubnkudGsvU0hBMlNlY3VyZVNlcnZlckNBLmNybDCBggYDVR0gBHsweTBt
BglghkgBpKInAQIwYDAtBggrBgEFBQcCARYhaHR0cHM6Ly9wa2kuamVtbXlsb3Zl
amVubnkudGsvY3BzMC8GCCsGAQUFBwICMCMaIWh0dHBzOi8vcGtpLmplbW15bG92
ZWplbm55LnRrL3JwYTAIBgZngQwBAgEwgYYGCCsGAQUFBwEBBHoweDAtBggrBgEF
BQcwAYYhaHR0cDovL29jc3AucGtpLmplbW15bG92ZWplbm55LnRrMEcGCCsGAQUF
BzAChjtodHRwOi8vY2FjZXJ0cy5wa2kuamVtbXlsb3ZlamVubnkudGsvU0hBMlNl
Y3VyZVNlcnZlckNBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IB
AQCtgVPw2KLT/ntVYZE8AL71C0R1gsn9MKoqD6asaM16qK60G7YK8qC2I/5wWXAr
+zVeegvU/73qWq66DnIF333uZz3aeaXoIEfDRcfePVzWTG62cO2fPyTWyIczaPFf
NqQqoukM3UeBM0yIRSbiyRAFoyz0TWhdgSDXGrG+X5EvUnH6J+umnt/PNGaNnz1f
eXJBh79UnmCpMI6rW+7UG4F60xxQ/RQeRZZt//Ze5YzIDRjUQpXQ1a+9cHuPT8EY
Ft4xe4q5FgMVTBsu1zAfA/ViSDlHWAO8oioKkYDYHqYmLT6ERSoXNVK6WbNh4mem
AaF8T8DKQTHD5GKFBJSSkvF7
-----END CERTIFICATE-----



Clé:

-----BEGIN DSA PRIVATE KEY-----
MIIBuwIBAAKBgQCVcFt4xWkIBtiN/XayO7Ls5EjBCFckvyBQpRJ5wmjrxepQbUK9
xmiXmpkXOsEYHy14UQXswzKPBWiHsNDs8apFoGAvjBxSg9Y07wd5VBnhBGvqd0Vm
D92eKAFW1sZZVoSrLwizfIde0sj9bZCDKICt/0jdz0QGBZzXTtd4MOcjUQIVAPD9
cVtRAdD6al8v/SV2YVQHZmafAoGBAI+AtCrjcvK0PFILpwpGD/3gJI8o2oxKoPjj
E3SM9b4mrN/2ixEGgGiXHOrEyZ7IgSjf1Z6X2nuN+IgsNdJAZjNbnuacxbu4z5Fm
nO6i9IRXEqtKNzONeHJSG+7w7zUPfsPT8sTxHU0Z5ynjiLz4GcnO5LVcMNbf2uEs
l41fObB4AoGAc4WhTzGezSowUvOHdmJhJyzZHOfDvF6jYdszyEYj3MpZGhXj1/1X
a8cWN09IuQ9vOChKo7GYYPtRl6lbRNyxI9Uoi4oHDTu+8mSlQbxTvWZx5003n581
shyCMp1OUghusQVhEUbrOshxnf9YCs9yHDdEL5JGsFdbz7btPj7Q8xoCFFfXTHSl
C7tdLJO9vQFcyKMhU8TU
-----END DSA PRIVATE KEY-----
1
JemmyLoveJenny